1 // Scintilla source code edit control
2 // ScintillaGTK.cxx - GTK+ specific subclass of ScintillaBase
3 // Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
4 // The License.txt file describes the conditions under which this software may be distributed.
5
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <ctype.h>
10 #include <time.h>
11
12 #include <gtk/gtk.h>
13 #include <gdk/gdkkeysyms.h>
14
15 #include "Platform.h"
16
17 #if PLAT_GTK_WIN32
18 #include "Windows.h"
19 #endif
20
21 #include "Scintilla.h"
22 #include "ScintillaWidget.h"
23 #ifdef SCI_LEXER
24 #include "SciLexer.h"
25 #include "PropSet.h"
26 #include "Accessor.h"
27 #include "KeyWords.h"
28 #endif
29 #include "ContractionState.h"
30 #include "SVector.h"
31 #include "CellBuffer.h"
32 #include "CallTip.h"
33 #include "KeyMap.h"
34 #include "Indicator.h"
35 #include "XPM.h"
36 #include "LineMarker.h"
37 #include "Style.h"
38 #include "AutoComplete.h"
39 #include "ViewStyle.h"
40 #include "Document.h"
41 #include "Editor.h"
42 #include "SString.h"
43 #include "ScintillaBase.h"
44 #include "UniConversion.h"
45
46 #include "gtk/gtksignal.h"
47 #include "gtk/gtkmarshal.h"
48 #if GTK_MAJOR_VERSION >= 2
49 #include "scintilla-marshal.h"
50 #endif
51
52 #ifdef SCI_LEXER
53 #include <glib.h>
54 #include <gmodule.h>
55 #include "ExternalLexer.h"
56 #endif
57
58 #define INTERNATIONAL_INPUT
59
60 #if !PLAT_GTK_WIN32 || GTK_MAJOR_VERSION >= 2
61 #define USE_CONVERTER
62 #endif
63
64 #ifdef USE_CONVERTER
65 #include "Converter.h"
66 #endif
67
68 #ifdef _MSC_VER
69 // Constant conditional expressions are because of GTK+ headers
70 #pragma warning(disable: 4127)
71 // Ignore unreferenced local functions in GTK+ headers
72 #pragma warning(disable: 4505)
73 #endif
74
75 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 2
76 #define USE_GTK_CLIPBOARD
77 #endif
78
79 extern char *UTF8FromLatin1(const char *s, int &len);
80
81 class ScintillaGTK : public ScintillaBase {
82 _ScintillaObject *sci;
83 Window wText;
84 Window scrollbarv;
85 Window scrollbarh;
86 GtkObject *adjustmentv;
87 GtkObject *adjustmenth;
88 int scrollBarWidth;
89 int scrollBarHeight;
90
91 // Because clipboard access is asynchronous, copyText is created by Copy
92 #ifndef USE_GTK_CLIPBOARD
93 SelectionText copyText;
94 #endif
95
96 SelectionText primary;
97
98 GdkEventButton evbtn;
99 bool capturedMouse;
100 bool dragWasDropped;
101 int lastKey;
102
103 GtkWidgetClass *parentClass;
104
105 static GdkAtom atomClipboard;
106 static GdkAtom atomUTF8;
107 static GdkAtom atomString;
108 GdkAtom atomSought;
109
110 #if PLAT_GTK_WIN32
111 CLIPFORMAT cfColumnSelect;
112 #endif
113
114 #ifdef INTERNATIONAL_INPUT
115 #if GTK_MAJOR_VERSION < 2
116 // Input context used for supporting internationalized key entry
117 GdkIC *ic;
118 GdkICAttr *ic_attr;
119 #else
120 Window wPreedit;
121 Window wPreeditDraw;
122 GtkIMContext *im_context;
123 #endif
124 #endif
125
126 // Wheel mouse support
127 unsigned int linesPerScroll;
128 GTimeVal lastWheelMouseTime;
129 gint lastWheelMouseDirection;
130 gint wheelMouseIntensity;
131
132 // Private so ScintillaGTK objects can not be copied
ScintillaGTK(const ScintillaGTK &)133 ScintillaGTK(const ScintillaGTK &) : ScintillaBase() {}
operator =(const ScintillaGTK &)134 ScintillaGTK &operator=(const ScintillaGTK &) { return * this; }
135
136 public:
137 ScintillaGTK(_ScintillaObject *sci_);
138 virtual ~ScintillaGTK();
139 static void ClassInit(GtkObjectClass* object_class, GtkWidgetClass *widget_class, GtkContainerClass *container_class);
140
141 private:
142 virtual void Initialise();
143 virtual void Finalise();
144 virtual void DisplayCursor(Window::Cursor c);
145 virtual void StartDrag();
146 int TargetAsUTF8(char *text);
147 int EncodedFromUTF8(char *utf8, char *encoded);
148 public: // Public for scintilla_send_message
149 virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
150 private:
151 virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
152 virtual void SetTicking(bool on);
153 virtual bool SetIdle(bool on);
154 virtual void SetMouseCapture(bool on);
155 virtual bool HaveMouseCapture();
156 void FullPaint();
157 virtual PRectangle GetClientRectangle();
158 void SyncPaint(PRectangle rc);
159 virtual void ScrollText(int linesToMove);
160 virtual void SetVerticalScrollPos();
161 virtual void SetHorizontalScrollPos();
162 virtual bool ModifyScrollBars(int nMax, int nPage);
163 void ReconfigureScrollBars();
164 virtual void NotifyChange();
165 virtual void NotifyFocus(bool focus);
166 virtual void NotifyParent(SCNotification scn);
167 void NotifyKey(int key, int modifiers);
168 void NotifyURIDropped(const char *list);
169 bool UseInputMethod() const;
170 const char *CharacterSetID() const;
171 virtual int KeyDefault(int key, int modifiers);
172 virtual void CopyToClipboard(const SelectionText &selectedText);
173 virtual void Copy();
174 virtual void Paste();
175 virtual void CreateCallTipWindow(PRectangle rc);
176 virtual void AddToPopUp(const char *label, int cmd = 0, bool enabled = true);
177 bool OwnPrimarySelection();
178 virtual void ClaimSelection();
179 void GetGtkSelectionText(GtkSelectionData *selectionData, SelectionText &selText);
180 void ReceivedSelection(GtkSelectionData *selection_data);
181 void ReceivedDrop(GtkSelectionData *selection_data);
182 static void GetSelection(GtkSelectionData *selection_data, guint info, SelectionText *selected);
183 #ifdef USE_GTK_CLIPBOARD
184 static void ClipboardGetSelection(GtkClipboard* clip, GtkSelectionData *selection_data, guint info, void *data);
185 static void ClipboardClearSelection(GtkClipboard* clip, void *data);
186 #endif
187
188 void UnclaimSelection(GdkEventSelection *selection_event);
189 void Resize(int width, int height);
190
191 // Callback functions
192 void RealizeThis(GtkWidget *widget);
193 static void Realize(GtkWidget *widget);
194 void UnRealizeThis(GtkWidget *widget);
195 static void UnRealize(GtkWidget *widget);
196 void MapThis();
197 static void Map(GtkWidget *widget);
198 void UnMapThis();
199 static void UnMap(GtkWidget *widget);
200 static gint CursorMoved(GtkWidget *widget, int xoffset, int yoffset, ScintillaGTK *sciThis);
201 static gint FocusIn(GtkWidget *widget, GdkEventFocus *event);
202 static gint FocusOut(GtkWidget *widget, GdkEventFocus *event);
203 static void SizeRequest(GtkWidget *widget, GtkRequisition *requisition);
204 static void SizeAllocate(GtkWidget *widget, GtkAllocation *allocation);
205 gint Expose(GtkWidget *widget, GdkEventExpose *ose);
206 static gint ExposeMain(GtkWidget *widget, GdkEventExpose *ose);
207 static void Draw(GtkWidget *widget, GdkRectangle *area);
208 void ForAll(GtkCallback callback, gpointer callback_data);
209 static void MainForAll(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data);
210
211 static void ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis);
212 static void ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis);
213 gint PressThis(GdkEventButton *event);
214 static gint Press(GtkWidget *widget, GdkEventButton *event);
215 static gint MouseRelease(GtkWidget *widget, GdkEventButton *event);
216 #if PLAT_GTK_WIN32 || (GTK_MAJOR_VERSION >= 2)
217 static gint ScrollEvent(GtkWidget *widget, GdkEventScroll *event);
218 #endif
219 static gint Motion(GtkWidget *widget, GdkEventMotion *event);
220 gint KeyThis(GdkEventKey *event);
221 static gint KeyPress(GtkWidget *widget, GdkEventKey *event);
222 static gint KeyRelease(GtkWidget *widget, GdkEventKey *event);
223 #if GTK_MAJOR_VERSION >= 2
224 static gint ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis);
225 gint ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose);
226 static void Commit(GtkIMContext *context, char *str, ScintillaGTK *sciThis);
227 void CommitThis(char *str);
228 static void PreeditChanged(GtkIMContext *context, ScintillaGTK *sciThis);
229 void PreeditChangedThis();
230 #endif
231 static gint StyleSetText(GtkWidget *widget, GtkStyle *previous, void*);
232 static gint RealizeText(GtkWidget *widget, void*);
233 static void Destroy(GtkObject *object);
234 static void SelectionReceived(GtkWidget *widget, GtkSelectionData *selection_data,
235 guint time);
236 static void SelectionGet(GtkWidget *widget, GtkSelectionData *selection_data,
237 guint info, guint time);
238 static gint SelectionClear(GtkWidget *widget, GdkEventSelection *selection_event);
239 #if GTK_MAJOR_VERSION < 2
240 static gint SelectionNotify(GtkWidget *widget, GdkEventSelection *selection_event);
241 #endif
242 static void DragBegin(GtkWidget *widget, GdkDragContext *context);
243 static gboolean DragMotion(GtkWidget *widget, GdkDragContext *context,
244 gint x, gint y, guint time);
245 static void DragLeave(GtkWidget *widget, GdkDragContext *context,
246 guint time);
247 static void DragEnd(GtkWidget *widget, GdkDragContext *context);
248 static gboolean Drop(GtkWidget *widget, GdkDragContext *context,
249 gint x, gint y, guint time);
250 static void DragDataReceived(GtkWidget *widget, GdkDragContext *context,
251 gint x, gint y, GtkSelectionData *selection_data, guint info, guint time);
252 static void DragDataGet(GtkWidget *widget, GdkDragContext *context,
253 GtkSelectionData *selection_data, guint info, guint time);
254 static gint TimeOut(ScintillaGTK *sciThis);
255 static gint IdleCallback(ScintillaGTK *sciThis);
256 static void PopUpCB(ScintillaGTK *sciThis, guint action, GtkWidget *widget);
257
258 gint ExposeTextThis(GtkWidget *widget, GdkEventExpose *ose);
259 static gint ExposeText(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis);
260
261 static gint ExposeCT(GtkWidget *widget, GdkEventExpose *ose, CallTip *ct);
262 static gint PressCT(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis);
263
264 static sptr_t DirectFunction(ScintillaGTK *sciThis,
265 unsigned int iMessage, uptr_t wParam, sptr_t lParam);
266 };
267
268 enum {
269 COMMAND_SIGNAL,
270 NOTIFY_SIGNAL,
271 LAST_SIGNAL
272 };
273
274 static gint scintilla_signals[LAST_SIGNAL] = { 0 };
275 static GtkWidgetClass* parent_class = NULL;
276
277 enum {
278 TARGET_STRING,
279 TARGET_TEXT,
280 TARGET_COMPOUND_TEXT,
281 TARGET_UTF8_STRING
282 };
283
284 GdkAtom ScintillaGTK::atomClipboard = 0;
285 GdkAtom ScintillaGTK::atomUTF8 = 0;
286 GdkAtom ScintillaGTK::atomString = 0;
287
288 static const GtkTargetEntry clipboardTargets[] = {
289 { "UTF8_STRING", 0, TARGET_UTF8_STRING },
290 { "STRING", 0, TARGET_STRING },
291 // { "TEXT", 0, TARGET_TEXT },
292 // { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
293 { "text/uri-list", 0, 0 },
294 };
295 static const gint nClipboardTargets = sizeof(clipboardTargets) / sizeof(clipboardTargets[0]);
296
PWidget(Window & w)297 static GtkWidget *PWidget(Window &w) {
298 return reinterpret_cast<GtkWidget *>(w.GetID());
299 }
300
ScintillaFromWidget(GtkWidget * widget)301 static ScintillaGTK *ScintillaFromWidget(GtkWidget *widget) {
302 ScintillaObject *scio = reinterpret_cast<ScintillaObject *>(widget);
303 return reinterpret_cast<ScintillaGTK *>(scio->pscin);
304 }
305
ScintillaGTK(_ScintillaObject * sci_)306 ScintillaGTK::ScintillaGTK(_ScintillaObject *sci_) :
307 adjustmentv(0), adjustmenth(0),
308 scrollBarWidth(30), scrollBarHeight(30),
309 capturedMouse(false), dragWasDropped(false),
310 lastKey(0), parentClass(0),
311 #ifdef INTERNATIONAL_INPUT
312 #if GTK_MAJOR_VERSION < 2
313 ic(NULL),
314 ic_attr(NULL),
315 #else
316 im_context(NULL),
317 #endif
318 #endif
319 lastWheelMouseDirection(0),
320 wheelMouseIntensity(0) {
321 sci = sci_;
322 wMain = GTK_WIDGET(sci);
323
324 #if PLAT_GTK_WIN32
325 // There does not seem to be a real standard for indicating that the clipboard
326 // contains a rectangular selection, so copy Developer Studio.
327 cfColumnSelect = static_cast<CLIPFORMAT>(
328 ::RegisterClipboardFormat("MSDEVColumnSelect"));
329
330 // Get intellimouse parameters when running on win32; otherwise use
331 // reasonable default
332 #ifndef SPI_GETWHEELSCROLLLINES
333 #define SPI_GETWHEELSCROLLLINES 104
334 #endif
335 ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &linesPerScroll, 0);
336 #else
337 linesPerScroll = 4;
338 #endif
339 lastWheelMouseTime.tv_sec = 0;
340 lastWheelMouseTime.tv_usec = 0;
341
342 Initialise();
343 }
344
~ScintillaGTK()345 ScintillaGTK::~ScintillaGTK() {
346 }
347
RealizeThis(GtkWidget * widget)348 void ScintillaGTK::RealizeThis(GtkWidget *widget) {
349 //Platform::DebugPrintf("ScintillaGTK::realize this\n");
350 GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
351 GdkWindowAttr attrs;
352 attrs.window_type = GDK_WINDOW_CHILD;
353 attrs.x = widget->allocation.x;
354 attrs.y = widget->allocation.y;
355 attrs.width = widget->allocation.width;
356 attrs.height = widget->allocation.height;
357 attrs.wclass = GDK_INPUT_OUTPUT;
358 attrs.visual = gtk_widget_get_visual(widget);
359 attrs.colormap = gtk_widget_get_colormap(widget);
360 attrs.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK;
361 GdkCursor *cursor = gdk_cursor_new(GDK_XTERM);
362 attrs.cursor = cursor;
363 widget->window = gdk_window_new(gtk_widget_get_parent_window(widget), &attrs,
364 GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_CURSOR);
365 gdk_window_set_user_data(widget->window, widget);
366 gdk_window_set_background(widget->window, &widget->style->bg[GTK_STATE_NORMAL]);
367 gdk_window_show(widget->window);
368 gdk_cursor_destroy(cursor);
369 widget->style = gtk_style_attach(widget->style, widget->window);
370 #ifdef INTERNATIONAL_INPUT
371 #if GTK_MAJOR_VERSION < 2
372 if (gdk_im_ready() && (ic_attr = gdk_ic_attr_new()) != NULL) {
373 gint width, height;
374 GdkColormap *colormap;
375 GdkEventMask mask;
376 GdkICAttr *attr = ic_attr;
377 GdkICAttributesType attrmask = GDK_IC_ALL_REQ;
378 GdkIMStyle style;
379 GdkIMStyle supported_style = (GdkIMStyle) (GDK_IM_PREEDIT_NONE |
380 GDK_IM_PREEDIT_NOTHING |
381 GDK_IM_PREEDIT_POSITION |
382 GDK_IM_STATUS_NONE |
383 GDK_IM_STATUS_NOTHING);
384
385 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
386 supported_style = (GdkIMStyle) ((int) supported_style & ~GDK_IM_PREEDIT_POSITION);
387
388 attr->style = style = gdk_im_decide_style(supported_style);
389 attr->client_window = widget->window;
390
391 if ((colormap = gtk_widget_get_colormap (widget)) != gtk_widget_get_default_colormap ()) {
392 attrmask = (GdkICAttributesType) ((int) attrmask | GDK_IC_PREEDIT_COLORMAP);
393 attr->preedit_colormap = colormap;
394 }
395
396 switch (style & GDK_IM_PREEDIT_MASK) {
397 case GDK_IM_PREEDIT_POSITION:
398 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET) {
399 g_warning("over-the-spot style requires fontset");
400 break;
401 }
402
403 attrmask = (GdkICAttributesType) ((int) attrmask | GDK_IC_PREEDIT_POSITION_REQ);
404 gdk_window_get_size(widget->window, &width, &height);
405 attr->spot_location.x = 0;
406 attr->spot_location.y = height;
407 attr->preedit_area.x = 0;
408 attr->preedit_area.y = 0;
409 attr->preedit_area.width = width;
410 attr->preedit_area.height = height;
411 attr->preedit_fontset = widget->style->font;
412
413 break;
414 }
415 ic = gdk_ic_new(attr, attrmask);
416
417 if (ic == NULL) {
418 g_warning("Can't create input context.");
419 } else {
420 mask = gdk_window_get_events(widget->window);
421 mask = (GdkEventMask) ((int) mask | gdk_ic_get_events(ic));
422 gdk_window_set_events(widget->window, mask);
423
424 if (GTK_WIDGET_HAS_FOCUS(widget))
425 gdk_im_begin(ic, widget->window);
426 }
427 }
428 #else
429 wPreedit = gtk_window_new(GTK_WINDOW_POPUP);
430 wPreeditDraw = gtk_drawing_area_new();
431 gtk_signal_connect(GTK_OBJECT(PWidget(wPreeditDraw)), "expose_event",
432 GtkSignalFunc(ExposePreedit), this);
433 gtk_container_add(GTK_CONTAINER(PWidget(wPreedit)), PWidget(wPreeditDraw));
434 gtk_widget_realize(PWidget(wPreedit));
435 gtk_widget_realize(PWidget(wPreeditDraw));
436 gtk_widget_show(PWidget(wPreeditDraw));
437
438 im_context = gtk_im_multicontext_new();
439 g_signal_connect(im_context, "commit",
440 G_CALLBACK(Commit), this);
441 g_signal_connect(im_context, "preedit_changed",
442 G_CALLBACK(PreeditChanged), this);
443 gtk_im_context_set_client_window(im_context, widget->window);
444 #endif
445 #endif
446 gtk_signal_connect_after(GTK_OBJECT(PWidget(wText)), "style_set",
447 GtkSignalFunc(ScintillaGTK::StyleSetText), NULL);
448 gtk_signal_connect_after(GTK_OBJECT(PWidget(wText)), "realize",
449 GtkSignalFunc(ScintillaGTK::RealizeText), NULL);
450 gtk_widget_realize(PWidget(wText));
451 gtk_widget_realize(PWidget(scrollbarv));
452 gtk_widget_realize(PWidget(scrollbarh));
453 }
454
Realize(GtkWidget * widget)455 void ScintillaGTK::Realize(GtkWidget *widget) {
456 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
457 sciThis->RealizeThis(widget);
458 }
459
UnRealizeThis(GtkWidget * widget)460 void ScintillaGTK::UnRealizeThis(GtkWidget *widget) {
461 if (GTK_WIDGET_MAPPED(widget)) {
462 gtk_widget_unmap(widget);
463 }
464 GTK_WIDGET_UNSET_FLAGS(widget, GTK_REALIZED);
465 gtk_widget_unrealize(PWidget(wText));
466 gtk_widget_unrealize(PWidget(scrollbarv));
467 gtk_widget_unrealize(PWidget(scrollbarh));
468 #ifdef INTERNATIONAL_INPUT
469 #if GTK_MAJOR_VERSION < 2
470 if (ic) {
471 gdk_ic_destroy(ic);
472 ic = NULL;
473 }
474 if (ic_attr) {
475 gdk_ic_attr_destroy(ic_attr);
476 ic_attr = NULL;
477 }
478 #else
479 gtk_widget_unrealize(PWidget(wPreedit));
480 gtk_widget_unrealize(PWidget(wPreeditDraw));
481 g_object_unref(im_context);
482 im_context = NULL;
483 #endif
484 #endif
485 if (GTK_WIDGET_CLASS(parentClass)->unrealize)
486 GTK_WIDGET_CLASS(parentClass)->unrealize(widget);
487
488 Finalise();
489 }
490
UnRealize(GtkWidget * widget)491 void ScintillaGTK::UnRealize(GtkWidget *widget) {
492 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
493 sciThis->UnRealizeThis(widget);
494 }
495
MapWidget(GtkWidget * widget)496 static void MapWidget(GtkWidget *widget) {
497 if (widget &&
498 GTK_WIDGET_VISIBLE(widget) &&
499 !GTK_WIDGET_MAPPED(widget)) {
500 gtk_widget_map(widget);
501 }
502 }
503
MapThis()504 void ScintillaGTK::MapThis() {
505 //Platform::DebugPrintf("ScintillaGTK::map this\n");
506 GTK_WIDGET_SET_FLAGS(PWidget(wMain), GTK_MAPPED);
507 MapWidget(PWidget(wText));
508 MapWidget(PWidget(scrollbarh));
509 MapWidget(PWidget(scrollbarv));
510 wMain.SetCursor(Window::cursorArrow);
511 scrollbarv.SetCursor(Window::cursorArrow);
512 scrollbarh.SetCursor(Window::cursorArrow);
513 ChangeSize();
514 gdk_window_show(PWidget(wMain)->window);
515 }
516
Map(GtkWidget * widget)517 void ScintillaGTK::Map(GtkWidget *widget) {
518 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
519 sciThis->MapThis();
520 }
521
UnMapThis()522 void ScintillaGTK::UnMapThis() {
523 //Platform::DebugPrintf("ScintillaGTK::unmap this\n");
524 GTK_WIDGET_UNSET_FLAGS(PWidget(wMain), GTK_MAPPED);
525 gdk_window_hide(PWidget(wMain)->window);
526 gtk_widget_unmap(PWidget(wText));
527 gtk_widget_unmap(PWidget(scrollbarh));
528 gtk_widget_unmap(PWidget(scrollbarv));
529 }
530
UnMap(GtkWidget * widget)531 void ScintillaGTK::UnMap(GtkWidget *widget) {
532 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
533 sciThis->UnMapThis();
534 }
535
ForAll(GtkCallback callback,gpointer callback_data)536 void ScintillaGTK::ForAll(GtkCallback callback, gpointer callback_data) {
537 (*callback) (PWidget(wText), callback_data);
538 (*callback) (PWidget(scrollbarv), callback_data);
539 (*callback) (PWidget(scrollbarh), callback_data);
540 }
541
MainForAll(GtkContainer * container,gboolean include_internals,GtkCallback callback,gpointer callback_data)542 void ScintillaGTK::MainForAll(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data) {
543 ScintillaGTK *sciThis = ScintillaFromWidget((GtkWidget *)container);
544
545 if (callback != NULL && include_internals) {
546 sciThis->ForAll(callback, callback_data);
547 }
548 }
549
550 #ifdef INTERNATIONAL_INPUT
551 #if GTK_MAJOR_VERSION < 2
CursorMoved(GtkWidget * widget,int xoffset,int yoffset,ScintillaGTK * sciThis)552 gint ScintillaGTK::CursorMoved(GtkWidget *widget, int xoffset, int yoffset, ScintillaGTK *sciThis) {
553 if (GTK_WIDGET_HAS_FOCUS(widget) && gdk_im_ready() && sciThis->ic &&
554 (gdk_ic_get_style(sciThis->ic) & GDK_IM_PREEDIT_POSITION)) {
555 sciThis->ic_attr->spot_location.x = xoffset;
556 sciThis->ic_attr->spot_location.y = yoffset;
557 gdk_ic_set_attr(sciThis->ic, sciThis->ic_attr, GDK_IC_SPOT_LOCATION);
558 }
559 return FALSE;
560 }
561 #else
CursorMoved(GtkWidget *,int xoffset,int yoffset,ScintillaGTK * sciThis)562 gint ScintillaGTK::CursorMoved(GtkWidget *, int xoffset, int yoffset, ScintillaGTK *sciThis) {
563 GdkRectangle area;
564 area.x = xoffset;
565 area.y = yoffset;
566 area.width = 1;
567 area.height = 1;
568 gtk_im_context_set_cursor_location(sciThis->im_context, &area);
569 return FALSE;
570 }
571 #endif
572 #else
CursorMoved(GtkWidget *,int,int,ScintillaGTK *)573 gint ScintillaGTK::CursorMoved(GtkWidget *, int, int, ScintillaGTK *) {
574 return FALSE;
575 }
576 #endif
577
FocusIn(GtkWidget * widget,GdkEventFocus *)578 gint ScintillaGTK::FocusIn(GtkWidget *widget, GdkEventFocus * /*event*/) {
579 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
580 //Platform::DebugPrintf("ScintillaGTK::focus in %x\n", sciThis);
581 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
582 sciThis->SetFocusState(true);
583
584 #ifdef INTERNATIONAL_INPUT
585 #if GTK_MAJOR_VERSION < 2
586 if (sciThis->ic)
587 gdk_im_begin(sciThis->ic, widget->window);
588 #else
589 if (sciThis->im_context != NULL) {
590 gchar *str = NULL;
591 gint cursor_pos;
592
593 gtk_im_context_get_preedit_string(sciThis->im_context, &str, NULL, &cursor_pos);
594 if (PWidget(sciThis->wPreedit) != NULL) {
595 if (strlen(str) > 0) {
596 gtk_widget_show(PWidget(sciThis->wPreedit));
597 } else {
598 gtk_widget_hide(PWidget(sciThis->wPreedit));
599 }
600 }
601 g_free(str);
602 gtk_im_context_focus_in(sciThis->im_context);
603 }
604 #endif
605 #endif
606
607 return FALSE;
608 }
609
FocusOut(GtkWidget * widget,GdkEventFocus *)610 gint ScintillaGTK::FocusOut(GtkWidget *widget, GdkEventFocus * /*event*/) {
611 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
612 //Platform::DebugPrintf("ScintillaGTK::focus out %x\n", sciThis);
613 GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
614 sciThis->SetFocusState(false);
615
616 #ifdef INTERNATIONAL_INPUT
617 #if GTK_MAJOR_VERSION < 2
618 gdk_im_end();
619 #else
620 if (PWidget(sciThis->wPreedit) != NULL)
621 gtk_widget_hide(PWidget(sciThis->wPreedit));
622 if (sciThis->im_context != NULL)
623 gtk_im_context_focus_out(sciThis->im_context);
624 #endif
625 #endif
626
627 return FALSE;
628 }
629
SizeRequest(GtkWidget * widget,GtkRequisition * requisition)630 void ScintillaGTK::SizeRequest(GtkWidget *widget, GtkRequisition *requisition) {
631 requisition->width = 600;
632 requisition->height = gdk_screen_height();
633 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
634 GtkRequisition child_requisition;
635 gtk_widget_size_request(PWidget(sciThis->scrollbarh), &child_requisition);
636 gtk_widget_size_request(PWidget(sciThis->scrollbarv), &child_requisition);
637 }
638
SizeAllocate(GtkWidget * widget,GtkAllocation * allocation)639 void ScintillaGTK::SizeAllocate(GtkWidget *widget, GtkAllocation *allocation) {
640 widget->allocation = *allocation;
641 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
642 if (GTK_WIDGET_REALIZED(widget))
643 gdk_window_move_resize(widget->window,
644 widget->allocation.x,
645 widget->allocation.y,
646 widget->allocation.width,
647 widget->allocation.height);
648
649 sciThis->Resize(allocation->width, allocation->height);
650
651 #ifdef INTERNATIONAL_INPUT
652 #if GTK_MAJOR_VERSION < 2
653 if (sciThis->ic && (gdk_ic_get_style(sciThis->ic) & GDK_IM_PREEDIT_POSITION)) {
654 gint width, height;
655
656 gdk_window_get_size(widget->window, &width, &height);
657 sciThis->ic_attr->preedit_area.width = width;
658 sciThis->ic_attr->preedit_area.height = height;
659
660 gdk_ic_set_attr(sciThis->ic, sciThis->ic_attr, GDK_IC_PREEDIT_AREA);
661 }
662 #endif
663 #endif
664 }
665
Initialise()666 void ScintillaGTK::Initialise() {
667 //Platform::DebugPrintf("ScintillaGTK::Initialise\n");
668 parentClass = reinterpret_cast<GtkWidgetClass *>(
669 gtk_type_class(gtk_container_get_type()));
670
671 GTK_WIDGET_SET_FLAGS(PWidget(wMain), GTK_CAN_FOCUS);
672 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(PWidget(wMain)), GTK_SENSITIVE);
673 gtk_widget_set_events(PWidget(wMain),
674 GDK_EXPOSURE_MASK
675 | GDK_STRUCTURE_MASK
676 | GDK_KEY_PRESS_MASK
677 | GDK_KEY_RELEASE_MASK
678 | GDK_FOCUS_CHANGE_MASK
679 | GDK_LEAVE_NOTIFY_MASK
680 | GDK_BUTTON_PRESS_MASK
681 | GDK_BUTTON_RELEASE_MASK
682 | GDK_POINTER_MOTION_MASK
683 | GDK_POINTER_MOTION_HINT_MASK);
684
685 wText = gtk_drawing_area_new();
686 gtk_widget_set_parent(PWidget(wText), PWidget(wMain));
687 gtk_widget_show(PWidget(wText));
688 gtk_signal_connect(GTK_OBJECT(PWidget(wText)), "expose_event",
689 GtkSignalFunc(ScintillaGTK::ExposeText), this);
690 gtk_widget_set_events(PWidget(wText), GDK_EXPOSURE_MASK);
691 #if GTK_MAJOR_VERSION >= 2
692 // Avoid background drawing flash
693 gtk_widget_set_double_buffered(PWidget(wText), FALSE);
694 #endif
695 gtk_drawing_area_size(GTK_DRAWING_AREA(PWidget(wText)),
696 100,100);
697
698 adjustmentv = gtk_adjustment_new(0.0, 0.0, 201.0, 1.0, 20.0, 20.0);
699 scrollbarv = gtk_vscrollbar_new(GTK_ADJUSTMENT(adjustmentv));
700 GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarv), GTK_CAN_FOCUS);
701 gtk_signal_connect(GTK_OBJECT(adjustmentv), "value_changed",
702 GTK_SIGNAL_FUNC(ScrollSignal), this);
703 gtk_widget_set_parent(PWidget(scrollbarv), PWidget(wMain));
704 gtk_widget_show(PWidget(scrollbarv));
705
706 adjustmenth = gtk_adjustment_new(0.0, 0.0, 101.0, 1.0, 20.0, 20.0);
707 scrollbarh = gtk_hscrollbar_new(GTK_ADJUSTMENT(adjustmenth));
708 GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarh), GTK_CAN_FOCUS);
709 gtk_signal_connect(GTK_OBJECT(adjustmenth), "value_changed",
710 GTK_SIGNAL_FUNC(ScrollHSignal), this);
711 gtk_widget_set_parent(PWidget(scrollbarh), PWidget(wMain));
712 gtk_widget_show(PWidget(scrollbarh));
713
714 gtk_widget_grab_focus(PWidget(wMain));
715
716 gtk_selection_add_targets(GTK_WIDGET(PWidget(wMain)), GDK_SELECTION_PRIMARY,
717 clipboardTargets, nClipboardTargets);
718
719 #ifndef USE_GTK_CLIPBOARD
720 gtk_selection_add_targets(GTK_WIDGET(PWidget(wMain)), atomClipboard,
721 clipboardTargets, nClipboardTargets);
722 #endif
723
724 gtk_drag_dest_set(GTK_WIDGET(PWidget(wMain)),
725 GTK_DEST_DEFAULT_ALL, clipboardTargets, nClipboardTargets,
726 static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE));
727
728 SetTicking(true);
729 }
730
Finalise()731 void ScintillaGTK::Finalise() {
732 SetTicking(false);
733 ScintillaBase::Finalise();
734 }
735
DisplayCursor(Window::Cursor c)736 void ScintillaGTK::DisplayCursor(Window::Cursor c) {
737 if (cursorMode == SC_CURSORNORMAL)
738 wText.SetCursor(c);
739 else
740 wText.SetCursor(static_cast<Window::Cursor>(cursorMode));
741 }
742
StartDrag()743 void ScintillaGTK::StartDrag() {
744 dragWasDropped = false;
745 static const GtkTargetEntry targets[] = {
746 { "UTF8_STRING", 0, TARGET_UTF8_STRING },
747 { "STRING", 0, TARGET_STRING },
748 // { "TEXT", 0, TARGET_TEXT },
749 // { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
750 };
751 static const gint n_targets = sizeof(targets) / sizeof(targets[0]);
752 GtkTargetList *tl = gtk_target_list_new(targets, n_targets);
753 gtk_drag_begin(GTK_WIDGET(PWidget(wMain)),
754 tl,
755 static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE),
756 evbtn.button,
757 reinterpret_cast<GdkEvent *>(&evbtn));
758 }
759
760 #ifdef USE_CONVERTER
ConvertText(int * lenResult,char * s,size_t len,const char * charSetDest,const char * charSetSource)761 static char *ConvertText(int *lenResult, char *s, size_t len, const char *charSetDest, const char *charSetSource) {
762 *lenResult = 0;
763 char *destForm = 0;
764 Converter conv(charSetDest, charSetSource);
765 if (conv) {
766 destForm = new char[len*3+1];
767 char *pin = s;
768 size_t inLeft = len;
769 char *pout = destForm;
770 size_t outLeft = len*3+1;
771 size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
772 if (conversions == ((size_t)(-1))) {
773 fprintf(stderr, "iconv %s->%s failed for %s\n", charSetSource, charSetDest, static_cast<char *>(s));
774 delete []destForm;
775 destForm = 0;
776 } else {
777 //fprintf(stderr, "iconv OK %s %d\n", destForm, pout - destForm);
778 *pout = '\0';
779 *lenResult = pout - destForm;
780 }
781 } else {
782 fprintf(stderr, "Can not iconv %s %s\n", charSetDest, charSetSource);
783 }
784 if (!destForm) {
785 destForm = new char[1];
786 destForm[0] = '\0';
787 *lenResult = 0;
788 }
789 return destForm;
790 }
791 #endif
792
793 // Returns the target converted to UTF8.
794 // Return the length in bytes.
TargetAsUTF8(char * text)795 int ScintillaGTK::TargetAsUTF8(char *text) {
796 int targetLength = targetEnd - targetStart;
797 if (IsUnicodeMode()) {
798 if (text) {
799 pdoc->GetCharRange(text, targetStart, targetLength);
800 }
801 } else {
802 // Need to convert
803 #ifdef USE_CONVERTER
804 const char *charSetBuffer = CharacterSetID();
805 if (*charSetBuffer) {
806 //~ fprintf(stderr, "AsUTF8 %s %d %0d-%0d\n", charSetBuffer, targetLength, targetStart, targetEnd);
807 char *s = new char[targetLength];
808 if (s) {
809 pdoc->GetCharRange(s, targetStart, targetLength);
810 //~ fprintf(stderr, " \"%s\"\n", s);
811 if (text) {
812 char *tmputf = ConvertText(&targetLength, s, targetLength, "UTF-8", charSetBuffer);
813 memcpy(text, tmputf, targetLength);
814 delete []tmputf;
815 //~ fprintf(stderr, " \"%s\"\n", text);
816 }
817 delete []s;
818 }
819 } else {
820 if (text) {
821 pdoc->GetCharRange(text, targetStart, targetLength);
822 }
823 }
824 #else
825 // Fail
826 return 0;
827 #endif
828 }
829 //~ fprintf(stderr, "Length = %d bytes\n", targetLength);
830 return targetLength;
831 }
832
833 // Translates a nul terminated UTF8 string into the document encoding.
834 // Return the length of the result in bytes.
EncodedFromUTF8(char * utf8,char * encoded)835 int ScintillaGTK::EncodedFromUTF8(char *utf8, char *encoded) {
836 int inputLength = (lengthForEncode >= 0) ? lengthForEncode : strlen(utf8);
837 if (IsUnicodeMode()) {
838 if (encoded) {
839 memcpy(encoded, utf8, inputLength);
840 }
841 return inputLength;
842 } else {
843 // Need to convert
844 #ifdef USE_CONVERTER
845 const char *charSetBuffer = CharacterSetID();
846 if (*charSetBuffer) {
847 //~ fprintf(stderr, "Encode %s %d\n", charSetBuffer, inputLength);
848 int outLength = 0;
849 char *tmpEncoded = ConvertText(&outLength, utf8, inputLength, charSetBuffer, "UTF-8");
850 if (tmpEncoded) {
851 //~ fprintf(stderr, " \"%s\"\n", tmpEncoded);
852 if (encoded) {
853 memcpy(encoded, tmpEncoded, outLength);
854 }
855 delete []tmpEncoded;
856 }
857 return outLength;
858 } else {
859 if (encoded) {
860 memcpy(encoded, utf8, inputLength);
861 }
862 return inputLength;
863 }
864 #endif
865 }
866 // Fail
867 return 0;
868 }
869
WndProc(unsigned int iMessage,uptr_t wParam,sptr_t lParam)870 sptr_t ScintillaGTK::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
871 switch (iMessage) {
872
873 case SCI_GRABFOCUS:
874 gtk_widget_grab_focus(PWidget(wMain));
875 break;
876
877 case SCI_GETDIRECTFUNCTION:
878 return reinterpret_cast<sptr_t>(DirectFunction);
879
880 case SCI_GETDIRECTPOINTER:
881 return reinterpret_cast<sptr_t>(this);
882
883 #ifdef SCI_LEXER
884 case SCI_LOADLEXERLIBRARY:
885 LexerManager::GetInstance()->Load(reinterpret_cast<const char*>(wParam));
886 break;
887 #endif
888 case SCI_TARGETASUTF8:
889 return TargetAsUTF8(reinterpret_cast<char*>(lParam));
890
891 case SCI_ENCODEDFROMUTF8:
892 return EncodedFromUTF8(reinterpret_cast<char*>(wParam),
893 reinterpret_cast<char*>(lParam));
894
895 default:
896 return ScintillaBase::WndProc(iMessage, wParam, lParam);
897 }
898 return 0l;
899 }
900
DefWndProc(unsigned int,uptr_t,sptr_t)901 sptr_t ScintillaGTK::DefWndProc(unsigned int, uptr_t, sptr_t) {
902 return 0;
903 }
904
SetTicking(bool on)905 void ScintillaGTK::SetTicking(bool on) {
906 if (timer.ticking != on) {
907 timer.ticking = on;
908 if (timer.ticking) {
909 timer.tickerID = reinterpret_cast<TickerID>(gtk_timeout_add(timer.tickSize, (GtkFunction)TimeOut, this));
910 } else {
911 gtk_timeout_remove(GPOINTER_TO_UINT(timer.tickerID));
912 }
913 }
914 timer.ticksToWait = caret.period;
915 }
916
SetIdle(bool on)917 bool ScintillaGTK::SetIdle(bool on) {
918 if (on) {
919 // Start idler, if it's not running.
920 if (idler.state == false) {
921 idler.state = true;
922 idler.idlerID = reinterpret_cast<IdlerID>
923 (gtk_idle_add((GtkFunction)IdleCallback, this));
924 }
925 } else {
926 // Stop idler, if it's running
927 if (idler.state == true) {
928 idler.state = false;
929 gtk_idle_remove(GPOINTER_TO_UINT(idler.idlerID));
930 }
931 }
932 return true;
933 }
934
SetMouseCapture(bool on)935 void ScintillaGTK::SetMouseCapture(bool on) {
936 if (mouseDownCaptures) {
937 if (on) {
938 gtk_grab_add(GTK_WIDGET(PWidget(wMain)));
939 } else {
940 gtk_grab_remove(GTK_WIDGET(PWidget(wMain)));
941 }
942 }
943 capturedMouse = on;
944 }
945
HaveMouseCapture()946 bool ScintillaGTK::HaveMouseCapture() {
947 return capturedMouse;
948 }
949
950 // Redraw all of text area. This paint will not be abandoned.
FullPaint()951 void ScintillaGTK::FullPaint() {
952 #if GTK_MAJOR_VERSION < 2
953 paintState = painting;
954 rcPaint = GetClientRectangle();
955 //Platform::DebugPrintf("ScintillaGTK::FullPaint %0d,%0d %0d,%0d\n",
956 // rcPaint.left, rcPaint.top, rcPaint.right, rcPaint.bottom);
957 paintingAllText = true;
958 if ((PWidget(wText))->window) {
959 Surface *sw = Surface::Allocate();
960 if (sw) {
961 sw->Init(PWidget(wText)->window, PWidget(wText));
962 Paint(sw, rcPaint);
963 sw->Release();
964 delete sw;
965 }
966 }
967 paintState = notPainting;
968 #else
969 wText.InvalidateAll();
970 #endif
971 }
972
GetClientRectangle()973 PRectangle ScintillaGTK::GetClientRectangle() {
974 PRectangle rc = wMain.GetClientPosition();
975 if (verticalScrollBarVisible)
976 rc.right -= scrollBarWidth;
977 if (horizontalScrollBarVisible && (wrapState == eWrapNone))
978 rc.bottom -= scrollBarHeight;
979 // Move to origin
980 rc.right -= rc.left;
981 rc.bottom -= rc.top;
982 rc.left = 0;
983 rc.top = 0;
984 return rc;
985 }
986
987 // Synchronously paint a rectangle of the window.
SyncPaint(PRectangle rc)988 void ScintillaGTK::SyncPaint(PRectangle rc) {
989 paintState = painting;
990 rcPaint = rc;
991 PRectangle rcClient = GetClientRectangle();
992 paintingAllText = rcPaint.Contains(rcClient);
993 if ((PWidget(wText))->window) {
994 Surface *sw = Surface::Allocate();
995 if (sw) {
996 sw->Init(PWidget(wText)->window, PWidget(wText));
997 Paint(sw, rc);
998 sw->Release();
999 delete sw;
1000 }
1001 }
1002 if (paintState == paintAbandoned) {
1003 // Painting area was insufficient to cover new styling or brace highlight positions
1004 FullPaint();
1005 }
1006 paintState = notPainting;
1007 }
1008
ScrollText(int linesToMove)1009 void ScintillaGTK::ScrollText(int linesToMove) {
1010 int diff = vs.lineHeight * -linesToMove;
1011 //Platform::DebugPrintf("ScintillaGTK::ScrollText %d %d %0d,%0d %0d,%0d\n", linesToMove, diff,
1012 // rc.left, rc.top, rc.right, rc.bottom);
1013 GtkWidget *wi = PWidget(wText);
1014
1015 #if GTK_MAJOR_VERSION < 2
1016 PRectangle rc = GetClientRectangle();
1017 GdkGC *gc = gdk_gc_new(wi->window);
1018
1019 // Set up gc so we get GraphicsExposures from gdk_draw_pixmap
1020 // which calls XCopyArea
1021 gdk_gc_set_exposures(gc, TRUE);
1022
1023 // Redraw exposed bit : scrolling upwards
1024 if (diff > 0) {
1025 gdk_draw_pixmap(wi->window,
1026 gc, wi->window,
1027 0, diff,
1028 0, 0,
1029 rc.Width()-1, rc.Height() - diff);
1030 SyncPaint(PRectangle(0, rc.Height() - diff,
1031 rc.Width(), rc.Height()+1));
1032
1033 // Redraw exposed bit : scrolling downwards
1034 } else {
1035 gdk_draw_pixmap(wi->window,
1036 gc, wi->window,
1037 0, 0,
1038 0, -diff,
1039 rc.Width()-1, rc.Height() + diff);
1040 SyncPaint(PRectangle(0, 0, rc.Width(), -diff));
1041 }
1042
1043 // Look for any graphics expose
1044 GdkEvent* event;
1045 while ((event = gdk_event_get_graphics_expose(wi->window)) != NULL) {
1046 gtk_widget_event(wi, event);
1047 if (event->expose.count == 0) {
1048 gdk_event_free(event);
1049 break;
1050 }
1051 gdk_event_free(event);
1052 }
1053
1054 gdk_gc_unref(gc);
1055 #else
1056 gdk_window_scroll(wi->window, 0, -diff);
1057 gdk_window_process_updates(wi->window, FALSE);
1058 #endif
1059 }
1060
SetVerticalScrollPos()1061 void ScintillaGTK::SetVerticalScrollPos() {
1062 DwellEnd(true);
1063 gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmentv), topLine);
1064 }
1065
SetHorizontalScrollPos()1066 void ScintillaGTK::SetHorizontalScrollPos() {
1067 DwellEnd(true);
1068 gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmenth), xOffset / 2);
1069 }
1070
ModifyScrollBars(int nMax,int nPage)1071 bool ScintillaGTK::ModifyScrollBars(int nMax, int nPage) {
1072 bool modified = false;
1073 int pageScroll = LinesToScroll();
1074
1075 if (GTK_ADJUSTMENT(adjustmentv)->upper != (nMax + 1) ||
1076 GTK_ADJUSTMENT(adjustmentv)->page_size != nPage ||
1077 GTK_ADJUSTMENT(adjustmentv)->page_increment != pageScroll) {
1078 GTK_ADJUSTMENT(adjustmentv)->upper = nMax + 1;
1079 GTK_ADJUSTMENT(adjustmentv)->page_size = nPage;
1080 GTK_ADJUSTMENT(adjustmentv)->page_increment = pageScroll;
1081 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv));
1082 modified = true;
1083 }
1084
1085 PRectangle rcText = GetTextRectangle();
1086 int horizEndPreferred = scrollWidth;
1087 if (horizEndPreferred < 0)
1088 horizEndPreferred = 0;
1089 unsigned int pageWidth = rcText.Width();
1090 if (GTK_ADJUSTMENT(adjustmenth)->upper != horizEndPreferred ||
1091 GTK_ADJUSTMENT(adjustmenth)->page_size != pageWidth) {
1092 GTK_ADJUSTMENT(adjustmenth)->upper = horizEndPreferred;
1093 GTK_ADJUSTMENT(adjustmenth)->page_size = pageWidth;
1094 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth));
1095 modified = true;
1096 }
1097 return modified;
1098 }
1099
ReconfigureScrollBars()1100 void ScintillaGTK::ReconfigureScrollBars() {
1101 PRectangle rc = wMain.GetClientPosition();
1102 Resize(rc.Width(), rc.Height());
1103 }
1104
NotifyChange()1105 void ScintillaGTK::NotifyChange() {
1106 gtk_signal_emit(GTK_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL],
1107 Platform::LongFromTwoShorts(GetCtrlID(), SCEN_CHANGE), PWidget(wMain));
1108 }
1109
NotifyFocus(bool focus)1110 void ScintillaGTK::NotifyFocus(bool focus) {
1111 gtk_signal_emit(GTK_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL],
1112 Platform::LongFromTwoShorts(GetCtrlID(), focus ? SCEN_SETFOCUS : SCEN_KILLFOCUS), PWidget(wMain));
1113 }
1114
NotifyParent(SCNotification scn)1115 void ScintillaGTK::NotifyParent(SCNotification scn) {
1116 scn.nmhdr.hwndFrom = PWidget(wMain);
1117 scn.nmhdr.idFrom = GetCtrlID();
1118 gtk_signal_emit(GTK_OBJECT(sci), scintilla_signals[NOTIFY_SIGNAL],
1119 GetCtrlID(), &scn);
1120 }
1121
NotifyKey(int key,int modifiers)1122 void ScintillaGTK::NotifyKey(int key, int modifiers) {
1123 SCNotification scn = {0};
1124 scn.nmhdr.code = SCN_KEY;
1125 scn.ch = key;
1126 scn.modifiers = modifiers;
1127
1128 NotifyParent(scn);
1129 }
1130
NotifyURIDropped(const char * list)1131 void ScintillaGTK::NotifyURIDropped(const char *list) {
1132 SCNotification scn = {0};
1133 scn.nmhdr.code = SCN_URIDROPPED;
1134 scn.text = list;
1135
1136 NotifyParent(scn);
1137 }
1138
UseInputMethod() const1139 bool ScintillaGTK::UseInputMethod() const {
1140 switch (vs.styles[STYLE_DEFAULT].characterSet) {
1141 case SC_CHARSET_CHINESEBIG5:
1142 case SC_CHARSET_GB2312:
1143 case SC_CHARSET_HANGUL:
1144 case SC_CHARSET_SHIFTJIS:
1145 case SC_CHARSET_JOHAB:
1146 case SC_CHARSET_HEBREW:
1147 case SC_CHARSET_ARABIC:
1148 case SC_CHARSET_VIETNAMESE:
1149 case SC_CHARSET_THAI:
1150 return true;
1151 default:
1152 return false;
1153 }
1154 }
1155
1156 const char *CharacterSetID(int characterSet);
1157
CharacterSetID() const1158 const char *ScintillaGTK::CharacterSetID() const {
1159 return ::CharacterSetID(vs.styles[STYLE_DEFAULT].characterSet);
1160 }
1161
1162 #if GTK_MAJOR_VERSION >= 2
1163 #define IS_ACC(x) \
1164 ((x) >= 65103 && (x) <= 65111)
1165 #define IS_CHAR(x) \
1166 ((x) >= 0 && (x) <= 128)
1167
1168 #define IS_ACC_OR_CHAR(x) \
1169 (IS_CHAR(x)) || (IS_ACC(x))
1170
1171 #define IS_ACC(x) \
1172 ((x) >= 65103 && (x) <= 65111)
1173 #define IS_CHAR(x) \
1174 ((x) >= 0 && (x) <= 128)
1175
1176 #define IS_ACC_OR_CHAR(x) \
1177 (IS_CHAR(x)) || (IS_ACC(x))
1178
MakeAccent(int key,int acc)1179 static int MakeAccent(int key, int acc) {
1180 const char *conv[] = {
1181 "aeiounc AEIOUNC",
1182 "�ei�u�c~�EI�U�C",
1183 "�����n�'�����N�",
1184 "�����nc`�����NC",
1185 "�����nc^�����NC",
1186 "�����nc������NC"
1187 };
1188 int idx;
1189 for (idx = 0; idx < 15; ++idx) {
1190 if (char(key) == conv[0][idx]) {
1191 break;
1192 }
1193 }
1194 if (idx == 15) {
1195 return key;
1196 }
1197 if (acc == GDK_dead_tilde) { // ~
1198 return int((unsigned char)(conv[1][idx]));
1199 } else if (acc == GDK_dead_acute) { // '
1200 return int((unsigned char)(conv[2][idx]));
1201 } else if (acc == GDK_dead_grave) { // `
1202 return int((unsigned char)(conv[3][idx]));
1203 } else if (acc == GDK_dead_circumflex) { // ^
1204 return int((unsigned char)(conv[4][idx]));
1205 } else if (acc == GDK_dead_diaeresis) { // "
1206 return int((unsigned char)(conv[5][idx]));
1207 }
1208 return key;
1209 }
1210 #endif
1211
KeyDefault(int key,int modifiers)1212 int ScintillaGTK::KeyDefault(int key, int modifiers) {
1213 if (!(modifiers & SCI_CTRL) && !(modifiers & SCI_ALT)) {
1214 #if GTK_MAJOR_VERSION >= 2
1215 if (!UseInputMethod()) {
1216 char utfVal[4]="\0\0\0";
1217 wchar_t wcs[2];
1218 if (IS_CHAR(key) && IS_ACC(lastKey)) {
1219 lastKey = key = MakeAccent(key, lastKey);
1220 }
1221 if (IS_ACC_OR_CHAR(key)) {
1222 lastKey = key;
1223 }
1224 wcs[0] = gdk_keyval_to_unicode(key);
1225 wcs[1] = 0;
1226 UTF8FromUCS2(wcs, 1, utfVal, 3);
1227 if (key <= 0xFE00) {
1228 if (IsUnicodeMode()) {
1229 AddCharUTF(utfVal,strlen(utfVal));
1230 return 1;
1231 } else {
1232 const char *source = CharacterSetID();
1233 if (*source) {
1234 Converter conv(source, "UTF-8");
1235 if (conv) {
1236 char localeVal[4]="\0\0\0";
1237 char *pin = utfVal;
1238 size_t inLeft = strlen(utfVal);
1239 char *pout = localeVal;
1240 size_t outLeft = sizeof(localeVal);
1241 size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
1242 if (conversions != ((size_t)(-1))) {
1243 *pout = '\0';
1244 for (int i=0; localeVal[i]; i++) {
1245 AddChar(localeVal[i]);
1246 }
1247 return 1;
1248 }
1249 }
1250 }
1251 }
1252 }
1253 }
1254 #endif
1255 if (key < 256) {
1256 AddChar(key);
1257 return 1;
1258 } else {
1259 // Pass up to container in case it is an accelerator
1260 NotifyKey(key, modifiers);
1261 return 0;
1262 }
1263 } else {
1264 // Pass up to container in case it is an accelerator
1265 NotifyKey(key, modifiers);
1266 return 0;
1267 }
1268 //Platform::DebugPrintf("SK-key: %d %x %x\n",key, modifiers);
1269 }
1270
CopyToClipboard(const SelectionText & selectedText)1271 void ScintillaGTK::CopyToClipboard(const SelectionText &selectedText) {
1272 #ifndef USE_GTK_CLIPBOARD
1273 copyText.Copy(selectedText);
1274 gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)),
1275 atomClipboard,
1276 GDK_CURRENT_TIME);
1277 #else
1278 GtkClipboard *clipBoard;
1279 clipBoard = gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain)), atomClipboard);
1280 if (clipBoard == NULL) // Occurs if widget isn't in a toplevel
1281 return;
1282
1283 SelectionText *clipText = new SelectionText();
1284 clipText->Copy(selectedText);
1285
1286 gtk_clipboard_set_with_data(clipBoard, clipboardTargets, nClipboardTargets,
1287 ClipboardGetSelection, ClipboardClearSelection, clipText);
1288
1289 #endif
1290 }
1291
Copy()1292 void ScintillaGTK::Copy() {
1293 if (currentPos != anchor) {
1294 #ifndef USE_GTK_CLIPBOARD
1295 CopySelectionRange(©Text);
1296 gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)),
1297 atomClipboard,
1298 GDK_CURRENT_TIME);
1299 #else
1300 GtkClipboard *clipBoard;
1301 clipBoard = gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain)), atomClipboard);
1302 if (clipBoard == NULL) // Occurs if widget isn't in a toplevel
1303 return;
1304
1305 SelectionText *clipText = new SelectionText();
1306 CopySelectionRange(clipText);
1307
1308 gtk_clipboard_set_with_data(clipBoard, clipboardTargets, nClipboardTargets,
1309 ClipboardGetSelection, ClipboardClearSelection, clipText);
1310
1311 #endif
1312 #if PLAT_GTK_WIN32
1313 if (selType == selRectangle) {
1314 ::OpenClipboard(NULL);
1315 ::SetClipboardData(cfColumnSelect, 0);
1316 ::CloseClipboard();
1317 }
1318 #endif
1319 }
1320 }
1321
Paste()1322 void ScintillaGTK::Paste() {
1323 atomSought = atomUTF8;
1324 gtk_selection_convert(GTK_WIDGET(PWidget(wMain)),
1325 atomClipboard, atomSought, GDK_CURRENT_TIME);
1326 }
1327
CreateCallTipWindow(PRectangle rc)1328 void ScintillaGTK::CreateCallTipWindow(PRectangle rc) {
1329 if (!ct.wCallTip.Created()) {
1330 ct.wCallTip = gtk_window_new(GTK_WINDOW_POPUP);
1331 ct.wDraw = gtk_drawing_area_new();
1332 gtk_container_add(GTK_CONTAINER(PWidget(ct.wCallTip)), PWidget(ct.wDraw));
1333 gtk_signal_connect(GTK_OBJECT(PWidget(ct.wDraw)), "expose_event",
1334 GtkSignalFunc(ScintillaGTK::ExposeCT), &ct);
1335 gtk_signal_connect(GTK_OBJECT(PWidget(ct.wDraw)), "button_press_event",
1336 GtkSignalFunc(ScintillaGTK::PressCT), static_cast<void *>(this));
1337 gtk_widget_set_events(PWidget(ct.wDraw),
1338 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
1339 }
1340
1341 gtk_drawing_area_size(GTK_DRAWING_AREA(PWidget(ct.wDraw)),
1342 rc.Width(), rc.Height());
1343 ct.wDraw.Show();
1344 //ct.wCallTip.Show();
1345 //gtk_widget_set_usize(PWidget(ct.wCallTip), rc.Width(), rc.Height());
1346
1347 if( PWidget(ct.wCallTip)->window != NULL )
1348 gdk_window_resize(PWidget(ct.wCallTip)->window, rc.Width(), rc.Height());
1349 }
1350
AddToPopUp(const char * label,int cmd,bool enabled)1351 void ScintillaGTK::AddToPopUp(const char *label, int cmd, bool enabled) {
1352 char fulllabel[200];
1353 strcpy(fulllabel, "/");
1354 strcat(fulllabel, label);
1355 GtkItemFactoryCallback menuSig = GtkItemFactoryCallback(PopUpCB);
1356 GtkItemFactoryEntry itemEntry = {
1357 fulllabel, NULL,
1358 menuSig,
1359 cmd,
1360 const_cast<gchar *>(label[0] ? "<Item>" : "<Separator>"),
1361 #if GTK_MAJOR_VERSION >= 2
1362 NULL
1363 #endif
1364 };
1365 gtk_item_factory_create_item(GTK_ITEM_FACTORY(popup.GetID()),
1366 &itemEntry, this, 1);
1367 if (cmd) {
1368 GtkWidget *item = gtk_item_factory_get_widget_by_action(
1369 reinterpret_cast<GtkItemFactory *>(popup.GetID()), cmd);
1370 if (item)
1371 gtk_widget_set_sensitive(item, enabled);
1372 }
1373 }
1374
OwnPrimarySelection()1375 bool ScintillaGTK::OwnPrimarySelection() {
1376 return ((gdk_selection_owner_get(GDK_SELECTION_PRIMARY)
1377 == GTK_WIDGET(PWidget(wMain))->window) &&
1378 (GTK_WIDGET(PWidget(wMain))->window != NULL));
1379 }
1380
ClaimSelection()1381 void ScintillaGTK::ClaimSelection() {
1382 // X Windows has a 'primary selection' as well as the clipboard.
1383 // Whenever the user selects some text, we become the primary selection
1384 if (currentPos != anchor) {
1385 primarySelection = true;
1386 gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)),
1387 GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
1388 primary.Free();
1389 } else if (OwnPrimarySelection()) {
1390 primarySelection = true;
1391 if (primary.s == NULL)
1392 gtk_selection_owner_set(NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
1393 } else {
1394 primarySelection = false;
1395 primary.Free();
1396 }
1397 }
1398
1399 // Detect rectangular text, convert line ends to current mode, convert from or to UTF-8
GetGtkSelectionText(GtkSelectionData * selectionData,SelectionText & selText)1400 void ScintillaGTK::GetGtkSelectionText(GtkSelectionData *selectionData, SelectionText &selText) {
1401 char *data = reinterpret_cast<char *>(selectionData->data);
1402 int len = selectionData->length;
1403 GdkAtom selectionType = selectionData->type;
1404
1405 // Return empty string if selection is not a string
1406 if ((selectionType != GDK_TARGET_STRING) && (selectionType != atomUTF8)) {
1407 char *empty = new char[1];
1408 empty[0] = '\0';
1409 selText.Set(empty, 0, SC_CP_UTF8, 0, false);
1410 return;
1411 }
1412
1413 // Check for "\n\0" ending to string indicating that selection is rectangular
1414 bool isRectangular;
1415 #if PLAT_GTK_WIN32
1416 isRectangular = ::IsClipboardFormatAvailable(cfColumnSelect) != 0;
1417 #else
1418 isRectangular = ((len > 2) && (data[len - 1] == 0 && data[len - 2] == '\n'));
1419 #endif
1420
1421 char *dest;
1422 if (selectionType == GDK_TARGET_STRING) {
1423 dest = Document::TransformLineEnds(&len, data, len, pdoc->eolMode);
1424 if (IsUnicodeMode()) {
1425 // Unknown encoding so assume in Latin1
1426 char *destPrevious = dest;
1427 dest = UTF8FromLatin1(dest, len);
1428 selText.Set(dest, len, SC_CP_UTF8, 0, selText.rectangular);
1429 delete []destPrevious;
1430 } else {
1431 // Assume buffer is in same encoding as selection
1432 selText.Set(dest, len, pdoc->dbcsCodePage,
1433 vs.styles[STYLE_DEFAULT].characterSet, isRectangular);
1434 }
1435 } else { // UTF-8
1436 dest = Document::TransformLineEnds(&len, data, len, pdoc->eolMode);
1437 selText.Set(dest, len, SC_CP_UTF8, 0, isRectangular);
1438 #ifdef USE_CONVERTER
1439 const char *charSetBuffer = CharacterSetID();
1440 if (!IsUnicodeMode() && *charSetBuffer) {
1441 //fprintf(stderr, "Convert to locale %s\n", CharacterSetID());
1442 // Convert to locale
1443 dest = ConvertText(&len, selText.s, selText.len, charSetBuffer, "UTF-8");
1444 selText.Set(dest, len, pdoc->dbcsCodePage,
1445 vs.styles[STYLE_DEFAULT].characterSet, selText.rectangular);
1446 }
1447 #endif
1448 }
1449 }
1450
ReceivedSelection(GtkSelectionData * selection_data)1451 void ScintillaGTK::ReceivedSelection(GtkSelectionData *selection_data) {
1452 if ((selection_data->selection == atomClipboard) ||
1453 (selection_data->selection == GDK_SELECTION_PRIMARY)) {
1454 if ((atomSought == atomUTF8) && (selection_data->length <= 0)) {
1455 atomSought = atomString;
1456 gtk_selection_convert(GTK_WIDGET(PWidget(wMain)),
1457 selection_data->selection, atomSought, GDK_CURRENT_TIME);
1458 } else if ((selection_data->length > 0) &&
1459 ((selection_data->type == GDK_TARGET_STRING) || (selection_data->type == atomUTF8))) {
1460 SelectionText selText;
1461 GetGtkSelectionText(selection_data, selText);
1462
1463 pdoc->BeginUndoAction();
1464 if (selection_data->selection != GDK_SELECTION_PRIMARY) {
1465 ClearSelection();
1466 }
1467 int selStart = SelectionStart();
1468
1469 if (selText.rectangular) {
1470 PasteRectangular(selStart, selText.s, selText.len);
1471 } else {
1472 pdoc->InsertString(currentPos, selText.s, selText.len);
1473 SetEmptySelection(currentPos + selText.len);
1474 }
1475 pdoc->EndUndoAction();
1476 }
1477 }
1478 // else fprintf(stderr, "Target non string %d %d\n", (int)(selection_data->type),
1479 // (int)(atomUTF8));
1480 Redraw();
1481 }
1482
ReceivedDrop(GtkSelectionData * selection_data)1483 void ScintillaGTK::ReceivedDrop(GtkSelectionData *selection_data) {
1484 dragWasDropped = true;
1485 if ((selection_data->type == GDK_TARGET_STRING) || (selection_data->type == atomUTF8)) {
1486 if (selection_data->length > 0) {
1487 SelectionText selText;
1488 GetGtkSelectionText(selection_data, selText);
1489 DropAt(posDrop, selText.s, false, selText.rectangular);
1490 }
1491 } else {
1492 char *ptr = reinterpret_cast<char *>(selection_data->data);
1493 NotifyURIDropped(ptr);
1494 }
1495 Redraw();
1496 }
1497
1498
1499
GetSelection(GtkSelectionData * selection_data,guint info,SelectionText * text)1500 void ScintillaGTK::GetSelection(GtkSelectionData *selection_data, guint info, SelectionText *text) {
1501 #if GTK_MAJOR_VERSION >= 2
1502 // Convert text to utf8 if it isn't already
1503 SelectionText *converted = 0;
1504 if ((text->codePage != SC_CP_UTF8) && (info == TARGET_UTF8_STRING)) {
1505 const char *charSet = ::CharacterSetID(text->characterSet);
1506 if (*charSet) {
1507 int new_len;
1508 char* tmputf = ConvertText(&new_len, text->s, text->len, "UTF-8", charSet);
1509 converted = new SelectionText();
1510 converted->Set(tmputf, new_len, SC_CP_UTF8, 0, text->rectangular);
1511 text = converted;
1512 }
1513 }
1514
1515 // Here is a somewhat evil kludge.
1516 // As I can not work out how to store data on the clipboard in multiple formats
1517 // and need some way to mark the clipping as being stream or rectangular,
1518 // the terminating \0 is included in the length for rectangular clippings.
1519 // All other tested aplications behave benignly by ignoring the \0.
1520 // The #if is here because on Windows cfColumnSelect clip entry is used
1521 // instead as standard indicator of rectangularness (so no need to kludge)
1522 int len = strlen(text->s);
1523 #if PLAT_GTK_WIN32 == 0
1524 if (text->rectangular)
1525 len++;
1526 #endif
1527
1528 if (info == TARGET_UTF8_STRING) {
1529 gtk_selection_data_set_text(selection_data, text->s, len);
1530 } else {
1531 gtk_selection_data_set(selection_data,
1532 static_cast<GdkAtom>(GDK_SELECTION_TYPE_STRING),
1533 8, reinterpret_cast<unsigned char *>(text->s), len);
1534 }
1535 delete converted;
1536
1537 #else /* Gtk 1 */
1538 char *selBuffer = text->s;
1539
1540 #if PLAT_GTK_WIN32
1541
1542 // Many native win32 programs require \n line endings,
1543 // so make a copy of the clip text now with newlines converted
1544
1545 int new_len;
1546 char *tmpstr = Document::TransformLineEnds(&new_len, selBuffer, text->len, SC_EOL_LF);
1547 selBuffer = tmpstr;
1548 #endif
1549 char *tmputf = 0;
1550 if ((info == TARGET_UTF8_STRING) || (info == TARGET_STRING)) {
1551 int len = strlen(selBuffer);
1552 #ifdef USE_CONVERTER
1553 // Possible character set conversion
1554 const char *charSetBuffer = ::CharacterSetID(text->characterSet);
1555 if (info == TARGET_UTF8_STRING) {
1556 //fprintf(stderr, "Copy to clipboard as UTF-8\n");
1557 if (text->codePage != SC_CP_UTF8) {
1558 // Convert to UTF-8
1559 //fprintf(stderr, "Convert to UTF-8 from %s\n", charSetBuffer);
1560 tmputf = ConvertText(&len, selBuffer, len, "UTF-8", charSetBuffer);
1561 selBuffer = tmputf;
1562 }
1563 } else if (info == TARGET_STRING) {
1564 if (text->codePage == SC_CP_UTF8) {
1565 //fprintf(stderr, "Convert to locale %s\n", charSetBuffer);
1566 // Convert to locale
1567 tmputf = ConvertText(&len, selBuffer, len, charSetBuffer, "UTF-8");
1568 selBuffer = tmputf;
1569 }
1570 }
1571 #endif
1572
1573 // Here is a somewhat evil kludge.
1574 // As I can not work out how to store data on the clipboard in multiple formats
1575 // and need some way to mark the clipping as being stream or rectangular,
1576 // the terminating \0 is included in the length for rectangular clippings.
1577 // All other tested aplications behave benignly by ignoring the \0.
1578 // The #if is here because on Windows cfColumnSelect clip entry is used
1579 // instead as standard indicator of rectangularness (so no need to kludge)
1580 #if PLAT_GTK_WIN32 == 0
1581 if (text->rectangular)
1582 len++;
1583 #endif
1584 gtk_selection_data_set(selection_data,
1585 (info == TARGET_STRING) ?
1586 static_cast<GdkAtom>(GDK_SELECTION_TYPE_STRING) : atomUTF8,
1587 8, reinterpret_cast<unsigned char *>(selBuffer),
1588 len);
1589 } else if ((info == TARGET_TEXT) || (info == TARGET_COMPOUND_TEXT)) {
1590 guchar *text;
1591 GdkAtom encoding;
1592 gint format;
1593 gint new_length;
1594
1595 gdk_string_to_compound_text(reinterpret_cast<char *>(selBuffer),
1596 &encoding, &format, &text, &new_length);
1597 gtk_selection_data_set(selection_data, encoding, format, text, new_length);
1598 gdk_free_compound_text(text);
1599 }
1600
1601 delete []tmputf;
1602 #if PLAT_GTK_WIN32
1603 delete []tmpstr;
1604 #endif
1605 #endif /* Gtk >= 2 */
1606 }
1607
1608 #ifdef USE_GTK_CLIPBOARD
ClipboardGetSelection(GtkClipboard *,GtkSelectionData * selection_data,guint info,void * data)1609 void ScintillaGTK::ClipboardGetSelection(GtkClipboard *, GtkSelectionData *selection_data, guint info, void *data) {
1610 GetSelection(selection_data, info, static_cast<SelectionText*>(data));
1611 }
1612
ClipboardClearSelection(GtkClipboard *,void * data)1613 void ScintillaGTK::ClipboardClearSelection(GtkClipboard *, void *data) {
1614 SelectionText *obj = static_cast<SelectionText*>(data);
1615 delete obj;
1616 }
1617 #endif
1618
UnclaimSelection(GdkEventSelection * selection_event)1619 void ScintillaGTK::UnclaimSelection(GdkEventSelection *selection_event) {
1620 //Platform::DebugPrintf("UnclaimSelection\n");
1621 if (selection_event->selection == GDK_SELECTION_PRIMARY) {
1622 //Platform::DebugPrintf("UnclaimPrimarySelection\n");
1623 if (!OwnPrimarySelection()) {
1624 primary.Free();
1625 primarySelection = false;
1626 FullPaint();
1627 }
1628 }
1629 }
1630
Resize(int width,int height)1631 void ScintillaGTK::Resize(int width, int height) {
1632 //Platform::DebugPrintf("Resize %d %d\n", width, height);
1633 //printf("Resize %d %d\n", width, height);
1634
1635 // Not always needed, but some themes can have different sizes of scrollbars
1636 scrollBarWidth = GTK_WIDGET(PWidget(scrollbarv))->requisition.width;
1637 scrollBarHeight = GTK_WIDGET(PWidget(scrollbarh))->requisition.height;
1638
1639 // These allocations should never produce negative sizes as they would wrap around to huge
1640 // unsigned numbers inside GTK+ causing warnings.
1641 bool showSBHorizontal = horizontalScrollBarVisible && (wrapState == eWrapNone);
1642 int horizontalScrollBarHeight = scrollBarHeight;
1643 if (!showSBHorizontal)
1644 horizontalScrollBarHeight = 0;
1645 int verticalScrollBarHeight = scrollBarWidth;
1646 if (!verticalScrollBarVisible)
1647 verticalScrollBarHeight = 0;
1648
1649 GtkAllocation alloc;
1650 alloc.x = 0;
1651 if (showSBHorizontal) {
1652 alloc.y = height - scrollBarHeight;
1653 alloc.width = Platform::Maximum(1, width - scrollBarWidth) + 1;
1654 alloc.height = horizontalScrollBarHeight;
1655 } else {
1656 alloc.y = -scrollBarHeight;
1657 alloc.width = 0;
1658 alloc.height = 0;
1659 }
1660 gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarh)), &alloc);
1661
1662 alloc.y = 0;
1663 if (verticalScrollBarVisible) {
1664 alloc.x = width - scrollBarWidth;
1665 alloc.width = scrollBarWidth;
1666 alloc.height = Platform::Maximum(1, height - scrollBarHeight) + 1;
1667 if (!showSBHorizontal)
1668 alloc.height += scrollBarWidth-1;
1669 } else {
1670 alloc.x = -scrollBarWidth;
1671 alloc.width = 0;
1672 alloc.height = 0;
1673 }
1674 gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarv)), &alloc);
1675 if (GTK_WIDGET_MAPPED(PWidget(wMain))) {
1676 ChangeSize();
1677 }
1678
1679 alloc.x = 0;
1680 alloc.y = 0;
1681 alloc.width = Platform::Maximum(1, width - scrollBarWidth);
1682 alloc.height = Platform::Maximum(1, height - scrollBarHeight);
1683 if (!showSBHorizontal)
1684 alloc.height += scrollBarWidth;
1685 gtk_widget_size_allocate(GTK_WIDGET(PWidget(wText)), &alloc);
1686 }
1687
SetAdjustmentValue(GtkObject * object,int value)1688 static void SetAdjustmentValue(GtkObject *object, int value) {
1689 GtkAdjustment *adjustment = GTK_ADJUSTMENT(object);
1690 int maxValue = static_cast<int>(
1691 adjustment->upper - adjustment->page_size);
1692 if (value > maxValue)
1693 value = maxValue;
1694 if (value < 0)
1695 value = 0;
1696 gtk_adjustment_set_value(adjustment, value);
1697 }
1698
PressThis(GdkEventButton * event)1699 gint ScintillaGTK::PressThis(GdkEventButton *event) {
1700 //Platform::DebugPrintf("Press %x time=%d state = %x button = %x\n",this,event->time, event->state, event->button);
1701 // Do not use GTK+ double click events as Scintilla has its own double click detection
1702 if (event->type != GDK_BUTTON_PRESS)
1703 return FALSE;
1704
1705 evbtn = *event;
1706 Point pt;
1707 pt.x = int(event->x);
1708 pt.y = int(event->y);
1709 PRectangle rcClient = GetClientRectangle();
1710 //Platform::DebugPrintf("Press %0d,%0d in %0d,%0d %0d,%0d\n",
1711 // pt.x, pt.y, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1712 if ((pt.x > rcClient.right) || (pt.y > rcClient.bottom)) {
1713 Platform::DebugPrintf("Bad location\n");
1714 return FALSE;
1715 }
1716
1717 bool ctrl = (event->state & GDK_CONTROL_MASK) != 0;
1718
1719 gtk_widget_grab_focus(PWidget(wMain));
1720 if (event->button == 1) {
1721 // On X, instead of sending literal modifiers use control instead of alt
1722 // This is because most X window managers grab alt + click for moving
1723 #if !PLAT_GTK_WIN32
1724 ButtonDown(pt, event->time,
1725 (event->state & GDK_SHIFT_MASK) != 0,
1726 (event->state & GDK_CONTROL_MASK) != 0,
1727 (event->state & GDK_CONTROL_MASK) != 0);
1728 #else
1729 ButtonDown(pt, event->time,
1730 (event->state & GDK_SHIFT_MASK) != 0,
1731 (event->state & GDK_CONTROL_MASK) != 0,
1732 (event->state & GDK_MOD1_MASK) != 0);
1733 #endif
1734 } else if (event->button == 2) {
1735 // Grab the primary selection if it exists
1736 Position pos = PositionFromLocation(pt);
1737 if (OwnPrimarySelection() && primary.s == NULL)
1738 CopySelectionRange(&primary);
1739
1740 SetSelection(pos, pos);
1741 atomSought = atomUTF8;
1742 gtk_selection_convert(GTK_WIDGET(PWidget(wMain)), GDK_SELECTION_PRIMARY,
1743 atomSought, event->time);
1744 } else if (event->button == 3) {
1745 if (displayPopupMenu) {
1746 // PopUp menu
1747 // Convert to screen
1748 int ox = 0;
1749 int oy = 0;
1750 gdk_window_get_origin(PWidget(wMain)->window, &ox, &oy);
1751 ContextMenu(Point(pt.x + ox, pt.y + oy));
1752 } else {
1753 return FALSE;
1754 }
1755 } else if (event->button == 4) {
1756 // Wheel scrolling up (only xwin gtk does it this way)
1757 if (ctrl)
1758 SetAdjustmentValue(adjustmenth, (xOffset / 2) - 6);
1759 else
1760 SetAdjustmentValue(adjustmentv, topLine - 3);
1761 } else if (event->button == 5) {
1762 // Wheel scrolling down (only xwin gtk does it this way)
1763 if (ctrl)
1764 SetAdjustmentValue(adjustmenth, (xOffset / 2) + 6);
1765 else
1766 SetAdjustmentValue(adjustmentv, topLine + 3);
1767 }
1768 #if GTK_MAJOR_VERSION >= 2
1769 return TRUE;
1770 #else
1771 return FALSE;
1772 #endif
1773 }
1774
Press(GtkWidget * widget,GdkEventButton * event)1775 gint ScintillaGTK::Press(GtkWidget *widget, GdkEventButton *event) {
1776 if (event->window != widget->window)
1777 return FALSE;
1778 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
1779 return sciThis->PressThis(event);
1780 }
1781
MouseRelease(GtkWidget * widget,GdkEventButton * event)1782 gint ScintillaGTK::MouseRelease(GtkWidget *widget, GdkEventButton *event) {
1783 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
1784 //Platform::DebugPrintf("Release %x %d %d\n",sciThis,event->time,event->state);
1785 if (!sciThis->HaveMouseCapture())
1786 return FALSE;
1787 if (event->button == 1) {
1788 Point pt;
1789 pt.x = int(event->x);
1790 pt.y = int(event->y);
1791 //Platform::DebugPrintf("Up %x %x %d %d %d\n",
1792 // sciThis,event->window,event->time, pt.x, pt.y);
1793 if (event->window != PWidget(sciThis->wMain)->window)
1794 // If mouse released on scroll bar then the position is relative to the
1795 // scrollbar, not the drawing window so just repeat the most recent point.
1796 pt = sciThis->ptMouseLast;
1797 sciThis->ButtonUp(pt, event->time, (event->state & 4) != 0);
1798 }
1799 return FALSE;
1800 }
1801
1802 // win32gtk has a special wheel mouse event for whatever reason and doesn't
1803 // use the button4/5 trick used under X windows.
1804 #if PLAT_GTK_WIN32 || (GTK_MAJOR_VERSION >= 2)
ScrollEvent(GtkWidget * widget,GdkEventScroll * event)1805 gint ScintillaGTK::ScrollEvent(GtkWidget *widget,
1806 GdkEventScroll *event) {
1807 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
1808
1809 if (widget == NULL || event == NULL)
1810 return FALSE;
1811
1812 // Compute amount and direction to scroll (even tho on win32 there is
1813 // intensity of scrolling info in the native message, gtk doesn't
1814 // support this so we simulate similarly adaptive scrolling)
1815 int cLineScroll;
1816 int timeDelta = 1000000;
1817 GTimeVal curTime;
1818 g_get_current_time(&curTime);
1819 if (curTime.tv_sec == sciThis->lastWheelMouseTime.tv_sec)
1820 timeDelta = curTime.tv_usec - sciThis->lastWheelMouseTime.tv_usec;
1821 else if (curTime.tv_sec == sciThis->lastWheelMouseTime.tv_sec + 1)
1822 timeDelta = 1000000 + (curTime.tv_usec - sciThis->lastWheelMouseTime.tv_usec);
1823 if ((event->direction == sciThis->lastWheelMouseDirection) && (timeDelta < 250000)) {
1824 if (sciThis->wheelMouseIntensity < 12)
1825 sciThis->wheelMouseIntensity++;
1826 cLineScroll = sciThis->wheelMouseIntensity;
1827 } else {
1828 cLineScroll = sciThis->linesPerScroll;
1829 if (cLineScroll == 0)
1830 cLineScroll = 4;
1831 sciThis->wheelMouseIntensity = cLineScroll;
1832 }
1833 if (event->direction == GDK_SCROLL_UP) {
1834 cLineScroll *= -1;
1835 }
1836 g_get_current_time(&sciThis->lastWheelMouseTime);
1837 sciThis->lastWheelMouseDirection = event->direction;
1838
1839 // Note: Unpatched versions of win32gtk don't set the 'state' value so
1840 // only regular scrolling is supported there. Also, unpatched win32gtk
1841 // issues spurious button 2 mouse events during wheeling, which can cause
1842 // problems (a patch for both was submitted by archaeopteryx.com on 13Jun2001)
1843
1844 // Data zoom not supported
1845 if (event->state & GDK_SHIFT_MASK) {
1846 return FALSE;
1847 }
1848
1849 // Text font size zoom
1850 if (event->state & GDK_CONTROL_MASK) {
1851 if (cLineScroll < 0) {
1852 sciThis->KeyCommand(SCI_ZOOMIN);
1853 return TRUE;
1854 } else {
1855 sciThis->KeyCommand(SCI_ZOOMOUT);
1856 return TRUE;
1857 }
1858
1859 // Regular scrolling
1860 } else {
1861 sciThis->ScrollTo(sciThis->topLine + cLineScroll);
1862 return TRUE;
1863 }
1864 }
1865 #endif
1866
Motion(GtkWidget * widget,GdkEventMotion * event)1867 gint ScintillaGTK::Motion(GtkWidget *widget, GdkEventMotion *event) {
1868 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
1869 //Platform::DebugPrintf("Motion %x %d\n",sciThis,event->time);
1870 if (event->window != widget->window)
1871 return FALSE;
1872 int x = 0;
1873 int y = 0;
1874 GdkModifierType state;
1875 if (event->is_hint) {
1876 gdk_window_get_pointer(event->window, &x, &y, &state);
1877 } else {
1878 x = static_cast<int>(event->x);
1879 y = static_cast<int>(event->y);
1880 state = static_cast<GdkModifierType>(event->state);
1881 }
1882 //Platform::DebugPrintf("Move %x %x %d %c %d %d\n",
1883 // sciThis,event->window,event->time,event->is_hint? 'h' :'.', x, y);
1884 Point pt(x, y);
1885 sciThis->ButtonMove(pt);
1886 return FALSE;
1887 }
1888
1889 // Map the keypad keys to their equivalent functions
KeyTranslate(int keyIn)1890 static int KeyTranslate(int keyIn) {
1891 switch (keyIn) {
1892 case GDK_ISO_Left_Tab:
1893 return SCK_TAB;
1894 case GDK_KP_Down:
1895 return SCK_DOWN;
1896 case GDK_KP_Up:
1897 return SCK_UP;
1898 case GDK_KP_Left:
1899 return SCK_LEFT;
1900 case GDK_KP_Right:
1901 return SCK_RIGHT;
1902 case GDK_KP_Home:
1903 return SCK_HOME;
1904 case GDK_KP_End:
1905 return SCK_END;
1906 case GDK_KP_Page_Up:
1907 return SCK_PRIOR;
1908 case GDK_KP_Page_Down:
1909 return SCK_NEXT;
1910 case GDK_KP_Delete:
1911 return SCK_DELETE;
1912 case GDK_KP_Insert:
1913 return SCK_INSERT;
1914 case GDK_KP_Enter:
1915 return SCK_RETURN;
1916
1917 case GDK_Down:
1918 return SCK_DOWN;
1919 case GDK_Up:
1920 return SCK_UP;
1921 case GDK_Left:
1922 return SCK_LEFT;
1923 case GDK_Right:
1924 return SCK_RIGHT;
1925 case GDK_Home:
1926 return SCK_HOME;
1927 case GDK_End:
1928 return SCK_END;
1929 case GDK_Page_Up:
1930 return SCK_PRIOR;
1931 case GDK_Page_Down:
1932 return SCK_NEXT;
1933 case GDK_Delete:
1934 return SCK_DELETE;
1935 case GDK_Insert:
1936 return SCK_INSERT;
1937 case GDK_Escape:
1938 return SCK_ESCAPE;
1939 case GDK_BackSpace:
1940 return SCK_BACK;
1941 case GDK_Tab:
1942 return SCK_TAB;
1943 case GDK_Return:
1944 return SCK_RETURN;
1945 case GDK_KP_Add:
1946 return SCK_ADD;
1947 case GDK_KP_Subtract:
1948 return SCK_SUBTRACT;
1949 case GDK_KP_Divide:
1950 return SCK_DIVIDE;
1951 default:
1952 return keyIn;
1953 }
1954 }
1955
KeyThis(GdkEventKey * event)1956 gint ScintillaGTK::KeyThis(GdkEventKey *event) {
1957 //Platform::DebugPrintf("SC-key: %d %x [%s]\n",
1958 // event->keyval, event->state, (event->length > 0) ? event->string : "empty");
1959 #if GTK_MAJOR_VERSION >= 2
1960 if (UseInputMethod()) {
1961 if (gtk_im_context_filter_keypress(im_context, event)) {
1962 return 1;
1963 }
1964 }
1965 #endif
1966 if (!event->keyval) {
1967 return true;
1968 }
1969
1970 bool shift = (event->state & GDK_SHIFT_MASK) != 0;
1971 bool ctrl = (event->state & GDK_CONTROL_MASK) != 0;
1972 bool alt = (event->state & GDK_MOD1_MASK) != 0;
1973 int key = event->keyval;
1974 if (ctrl && (key < 128))
1975 key = toupper(key);
1976 else if (!ctrl && (key >= GDK_KP_Multiply && key <= GDK_KP_9))
1977 key &= 0x7F;
1978 // Hack for keys over 256 and below command keys but makes Hungarian work.
1979 // This will have to change for Unicode
1980 else if (key >= 0xFE00)
1981 key = KeyTranslate(key);
1982 else if (IsUnicodeMode())
1983 ; // No operation
1984 #if GTK_MAJOR_VERSION < 2
1985 else if ((key >= 0x100) && (key < 0x1000))
1986 key &= 0xff;
1987 #endif
1988
1989 bool consumed = false;
1990 bool added = KeyDown(key, shift, ctrl, alt, &consumed) != 0;
1991 if (!consumed)
1992 consumed = added;
1993 //Platform::DebugPrintf("SK-key: %d %x %x\n",event->keyval, event->state, consumed);
1994 if (event->keyval == 0xffffff && event->length > 0) {
1995 ClearSelection();
1996 if (pdoc->InsertString(CurrentPosition(), event->string)) {
1997 MovePositionTo(CurrentPosition() + event->length);
1998 }
1999 }
2000 return consumed;
2001 }
2002
KeyPress(GtkWidget * widget,GdkEventKey * event)2003 gint ScintillaGTK::KeyPress(GtkWidget *widget, GdkEventKey *event) {
2004 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2005 return sciThis->KeyThis(event);
2006 }
2007
KeyRelease(GtkWidget *,GdkEventKey *)2008 gint ScintillaGTK::KeyRelease(GtkWidget *, GdkEventKey * /*event*/) {
2009 //Platform::DebugPrintf("SC-keyrel: %d %x %3s\n",event->keyval, event->state, event->string);
2010 return FALSE;
2011 }
2012
2013 #if GTK_MAJOR_VERSION >= 2
ExposePreedit(GtkWidget * widget,GdkEventExpose * ose,ScintillaGTK * sciThis)2014 gint ScintillaGTK::ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis) {
2015 return sciThis->ExposePreeditThis(widget, ose);
2016 }
2017
ExposePreeditThis(GtkWidget * widget,GdkEventExpose * ose)2018 gint ScintillaGTK::ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose) {
2019 gchar *str;
2020 gint cursor_pos;
2021 PangoAttrList *attrs;
2022
2023 gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos);
2024 PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str);
2025 pango_layout_set_attributes(layout, attrs);
2026
2027 GdkGC *gc = gdk_gc_new(widget->window);
2028 GdkColor color[2] = { {0, 0x0000, 0x0000, 0x0000},
2029 {0, 0xffff, 0xffff, 0xffff}};
2030 gdk_color_alloc(gdk_colormap_get_system(), color);
2031 gdk_color_alloc(gdk_colormap_get_system(), color + 1);
2032
2033 gdk_gc_set_foreground(gc, color + 1);
2034 gdk_draw_rectangle(widget->window, gc, TRUE, ose->area.x, ose->area.y,
2035 ose->area.width, ose->area.height);
2036
2037 gdk_gc_set_foreground(gc, color);
2038 gdk_gc_set_background(gc, color + 1);
2039 gdk_draw_layout(widget->window, gc, 0, 0, layout);
2040
2041 gdk_gc_unref(gc);
2042 g_free(str);
2043 pango_attr_list_unref(attrs);
2044 g_object_unref(layout);
2045 return TRUE;
2046 }
2047
Commit(GtkIMContext *,char * str,ScintillaGTK * sciThis)2048 void ScintillaGTK::Commit(GtkIMContext *, char *str, ScintillaGTK *sciThis) {
2049 sciThis->CommitThis(str);
2050 }
2051
CommitThis(char * str)2052 void ScintillaGTK::CommitThis(char *str) {
2053 AddCharUTF(str, strlen(str));
2054 }
2055
PreeditChanged(GtkIMContext *,ScintillaGTK * sciThis)2056 void ScintillaGTK::PreeditChanged(GtkIMContext *, ScintillaGTK *sciThis) {
2057 sciThis->PreeditChangedThis();
2058 }
2059
PreeditChangedThis()2060 void ScintillaGTK::PreeditChangedThis() {
2061 gchar *str;
2062 PangoAttrList *attrs;
2063 gint cursor_pos;
2064 gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos);
2065 if (strlen(str) > 0){
2066 PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str);
2067 pango_layout_set_attributes(layout, attrs);
2068
2069 gint w, h;
2070 pango_layout_get_pixel_size(layout, &w, &h);
2071 g_object_unref(layout);
2072
2073 gint x, y;
2074 gdk_window_get_origin((PWidget(wText))->window, &x, &y);
2075
2076 Point pt = LocationFromPosition(currentPos);
2077 if (pt.x < 0)
2078 pt.x = 0;
2079 if (pt.y < 0)
2080 pt.y = 0;
2081
2082 gtk_window_move(GTK_WINDOW(PWidget(wPreedit)), x+pt.x, y+pt.y);
2083 gtk_window_resize(GTK_WINDOW(PWidget(wPreedit)), w, h);
2084 gtk_widget_show(PWidget(wPreedit));
2085 gtk_widget_queue_draw_area(PWidget(wPreeditDraw), 0, 0, w, h);
2086 } else {
2087 gtk_widget_hide(PWidget(wPreedit));
2088 }
2089 g_free(str);
2090 pango_attr_list_unref(attrs);
2091 }
2092 #endif
2093
StyleSetText(GtkWidget * widget,GtkStyle *,void *)2094 gint ScintillaGTK::StyleSetText(GtkWidget *widget, GtkStyle *, void*) {
2095 if (widget->window != NULL)
2096 gdk_window_set_back_pixmap(widget->window, NULL, FALSE);
2097 return FALSE;
2098 }
2099
RealizeText(GtkWidget * widget,void *)2100 gint ScintillaGTK::RealizeText(GtkWidget *widget, void*) {
2101 if (widget->window != NULL)
2102 gdk_window_set_back_pixmap(widget->window, NULL, FALSE);
2103 return FALSE;
2104 }
2105
Destroy(GtkObject * object)2106 void ScintillaGTK::Destroy(GtkObject* object) {
2107 ScintillaObject *scio = reinterpret_cast<ScintillaObject *>(object);
2108 // This avoids a double destruction
2109 if (!scio->pscin)
2110 return;
2111 ScintillaGTK *sciThis = reinterpret_cast<ScintillaGTK *>(scio->pscin);
2112 //Platform::DebugPrintf("Destroying %x %x\n", sciThis, object);
2113 sciThis->Finalise();
2114
2115 if (GTK_OBJECT_CLASS(parent_class)->destroy)
2116 (* GTK_OBJECT_CLASS(parent_class)->destroy)(object);
2117
2118 delete sciThis;
2119 scio->pscin = 0;
2120 }
2121
DrawChild(GtkWidget * widget,GdkRectangle * area)2122 static void DrawChild(GtkWidget *widget, GdkRectangle *area) {
2123 GdkRectangle areaIntersect;
2124 if (widget &&
2125 GTK_WIDGET_DRAWABLE(widget) &&
2126 gtk_widget_intersect(widget, area, &areaIntersect)) {
2127 gtk_widget_draw(widget, &areaIntersect);
2128 }
2129 }
2130
Draw(GtkWidget * widget,GdkRectangle * area)2131 void ScintillaGTK::Draw(GtkWidget *widget, GdkRectangle *area) {
2132 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2133 //Platform::DebugPrintf("Draw %p %0d,%0d %0d,%0d\n", widget, area->x, area->y, area->width, area->height);
2134 PRectangle rcPaint(area->x, area->y, area->x + area->width, area->y + area->height);
2135 sciThis->SyncPaint(rcPaint);
2136 if (GTK_WIDGET_DRAWABLE(PWidget(sciThis->wMain))) {
2137 DrawChild(PWidget(sciThis->scrollbarh), area);
2138 DrawChild(PWidget(sciThis->scrollbarv), area);
2139 }
2140
2141 #ifdef INTERNATIONAL_INPUT
2142 Point pt = sciThis->LocationFromPosition(sciThis->currentPos);
2143 pt.y += sciThis->vs.lineHeight - 2;
2144 if (pt.x < 0) pt.x = 0;
2145 if (pt.y < 0) pt.y = 0;
2146 CursorMoved(widget, pt.x, pt.y, sciThis);
2147 #endif
2148 }
2149
ExposeTextThis(GtkWidget *,GdkEventExpose * ose)2150 gint ScintillaGTK::ExposeTextThis(GtkWidget * /*widget*/, GdkEventExpose *ose) {
2151 paintState = painting;
2152
2153 rcPaint.left = ose->area.x;
2154 rcPaint.top = ose->area.y;
2155 rcPaint.right = ose->area.x + ose->area.width;
2156 rcPaint.bottom = ose->area.y + ose->area.height;
2157
2158 PRectangle rcClient = GetClientRectangle();
2159 paintingAllText = rcPaint.Contains(rcClient);
2160 Surface *surfaceWindow = Surface::Allocate();
2161 if (surfaceWindow) {
2162 surfaceWindow->Init(PWidget(wText)->window, PWidget(wText));
2163 Paint(surfaceWindow, rcPaint);
2164 surfaceWindow->Release();
2165 delete surfaceWindow;
2166 }
2167 if (paintState == paintAbandoned) {
2168 // Painting area was insufficient to cover new styling or brace highlight positions
2169 FullPaint();
2170 }
2171 paintState = notPainting;
2172 return FALSE;
2173 }
2174
ExposeText(GtkWidget * widget,GdkEventExpose * ose,ScintillaGTK * sciThis)2175 gint ScintillaGTK::ExposeText(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis) {
2176 return sciThis->ExposeTextThis(widget, ose);
2177 }
2178
ExposeMain(GtkWidget * widget,GdkEventExpose * ose)2179 gint ScintillaGTK::ExposeMain(GtkWidget *widget, GdkEventExpose *ose) {
2180 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2181 //Platform::DebugPrintf("Expose Main %0d,%0d %0d,%0d\n",
2182 //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2183 return sciThis->Expose(widget, ose);
2184 }
2185
Expose(GtkWidget *,GdkEventExpose * ose)2186 gint ScintillaGTK::Expose(GtkWidget *, GdkEventExpose *ose) {
2187 //fprintf(stderr, "Expose %0d,%0d %0d,%0d\n",
2188 //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2189
2190 #if GTK_MAJOR_VERSION < 2
2191
2192 paintState = painting;
2193
2194 rcPaint.left = ose->area.x;
2195 rcPaint.top = ose->area.y;
2196 rcPaint.right = ose->area.x + ose->area.width;
2197 rcPaint.bottom = ose->area.y + ose->area.height;
2198
2199 PRectangle rcClient = GetClientRectangle();
2200 paintingAllText = rcPaint.Contains(rcClient);
2201 Surface *surfaceWindow = Surface::Allocate();
2202 if (surfaceWindow) {
2203 surfaceWindow->Init(PWidget(wMain)->window, PWidget(wMain));
2204
2205 // Fill the corner between the scrollbars
2206 if (verticalScrollBarVisible) {
2207 if (horizontalScrollBarVisible && (wrapState == eWrapNone)) {
2208 PRectangle rcCorner = wMain.GetClientPosition();
2209 rcCorner.left = rcCorner.right - scrollBarWidth + 1;
2210 rcCorner.top = rcCorner.bottom - scrollBarHeight + 1;
2211 //fprintf(stderr, "Corner %0d,%0d %0d,%0d\n",
2212 //rcCorner.left, rcCorner.top, rcCorner.right, rcCorner.bottom);
2213 surfaceWindow->FillRectangle(rcCorner,
2214 vs.styles[STYLE_LINENUMBER].back.allocated);
2215 }
2216 }
2217
2218 //Paint(surfaceWindow, rcPaint);
2219 surfaceWindow->Release();
2220 delete surfaceWindow;
2221 }
2222 if (paintState == paintAbandoned) {
2223 // Painting area was insufficient to cover new styling or brace highlight positions
2224 FullPaint();
2225 }
2226 paintState = notPainting;
2227
2228 #else
2229 // For GTK+ 2, the text is painted in ExposeText
2230 gtk_container_propagate_expose(
2231 GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarh), ose);
2232 gtk_container_propagate_expose(
2233 GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarv), ose);
2234 #endif
2235
2236 return FALSE;
2237 }
2238
ScrollSignal(GtkAdjustment * adj,ScintillaGTK * sciThis)2239 void ScintillaGTK::ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) {
2240 sciThis->ScrollTo(static_cast<int>(adj->value), false);
2241 }
2242
ScrollHSignal(GtkAdjustment * adj,ScintillaGTK * sciThis)2243 void ScintillaGTK::ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) {
2244 sciThis->HorizontalScrollTo(static_cast<int>(adj->value * 2));
2245 }
2246
SelectionReceived(GtkWidget * widget,GtkSelectionData * selection_data,guint)2247 void ScintillaGTK::SelectionReceived(GtkWidget *widget,
2248 GtkSelectionData *selection_data, guint) {
2249 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2250 //Platform::DebugPrintf("Selection received\n");
2251 sciThis->ReceivedSelection(selection_data);
2252 }
2253
SelectionGet(GtkWidget * widget,GtkSelectionData * selection_data,guint info,guint)2254 void ScintillaGTK::SelectionGet(GtkWidget *widget,
2255 GtkSelectionData *selection_data, guint info, guint) {
2256 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2257 //Platform::DebugPrintf("Selection get\n");
2258 if (selection_data->selection == GDK_SELECTION_PRIMARY) {
2259 if (sciThis->primary.s == NULL) {
2260 sciThis->CopySelectionRange(&sciThis->primary);
2261 }
2262 sciThis->GetSelection(selection_data, info, &sciThis->primary);
2263 }
2264 #ifndef USE_GTK_CLIPBOARD
2265 else {
2266 sciThis->GetSelection(selection_data, info, &sciThis->copyText);
2267 }
2268 #endif
2269 }
2270
SelectionClear(GtkWidget * widget,GdkEventSelection * selection_event)2271 gint ScintillaGTK::SelectionClear(GtkWidget *widget, GdkEventSelection *selection_event) {
2272 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2273 //Platform::DebugPrintf("Selection clear\n");
2274 sciThis->UnclaimSelection(selection_event);
2275 return gtk_selection_clear(widget, selection_event);
2276 }
2277
2278 #if GTK_MAJOR_VERSION < 2
SelectionNotify(GtkWidget * widget,GdkEventSelection * selection_event)2279 gint ScintillaGTK::SelectionNotify(GtkWidget *widget, GdkEventSelection *selection_event) {
2280 //Platform::DebugPrintf("Selection notify\n");
2281 return gtk_selection_notify(widget, selection_event);
2282 }
2283 #endif
2284
DragBegin(GtkWidget *,GdkDragContext *)2285 void ScintillaGTK::DragBegin(GtkWidget *, GdkDragContext *) {
2286 //Platform::DebugPrintf("DragBegin\n");
2287 }
2288
DragMotion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint dragtime)2289 gboolean ScintillaGTK::DragMotion(GtkWidget *widget, GdkDragContext *context,
2290 gint x, gint y, guint dragtime) {
2291 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2292 //Platform::DebugPrintf("DragMotion %d %d %x %x %x\n", x, y,
2293 // context->actions, context->suggested_action, sciThis);
2294 Point npt(x, y);
2295 sciThis->inDragDrop = true;
2296 sciThis->SetDragPosition(sciThis->PositionFromLocation(npt));
2297 gdk_drag_status(context, context->suggested_action, dragtime);
2298 return FALSE;
2299 }
2300
DragLeave(GtkWidget * widget,GdkDragContext *,guint)2301 void ScintillaGTK::DragLeave(GtkWidget *widget, GdkDragContext * /*context*/, guint) {
2302 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2303 sciThis->SetDragPosition(invalidPosition);
2304 //Platform::DebugPrintf("DragLeave %x\n", sciThis);
2305 }
2306
DragEnd(GtkWidget * widget,GdkDragContext *)2307 void ScintillaGTK::DragEnd(GtkWidget *widget, GdkDragContext * /*context*/) {
2308 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2309 // If drag did not result in drop here or elsewhere
2310 if (!sciThis->dragWasDropped)
2311 sciThis->SetEmptySelection(sciThis->posDrag);
2312 sciThis->SetDragPosition(invalidPosition);
2313 //Platform::DebugPrintf("DragEnd %x %d\n", sciThis, sciThis->dragWasDropped);
2314 }
2315
Drop(GtkWidget * widget,GdkDragContext *,gint,gint,guint)2316 gboolean ScintillaGTK::Drop(GtkWidget *widget, GdkDragContext * /*context*/,
2317 gint, gint, guint) {
2318 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2319 //Platform::DebugPrintf("Drop %x\n", sciThis);
2320 sciThis->SetDragPosition(invalidPosition);
2321 return FALSE;
2322 }
2323
DragDataReceived(GtkWidget * widget,GdkDragContext *,gint,gint,GtkSelectionData * selection_data,guint,guint)2324 void ScintillaGTK::DragDataReceived(GtkWidget *widget, GdkDragContext * /*context*/,
2325 gint, gint, GtkSelectionData *selection_data, guint /*info*/, guint) {
2326 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2327 sciThis->ReceivedDrop(selection_data);
2328 sciThis->SetDragPosition(invalidPosition);
2329 }
2330
DragDataGet(GtkWidget * widget,GdkDragContext * context,GtkSelectionData * selection_data,guint info,guint)2331 void ScintillaGTK::DragDataGet(GtkWidget *widget, GdkDragContext *context,
2332 GtkSelectionData *selection_data, guint info, guint) {
2333 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2334 sciThis->dragWasDropped = true;
2335 if (sciThis->currentPos != sciThis->anchor) {
2336 sciThis->GetSelection(selection_data, info, &sciThis->drag);
2337 }
2338 if (context->action == GDK_ACTION_MOVE) {
2339 int selStart = sciThis->SelectionStart();
2340 int selEnd = sciThis->SelectionEnd();
2341 if (sciThis->posDrop > selStart) {
2342 if (sciThis->posDrop > selEnd)
2343 sciThis->posDrop = sciThis->posDrop - (selEnd - selStart);
2344 else
2345 sciThis->posDrop = selStart;
2346 sciThis->posDrop = sciThis->pdoc->ClampPositionIntoDocument(sciThis->posDrop);
2347 }
2348 sciThis->ClearSelection();
2349 }
2350 sciThis->SetDragPosition(invalidPosition);
2351 }
2352
TimeOut(ScintillaGTK * sciThis)2353 int ScintillaGTK::TimeOut(ScintillaGTK *sciThis) {
2354 sciThis->Tick();
2355 return 1;
2356 }
2357
IdleCallback(ScintillaGTK * sciThis)2358 int ScintillaGTK::IdleCallback(ScintillaGTK *sciThis) {
2359 // Idler will be automatically stoped, if there is nothing
2360 // to do while idle.
2361 bool ret = sciThis->Idle();
2362 if (ret == false) {
2363 // FIXME: This will remove the idler from GTK, we don't want to
2364 // remove it as it is removed automatically when this function
2365 // returns false (although, it should be harmless).
2366 sciThis->SetIdle(false);
2367 }
2368 return ret;
2369 }
2370
PopUpCB(ScintillaGTK * sciThis,guint action,GtkWidget *)2371 void ScintillaGTK::PopUpCB(ScintillaGTK *sciThis, guint action, GtkWidget *) {
2372 if (action) {
2373 sciThis->Command(action);
2374 }
2375 }
2376
PressCT(GtkWidget * widget,GdkEventButton * event,ScintillaGTK * sciThis)2377 gint ScintillaGTK::PressCT(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis) {
2378 if (event->window != widget->window)
2379 return FALSE;
2380 if (event->type != GDK_BUTTON_PRESS)
2381 return FALSE;
2382 Point pt;
2383 pt.x = int(event->x);
2384 pt.y = int(event->y);
2385 sciThis->ct.MouseClick(pt);
2386 sciThis->CallTipClick();
2387 #if GTK_MAJOR_VERSION >= 2
2388 return TRUE;
2389 #else
2390 return FALSE;
2391 #endif
2392 }
2393
ExposeCT(GtkWidget * widget,GdkEventExpose *,CallTip * ctip)2394 gint ScintillaGTK::ExposeCT(GtkWidget *widget, GdkEventExpose * /*ose*/, CallTip *ctip) {
2395 Surface *surfaceWindow = Surface::Allocate();
2396 if (surfaceWindow) {
2397 surfaceWindow->Init(widget->window, widget);
2398 ctip->PaintCT(surfaceWindow);
2399 surfaceWindow->Release();
2400 delete surfaceWindow;
2401 }
2402 return TRUE;
2403 }
2404
DirectFunction(ScintillaGTK * sciThis,unsigned int iMessage,uptr_t wParam,sptr_t lParam)2405 sptr_t ScintillaGTK::DirectFunction(
2406 ScintillaGTK *sciThis, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
2407 return sciThis->WndProc(iMessage, wParam, lParam);
2408 }
2409
scintilla_send_message(ScintillaObject * sci,unsigned int iMessage,uptr_t wParam,sptr_t lParam)2410 sptr_t scintilla_send_message(ScintillaObject *sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
2411 ScintillaGTK *psci = reinterpret_cast<ScintillaGTK *>(sci->pscin);
2412 return psci->WndProc(iMessage, wParam, lParam);
2413 }
2414
2415 static void scintilla_class_init(ScintillaClass *klass);
2416 static void scintilla_init(ScintillaObject *sci);
2417
2418 extern void Platform_Initialise();
2419 extern void Platform_Finalise();
2420
scintilla_get_type()2421 GtkType scintilla_get_type() {
2422 static GtkType scintilla_type = 0;
2423
2424 if (!scintilla_type) {
2425 Platform_Initialise();
2426 static GtkTypeInfo scintilla_info = {
2427 "Scintilla",
2428 sizeof (ScintillaObject),
2429 sizeof (ScintillaClass),
2430 (GtkClassInitFunc) scintilla_class_init,
2431 (GtkObjectInitFunc) scintilla_init,
2432 (gpointer) NULL,
2433 (gpointer) NULL,
2434 0
2435 };
2436
2437 scintilla_type = gtk_type_unique(gtk_container_get_type(), &scintilla_info);
2438 }
2439
2440 return scintilla_type;
2441 }
2442
ClassInit(GtkObjectClass * object_class,GtkWidgetClass * widget_class,GtkContainerClass * container_class)2443 void ScintillaGTK::ClassInit(GtkObjectClass* object_class, GtkWidgetClass *widget_class, GtkContainerClass *container_class) {
2444 atomClipboard = gdk_atom_intern("CLIPBOARD", FALSE);
2445 atomUTF8 = gdk_atom_intern("UTF8_STRING", FALSE);
2446 atomString = GDK_SELECTION_TYPE_STRING;
2447
2448 // Define default signal handlers for the class: Could move more
2449 // of the signal handlers here (those that currently attached to wDraw
2450 // in Initialise() may require coordinate translation?)
2451
2452 object_class->destroy = Destroy;
2453
2454 widget_class->size_request = SizeRequest;
2455 widget_class->size_allocate = SizeAllocate;
2456 widget_class->expose_event = ExposeMain;
2457 #if GTK_MAJOR_VERSION < 2
2458 widget_class->draw = Draw;
2459 #endif
2460
2461 widget_class->motion_notify_event = Motion;
2462 widget_class->button_press_event = Press;
2463 widget_class->button_release_event = MouseRelease;
2464 #if PLAT_GTK_WIN32 || (GTK_MAJOR_VERSION >= 2)
2465 widget_class->scroll_event = ScrollEvent;
2466 #endif
2467 widget_class->key_press_event = KeyPress;
2468 widget_class->key_release_event = KeyRelease;
2469 widget_class->focus_in_event = FocusIn;
2470 widget_class->focus_out_event = FocusOut;
2471 widget_class->selection_received = SelectionReceived;
2472 widget_class->selection_get = SelectionGet;
2473 widget_class->selection_clear_event = SelectionClear;
2474 #if GTK_MAJOR_VERSION < 2
2475 widget_class->selection_notify_event = SelectionNotify;
2476 #endif
2477
2478 widget_class->drag_data_received = DragDataReceived;
2479 widget_class->drag_motion = DragMotion;
2480 widget_class->drag_leave = DragLeave;
2481 widget_class->drag_end = DragEnd;
2482 widget_class->drag_drop = Drop;
2483 widget_class->drag_data_get = DragDataGet;
2484
2485 widget_class->realize = Realize;
2486 widget_class->unrealize = UnRealize;
2487 widget_class->map = Map;
2488 widget_class->unmap = UnMap;
2489
2490 container_class->forall = MainForAll;
2491 }
2492
2493 #if GTK_MAJOR_VERSION < 2
2494 #define GTK_CLASS_TYPE(c) (c->type)
2495 #define SIG_MARSHAL gtk_marshal_NONE__INT_POINTER
2496 #else
2497 #define SIG_MARSHAL scintilla_marshal_NONE__INT_POINTER
2498 #endif
2499 #define MARSHAL_ARGUMENTS GTK_TYPE_INT, GTK_TYPE_POINTER
2500
scintilla_class_init(ScintillaClass * klass)2501 static void scintilla_class_init(ScintillaClass *klass) {
2502 GtkObjectClass *object_class = (GtkObjectClass*) klass;
2503 GtkWidgetClass *widget_class = (GtkWidgetClass*) klass;
2504 GtkContainerClass *container_class = (GtkContainerClass*) klass;
2505
2506 parent_class = (GtkWidgetClass*) gtk_type_class(gtk_container_get_type());
2507
2508 scintilla_signals[COMMAND_SIGNAL] = gtk_signal_new(
2509 "command",
2510 GTK_RUN_LAST,
2511 GTK_CLASS_TYPE(object_class),
2512 GTK_SIGNAL_OFFSET(ScintillaClass, command),
2513 SIG_MARSHAL,
2514 GTK_TYPE_NONE,
2515 2, MARSHAL_ARGUMENTS);
2516
2517 scintilla_signals[NOTIFY_SIGNAL] = gtk_signal_new(
2518 SCINTILLA_NOTIFY,
2519 GTK_RUN_LAST,
2520 GTK_CLASS_TYPE(object_class),
2521 GTK_SIGNAL_OFFSET(ScintillaClass, notify),
2522 SIG_MARSHAL,
2523 GTK_TYPE_NONE,
2524 2, MARSHAL_ARGUMENTS);
2525 #if GTK_MAJOR_VERSION < 2
2526 gtk_object_class_add_signals(object_class,
2527 reinterpret_cast<unsigned int *>(scintilla_signals), LAST_SIGNAL);
2528 #endif
2529 klass->command = NULL;
2530 klass->notify = NULL;
2531
2532 ScintillaGTK::ClassInit(object_class, widget_class, container_class);
2533 }
2534
scintilla_init(ScintillaObject * sci)2535 static void scintilla_init(ScintillaObject *sci) {
2536 GTK_WIDGET_SET_FLAGS(sci, GTK_CAN_FOCUS);
2537 sci->pscin = new ScintillaGTK(sci);
2538 }
2539
scintilla_new()2540 GtkWidget* scintilla_new() {
2541 return GTK_WIDGET(gtk_type_new(scintilla_get_type()));
2542 }
2543
scintilla_set_id(ScintillaObject * sci,int id)2544 void scintilla_set_id(ScintillaObject *sci, int id) {
2545 ScintillaGTK *psci = reinterpret_cast<ScintillaGTK *>(sci->pscin);
2546 psci->ctrlID = id;
2547 }
2548
scintilla_release_resources(void)2549 void scintilla_release_resources(void) {
2550 Platform_Finalise();
2551 }
2552