OSDN Git Service

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