scintilla: Update scintilla with changeset 3662:1d1c06df8a2f using gtk+3
[anjuta-extras.git] / plugins / scintilla / scintilla / ScintillaGTK.cxx
blob5682fde647539903419798bb557c285d1fc6948e
1 // Scintilla source code edit control
2 // ScintillaGTK.cxx - GTK+ specific subclass of ScintillaBase
3 // Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
4 // The License.txt file describes the conditions under which this software may be distributed.
6 #include <new>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <assert.h>
11 #include <ctype.h>
12 #include <time.h>
14 #include <string>
15 #include <vector>
17 #include <gtk/gtk.h>
18 #include <gdk/gdkkeysyms.h>
20 #include "Platform.h"
22 #if PLAT_GTK_WIN32
23 #include "windows.h"
24 #endif
26 #include "ILexer.h"
27 #include "Scintilla.h"
28 #include "ScintillaWidget.h"
29 #ifdef SCI_LEXER
30 #include "SciLexer.h"
31 #endif
32 #include "SVector.h"
33 #include "SplitVector.h"
34 #include "Partitioning.h"
35 #include "RunStyles.h"
36 #include "ContractionState.h"
37 #include "CellBuffer.h"
38 #include "CallTip.h"
39 #include "KeyMap.h"
40 #include "Indicator.h"
41 #include "XPM.h"
42 #include "LineMarker.h"
43 #include "Style.h"
44 #include "AutoComplete.h"
45 #include "ViewStyle.h"
46 #include "Decoration.h"
47 #include "CharClassify.h"
48 #include "Document.h"
49 #include "Selection.h"
50 #include "PositionCache.h"
51 #include "Editor.h"
52 #include "ScintillaBase.h"
53 #include "UniConversion.h"
55 #include "scintilla-marshal.h"
57 #ifdef SCI_LEXER
58 #include <glib.h>
59 #include <gmodule.h>
60 #include "LexerModule.h"
61 #include "ExternalLexer.h"
62 #endif
64 #include "Converter.h"
66 #if GTK_CHECK_VERSION(2,20,0)
67 #define IS_WIDGET_REALIZED(w) (gtk_widget_get_realized(GTK_WIDGET(w)))
68 #define IS_WIDGET_MAPPED(w) (gtk_widget_get_mapped(GTK_WIDGET(w)))
69 #define IS_WIDGET_VISIBLE(w) (gtk_widget_get_visible(GTK_WIDGET(w)))
70 #else
71 #define IS_WIDGET_REALIZED(w) (GTK_WIDGET_REALIZED(w))
72 #define IS_WIDGET_MAPPED(w) (GTK_WIDGET_MAPPED(w))
73 #define IS_WIDGET_VISIBLE(w) (GTK_WIDGET_VISIBLE(w))
74 #endif
76 #if GTK_CHECK_VERSION(2,22,0)
77 #define USE_CAIRO 1
78 #endif
80 static GdkWindow *WindowFromWidget(GtkWidget *w) {
81 #if GTK_CHECK_VERSION(3,0,0)
82 return gtk_widget_get_window(w);
83 #else
84 return w->window;
85 #endif
88 static GdkWindow *PWindow(const Window &w) {
89 GtkWidget *widget = reinterpret_cast<GtkWidget *>(w.GetID());
90 #if GTK_CHECK_VERSION(3,0,0)
91 return gtk_widget_get_window(widget);
92 #else
93 return widget->window;
94 #endif
97 #ifdef _MSC_VER
98 // Constant conditional expressions are because of GTK+ headers
99 #pragma warning(disable: 4127)
100 // Ignore unreferenced local functions in GTK+ headers
101 #pragma warning(disable: 4505)
102 #endif
104 #if GTK_CHECK_VERSION(2,6,0)
105 #define USE_GTK_CLIPBOARD
106 #endif
108 #define OBJECT_CLASS GObjectClass
110 #ifdef SCI_NAMESPACE
111 using namespace Scintilla;
112 #endif
114 extern char *UTF8FromLatin1(const char *s, int &len);
116 class ScintillaGTK : public ScintillaBase {
117 _ScintillaObject *sci;
118 Window wText;
119 Window scrollbarv;
120 Window scrollbarh;
121 GtkAdjustment *adjustmentv;
122 GtkAdjustment *adjustmenth;
123 int scrollBarWidth;
124 int scrollBarHeight;
126 // Because clipboard access is asynchronous, copyText is created by Copy
127 #ifndef USE_GTK_CLIPBOARD
128 SelectionText copyText;
129 #endif
131 SelectionText primary;
133 GdkEventButton evbtn;
134 bool capturedMouse;
135 bool dragWasDropped;
136 int lastKey;
137 int rectangularSelectionModifier;
139 GtkWidgetClass *parentClass;
141 static GdkAtom atomClipboard;
142 static GdkAtom atomUTF8;
143 static GdkAtom atomString;
144 static GdkAtom atomUriList;
145 static GdkAtom atomDROPFILES_DND;
146 GdkAtom atomSought;
148 #if PLAT_GTK_WIN32
149 CLIPFORMAT cfColumnSelect;
150 #endif
152 Window wPreedit;
153 Window wPreeditDraw;
154 GtkIMContext *im_context;
156 // Wheel mouse support
157 unsigned int linesPerScroll;
158 GTimeVal lastWheelMouseTime;
159 gint lastWheelMouseDirection;
160 gint wheelMouseIntensity;
162 #if GTK_CHECK_VERSION(3,0,0)
163 cairo_rectangle_list_t *rgnUpdate;
164 #else
165 GdkRegion *rgnUpdate;
166 #endif
168 // Private so ScintillaGTK objects can not be copied
169 ScintillaGTK(const ScintillaGTK &);
170 ScintillaGTK &operator=(const ScintillaGTK &);
172 public:
173 ScintillaGTK(_ScintillaObject *sci_);
174 virtual ~ScintillaGTK();
175 static void ClassInit(OBJECT_CLASS* object_class, GtkWidgetClass *widget_class, GtkContainerClass *container_class);
176 private:
177 virtual void Initialise();
178 virtual void Finalise();
179 virtual void DisplayCursor(Window::Cursor c);
180 virtual bool DragThreshold(Point ptStart, Point ptNow);
181 virtual void StartDrag();
182 int TargetAsUTF8(char *text);
183 int EncodedFromUTF8(char *utf8, char *encoded);
184 virtual bool ValidCodePage(int codePage) const;
185 public: // Public for scintilla_send_message
186 virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
187 private:
188 virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
189 virtual void SetTicking(bool on);
190 virtual bool SetIdle(bool on);
191 virtual void SetMouseCapture(bool on);
192 virtual bool HaveMouseCapture();
193 virtual bool PaintContains(PRectangle rc);
194 void FullPaint();
195 virtual PRectangle GetClientRectangle();
196 void SyncPaint(PRectangle rc);
197 virtual void ScrollText(int linesToMove);
198 virtual void SetVerticalScrollPos();
199 virtual void SetHorizontalScrollPos();
200 virtual bool ModifyScrollBars(int nMax, int nPage);
201 void ReconfigureScrollBars();
202 virtual void NotifyChange();
203 virtual void NotifyFocus(bool focus);
204 virtual void NotifyParent(SCNotification scn);
205 void NotifyKey(int key, int modifiers);
206 void NotifyURIDropped(const char *list);
207 const char *CharacterSetID() const;
208 virtual CaseFolder *CaseFolderForEncoding();
209 virtual std::string CaseMapString(const std::string &s, int caseMapping);
210 virtual int KeyDefault(int key, int modifiers);
211 virtual void CopyToClipboard(const SelectionText &selectedText);
212 virtual void Copy();
213 virtual void Paste();
214 virtual void CreateCallTipWindow(PRectangle rc);
215 virtual void AddToPopUp(const char *label, int cmd = 0, bool enabled = true);
216 bool OwnPrimarySelection();
217 virtual void ClaimSelection();
218 void GetGtkSelectionText(GtkSelectionData *selectionData, SelectionText &selText);
219 void ReceivedSelection(GtkSelectionData *selection_data);
220 void ReceivedDrop(GtkSelectionData *selection_data);
221 static void GetSelection(GtkSelectionData *selection_data, guint info, SelectionText *selected);
222 #ifdef USE_GTK_CLIPBOARD
223 void StoreOnClipboard(SelectionText *clipText);
224 static void ClipboardGetSelection(GtkClipboard* clip, GtkSelectionData *selection_data, guint info, void *data);
225 static void ClipboardClearSelection(GtkClipboard* clip, void *data);
226 #endif
228 void UnclaimSelection(GdkEventSelection *selection_event);
229 void Resize(int width, int height);
231 // Callback functions
232 void RealizeThis(GtkWidget *widget);
233 static void Realize(GtkWidget *widget);
234 void UnRealizeThis(GtkWidget *widget);
235 static void UnRealize(GtkWidget *widget);
236 void MapThis();
237 static void Map(GtkWidget *widget);
238 void UnMapThis();
239 static void UnMap(GtkWidget *widget);
240 gint FocusInThis(GtkWidget *widget);
241 static gint FocusIn(GtkWidget *widget, GdkEventFocus *event);
242 gint FocusOutThis(GtkWidget *widget);
243 static gint FocusOut(GtkWidget *widget, GdkEventFocus *event);
244 static void SizeRequest(GtkWidget *widget, GtkRequisition *requisition);
245 static void GetPreferredWidth(GtkWidget *widget, gint *minimalWidth, gint *naturalWidth);
246 static void GetPreferredHeight(GtkWidget *widget, gint *minimalHeight, gint *naturalHeight);
247 static void SizeAllocate(GtkWidget *widget, GtkAllocation *allocation);
248 #if GTK_CHECK_VERSION(3,0,0)
249 gboolean DrawTextThis(cairo_t *cr);
250 static gboolean DrawText(GtkWidget *widget, cairo_t *cr, ScintillaGTK *sciThis);
251 gboolean DrawThis(cairo_t *cr);
252 static gboolean DrawMain(GtkWidget *widget, cairo_t *cr);
253 #else
254 gboolean ExposeTextThis(GtkWidget *widget, GdkEventExpose *ose);
255 static gboolean ExposeText(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis);
256 gboolean Expose(GtkWidget *widget, GdkEventExpose *ose);
257 static gboolean ExposeMain(GtkWidget *widget, GdkEventExpose *ose);
258 #endif
259 static void Draw(GtkWidget *widget, GdkRectangle *area);
260 void ForAll(GtkCallback callback, gpointer callback_data);
261 static void MainForAll(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data);
263 static void ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis);
264 static void ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis);
265 gint PressThis(GdkEventButton *event);
266 static gint Press(GtkWidget *widget, GdkEventButton *event);
267 static gint MouseRelease(GtkWidget *widget, GdkEventButton *event);
268 static gint ScrollEvent(GtkWidget *widget, GdkEventScroll *event);
269 static gint Motion(GtkWidget *widget, GdkEventMotion *event);
270 gboolean KeyThis(GdkEventKey *event);
271 static gboolean KeyPress(GtkWidget *widget, GdkEventKey *event);
272 static gboolean KeyRelease(GtkWidget *widget, GdkEventKey *event);
273 gboolean ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose);
274 static gboolean ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis);
275 void CommitThis(char *str);
276 static void Commit(GtkIMContext *context, char *str, ScintillaGTK *sciThis);
277 void PreeditChangedThis();
278 static void PreeditChanged(GtkIMContext *context, ScintillaGTK *sciThis);
279 static void StyleSetText(GtkWidget *widget, GtkStyle *previous, void*);
280 static void RealizeText(GtkWidget *widget, void*);
281 static void Destroy(GObject *object);
282 static void SelectionReceived(GtkWidget *widget, GtkSelectionData *selection_data,
283 guint time);
284 static void SelectionGet(GtkWidget *widget, GtkSelectionData *selection_data,
285 guint info, guint time);
286 static gint SelectionClear(GtkWidget *widget, GdkEventSelection *selection_event);
287 static void DragBegin(GtkWidget *widget, GdkDragContext *context);
288 gboolean DragMotionThis(GdkDragContext *context, gint x, gint y, guint dragtime);
289 static gboolean DragMotion(GtkWidget *widget, GdkDragContext *context,
290 gint x, gint y, guint dragtime);
291 static void DragLeave(GtkWidget *widget, GdkDragContext *context,
292 guint time);
293 static void DragEnd(GtkWidget *widget, GdkDragContext *context);
294 static gboolean Drop(GtkWidget *widget, GdkDragContext *context,
295 gint x, gint y, guint time);
296 static void DragDataReceived(GtkWidget *widget, GdkDragContext *context,
297 gint x, gint y, GtkSelectionData *selection_data, guint info, guint time);
298 static void DragDataGet(GtkWidget *widget, GdkDragContext *context,
299 GtkSelectionData *selection_data, guint info, guint time);
300 static gboolean TimeOut(ScintillaGTK *sciThis);
301 static gboolean IdleCallback(ScintillaGTK *sciThis);
302 static gboolean StyleIdle(ScintillaGTK *sciThis);
303 virtual void QueueStyling(int upTo);
304 static void PopUpCB(GtkMenuItem *menuItem, ScintillaGTK *sciThis);
306 #if GTK_CHECK_VERSION(3,0,0)
307 static gboolean DrawCT(GtkWidget *widget, cairo_t *cr, CallTip *ctip);
308 #else
309 static gboolean ExposeCT(GtkWidget *widget, GdkEventExpose *ose, CallTip *ct);
310 #endif
311 static gboolean PressCT(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis);
313 static sptr_t DirectFunction(ScintillaGTK *sciThis,
314 unsigned int iMessage, uptr_t wParam, sptr_t lParam);
317 enum {
318 COMMAND_SIGNAL,
319 NOTIFY_SIGNAL,
320 LAST_SIGNAL
323 static gint scintilla_signals[LAST_SIGNAL] = { 0 };
325 enum {
326 TARGET_STRING,
327 TARGET_TEXT,
328 TARGET_COMPOUND_TEXT,
329 TARGET_UTF8_STRING,
330 TARGET_URI
333 GdkAtom ScintillaGTK::atomClipboard = 0;
334 GdkAtom ScintillaGTK::atomUTF8 = 0;
335 GdkAtom ScintillaGTK::atomString = 0;
336 GdkAtom ScintillaGTK::atomUriList = 0;
337 GdkAtom ScintillaGTK::atomDROPFILES_DND = 0;
339 static const GtkTargetEntry clipboardCopyTargets[] = {
340 { (gchar *) "UTF8_STRING", 0, TARGET_UTF8_STRING },
341 { (gchar *) "STRING", 0, TARGET_STRING },
343 static const gint nClipboardCopyTargets = sizeof(clipboardCopyTargets) / sizeof(clipboardCopyTargets[0]);
345 static const GtkTargetEntry clipboardPasteTargets[] = {
346 { (gchar *) "text/uri-list", 0, TARGET_URI },
347 { (gchar *) "UTF8_STRING", 0, TARGET_UTF8_STRING },
348 { (gchar *) "STRING", 0, TARGET_STRING },
350 static const gint nClipboardPasteTargets = sizeof(clipboardPasteTargets) / sizeof(clipboardPasteTargets[0]);
352 static GtkWidget *PWidget(Window &w) {
353 return reinterpret_cast<GtkWidget *>(w.GetID());
356 static ScintillaGTK *ScintillaFromWidget(GtkWidget *widget) {
357 ScintillaObject *scio = reinterpret_cast<ScintillaObject *>(widget);
358 return reinterpret_cast<ScintillaGTK *>(scio->pscin);
361 ScintillaGTK::ScintillaGTK(_ScintillaObject *sci_) :
362 adjustmentv(0), adjustmenth(0),
363 scrollBarWidth(30), scrollBarHeight(30),
364 capturedMouse(false), dragWasDropped(false),
365 lastKey(0), rectangularSelectionModifier(SCMOD_CTRL), parentClass(0),
366 im_context(NULL),
367 lastWheelMouseDirection(0),
368 wheelMouseIntensity(0),
369 rgnUpdate(0) {
370 sci = sci_;
371 wMain = GTK_WIDGET(sci);
373 #if PLAT_GTK_WIN32
374 rectangularSelectionModifier = SCMOD_ALT;
375 #else
376 rectangularSelectionModifier = SCMOD_CTRL;
377 #endif
379 #if PLAT_GTK_WIN32
380 // There does not seem to be a real standard for indicating that the clipboard
381 // contains a rectangular selection, so copy Developer Studio.
382 cfColumnSelect = static_cast<CLIPFORMAT>(
383 ::RegisterClipboardFormat("MSDEVColumnSelect"));
385 // Get intellimouse parameters when running on win32; otherwise use
386 // reasonable default
387 #ifndef SPI_GETWHEELSCROLLLINES
388 #define SPI_GETWHEELSCROLLLINES 104
389 #endif
390 ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &linesPerScroll, 0);
391 #else
392 linesPerScroll = 4;
393 #endif
394 lastWheelMouseTime.tv_sec = 0;
395 lastWheelMouseTime.tv_usec = 0;
397 Initialise();
400 ScintillaGTK::~ScintillaGTK() {
401 g_idle_remove_by_data(this);
404 void ScintillaGTK::RealizeThis(GtkWidget *widget) {
405 //Platform::DebugPrintf("ScintillaGTK::realize this\n");
406 #if GTK_CHECK_VERSION(2,20,0)
407 gtk_widget_set_realized(widget, TRUE);
408 #else
409 GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
410 #endif
411 GdkWindowAttr attrs;
412 attrs.window_type = GDK_WINDOW_CHILD;
413 GtkAllocation allocation;
414 #if GTK_CHECK_VERSION(3,0,0)
415 gtk_widget_get_allocation(widget, &allocation);
416 #else
417 allocation = widget->allocation;
418 #endif
419 attrs.x = allocation.x;
420 attrs.y = allocation.y;
421 attrs.width = allocation.width;
422 attrs.height = allocation.height;
423 attrs.wclass = GDK_INPUT_OUTPUT;
424 attrs.visual = gtk_widget_get_visual(widget);
425 #if !GTK_CHECK_VERSION(3,0,0)
426 attrs.colormap = gtk_widget_get_colormap(widget);
427 #endif
428 attrs.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK;
429 GdkCursor *cursor = gdk_cursor_new(GDK_XTERM);
430 attrs.cursor = cursor;
431 #if GTK_CHECK_VERSION(3,0,0)
432 gtk_widget_set_window(widget, gdk_window_new(gtk_widget_get_parent_window(widget), &attrs,
433 GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_CURSOR));
434 gdk_window_set_user_data(gtk_widget_get_window(widget), widget);
435 gdk_window_set_background(gtk_widget_get_window(widget),
436 &(gtk_widget_get_style(widget)->bg[GTK_STATE_NORMAL]));
437 gdk_window_show(gtk_widget_get_window(widget));
438 gdk_cursor_unref(cursor);
439 // Deprecated: should chain up to parent class' "realize" implementation
440 gtk_widget_style_attach(widget);
441 #else
442 widget->window = gdk_window_new(gtk_widget_get_parent_window(widget), &attrs,
443 GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_CURSOR);
444 gdk_window_set_user_data(widget->window, widget);
445 gdk_window_set_background(widget->window, &widget->style->bg[GTK_STATE_NORMAL]);
446 gdk_window_show(widget->window);
447 gdk_cursor_unref(cursor);
448 widget->style = gtk_style_attach(widget->style, widget->window);
449 #endif
450 wPreedit = gtk_window_new(GTK_WINDOW_POPUP);
451 wPreeditDraw = gtk_drawing_area_new();
452 GtkWidget *predrw = PWidget(wPreeditDraw); // No code inside the G_OBJECT macro
453 #if !GTK_CHECK_VERSION(3,0,0)
454 g_signal_connect(G_OBJECT(predrw), "expose_event",
455 G_CALLBACK(ExposePreedit), this);
456 #endif
457 gtk_container_add(GTK_CONTAINER(PWidget(wPreedit)), predrw);
458 gtk_widget_realize(PWidget(wPreedit));
459 gtk_widget_realize(predrw);
460 gtk_widget_show(predrw);
462 im_context = gtk_im_multicontext_new();
463 g_signal_connect(G_OBJECT(im_context), "commit",
464 G_CALLBACK(Commit), this);
465 g_signal_connect(G_OBJECT(im_context), "preedit_changed",
466 G_CALLBACK(PreeditChanged), this);
467 gtk_im_context_set_client_window(im_context, WindowFromWidget(widget));
468 GtkWidget *widtxt = PWidget(wText); // // No code inside the G_OBJECT macro
469 g_signal_connect_after(G_OBJECT(widtxt), "style_set",
470 G_CALLBACK(ScintillaGTK::StyleSetText), NULL);
471 g_signal_connect_after(G_OBJECT(widtxt), "realize",
472 G_CALLBACK(ScintillaGTK::RealizeText), NULL);
473 gtk_widget_realize(widtxt);
474 gtk_widget_realize(PWidget(scrollbarv));
475 gtk_widget_realize(PWidget(scrollbarh));
477 cursor = gdk_cursor_new(GDK_XTERM);
478 gdk_window_set_cursor(PWindow(wText), cursor);
479 gdk_cursor_unref(cursor);
481 cursor = gdk_cursor_new(GDK_LEFT_PTR);
482 gdk_window_set_cursor(PWindow(scrollbarv), cursor);
483 gdk_cursor_unref(cursor);
485 cursor = gdk_cursor_new(GDK_LEFT_PTR);
486 gdk_window_set_cursor(PWindow(scrollbarh), cursor);
487 gdk_cursor_unref(cursor);
489 gtk_selection_add_targets(widget, GDK_SELECTION_PRIMARY,
490 clipboardCopyTargets, nClipboardCopyTargets);
491 #ifndef USE_GTK_CLIPBOARD
492 gtk_selection_add_targets(widget, atomClipboard,
493 clipboardPasteTargets, nClipboardPasteTargets);
494 #endif
497 void ScintillaGTK::Realize(GtkWidget *widget) {
498 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
499 sciThis->RealizeThis(widget);
502 void ScintillaGTK::UnRealizeThis(GtkWidget *widget) {
503 try {
504 gtk_selection_clear_targets(widget, GDK_SELECTION_PRIMARY);
505 #ifndef USE_GTK_CLIPBOARD
506 gtk_selection_clear_targets(widget, atomClipboard);
507 #endif
509 if (IS_WIDGET_MAPPED(widget)) {
510 gtk_widget_unmap(widget);
512 #if GTK_CHECK_VERSION(2,20,0)
513 gtk_widget_set_realized(widget, FALSE);
514 #else
515 GTK_WIDGET_UNSET_FLAGS(widget, GTK_REALIZED);
516 #endif
517 gtk_widget_unrealize(PWidget(wText));
518 gtk_widget_unrealize(PWidget(scrollbarv));
519 gtk_widget_unrealize(PWidget(scrollbarh));
520 gtk_widget_unrealize(PWidget(wPreedit));
521 gtk_widget_unrealize(PWidget(wPreeditDraw));
522 g_object_unref(im_context);
523 im_context = NULL;
524 if (GTK_WIDGET_CLASS(parentClass)->unrealize)
525 GTK_WIDGET_CLASS(parentClass)->unrealize(widget);
527 Finalise();
528 } catch (...) {
529 errorStatus = SC_STATUS_FAILURE;
533 void ScintillaGTK::UnRealize(GtkWidget *widget) {
534 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
535 sciThis->UnRealizeThis(widget);
538 static void MapWidget(GtkWidget *widget) {
539 if (widget &&
540 IS_WIDGET_VISIBLE(widget) &&
541 !IS_WIDGET_MAPPED(widget)) {
542 gtk_widget_map(widget);
546 void ScintillaGTK::MapThis() {
547 try {
548 //Platform::DebugPrintf("ScintillaGTK::map this\n");
549 #if GTK_CHECK_VERSION(2,20,0)
550 gtk_widget_set_mapped(PWidget(wMain), TRUE);
551 #else
552 GTK_WIDGET_SET_FLAGS(PWidget(wMain), GTK_MAPPED);
553 #endif
554 MapWidget(PWidget(wText));
555 MapWidget(PWidget(scrollbarh));
556 MapWidget(PWidget(scrollbarv));
557 wMain.SetCursor(Window::cursorArrow);
558 scrollbarv.SetCursor(Window::cursorArrow);
559 scrollbarh.SetCursor(Window::cursorArrow);
560 ChangeSize();
561 gdk_window_show(PWindow(wMain));
562 } catch (...) {
563 errorStatus = SC_STATUS_FAILURE;
567 void ScintillaGTK::Map(GtkWidget *widget) {
568 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
569 sciThis->MapThis();
572 void ScintillaGTK::UnMapThis() {
573 try {
574 //Platform::DebugPrintf("ScintillaGTK::unmap this\n");
575 #if GTK_CHECK_VERSION(2,20,0)
576 gtk_widget_set_mapped(PWidget(wMain), FALSE);
577 #else
578 GTK_WIDGET_UNSET_FLAGS(PWidget(wMain), GTK_MAPPED);
579 #endif
580 DropGraphics();
581 gdk_window_hide(PWindow(wMain));
582 gtk_widget_unmap(PWidget(wText));
583 gtk_widget_unmap(PWidget(scrollbarh));
584 gtk_widget_unmap(PWidget(scrollbarv));
585 } catch (...) {
586 errorStatus = SC_STATUS_FAILURE;
590 void ScintillaGTK::UnMap(GtkWidget *widget) {
591 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
592 sciThis->UnMapThis();
595 void ScintillaGTK::ForAll(GtkCallback callback, gpointer callback_data) {
596 try {
597 (*callback) (PWidget(wText), callback_data);
598 (*callback) (PWidget(scrollbarv), callback_data);
599 (*callback) (PWidget(scrollbarh), callback_data);
600 } catch (...) {
601 errorStatus = SC_STATUS_FAILURE;
605 void ScintillaGTK::MainForAll(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data) {
606 ScintillaGTK *sciThis = ScintillaFromWidget((GtkWidget *)container);
608 if (callback != NULL && include_internals) {
609 sciThis->ForAll(callback, callback_data);
613 gint ScintillaGTK::FocusInThis(GtkWidget *widget) {
614 try {
615 SetFocusState(true);
616 if (im_context != NULL) {
617 gchar *str = NULL;
618 gint cursor_pos;
620 gtk_im_context_get_preedit_string(im_context, &str, NULL, &cursor_pos);
621 if (PWidget(wPreedit) != NULL) {
622 if (strlen(str) > 0) {
623 gtk_widget_show(PWidget(wPreedit));
624 } else {
625 gtk_widget_hide(PWidget(wPreedit));
628 g_free(str);
629 gtk_im_context_focus_in(im_context);
632 } catch (...) {
633 errorStatus = SC_STATUS_FAILURE;
635 return FALSE;
638 gint ScintillaGTK::FocusIn(GtkWidget *widget, GdkEventFocus * /*event*/) {
639 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
640 return sciThis->FocusInThis(widget);
643 gint ScintillaGTK::FocusOutThis(GtkWidget *widget) {
644 try {
645 SetFocusState(false);
647 if (PWidget(wPreedit) != NULL)
648 gtk_widget_hide(PWidget(wPreedit));
649 if (im_context != NULL)
650 gtk_im_context_focus_out(im_context);
652 } catch (...) {
653 errorStatus = SC_STATUS_FAILURE;
655 return FALSE;
658 gint ScintillaGTK::FocusOut(GtkWidget *widget, GdkEventFocus * /*event*/) {
659 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
660 return sciThis->FocusOutThis(widget);
663 void ScintillaGTK::SizeRequest(GtkWidget *widget, GtkRequisition *requisition) {
664 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
665 requisition->width = 1;
666 requisition->height = 1;
667 GtkRequisition child_requisition;
668 #if GTK_CHECK_VERSION(3,0,0)
669 gtk_widget_get_preferred_size(PWidget(sciThis->scrollbarh), NULL, &child_requisition);
670 gtk_widget_get_preferred_size(PWidget(sciThis->scrollbarv), NULL, &child_requisition);
671 #else
672 gtk_widget_size_request(PWidget(sciThis->scrollbarh), &child_requisition);
673 gtk_widget_size_request(PWidget(sciThis->scrollbarv), &child_requisition);
674 #endif
677 void ScintillaGTK::GetPreferredWidth(GtkWidget *widget, gint *minimalWidth, gint *naturalWidth) {
678 GtkRequisition requisition;
679 SizeRequest(widget, &requisition);
680 *minimalWidth = *naturalWidth = requisition.width;
683 void ScintillaGTK::GetPreferredHeight(GtkWidget *widget, gint *minimalHeight, gint *naturalHeight) {
684 GtkRequisition requisition;
685 SizeRequest(widget, &requisition);
686 *minimalHeight = *naturalHeight = requisition.height;
689 void ScintillaGTK::SizeAllocate(GtkWidget *widget, GtkAllocation *allocation) {
690 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
691 try {
692 #if GTK_CHECK_VERSION(2,20,0)
693 gtk_widget_set_allocation(widget, allocation);
694 #else
695 widget->allocation = *allocation;
696 #endif
697 if (IS_WIDGET_REALIZED(widget))
698 gdk_window_move_resize(WindowFromWidget(widget),
699 allocation->x,
700 allocation->y,
701 allocation->width,
702 allocation->height);
704 sciThis->Resize(allocation->width, allocation->height);
706 } catch (...) {
707 sciThis->errorStatus = SC_STATUS_FAILURE;
711 void ScintillaGTK::Initialise() {
712 //Platform::DebugPrintf("ScintillaGTK::Initialise\n");
713 parentClass = reinterpret_cast<GtkWidgetClass *>(
714 g_type_class_ref(gtk_container_get_type()));
716 #if GTK_CHECK_VERSION(2,20,0)
717 gtk_widget_set_can_focus(PWidget(wMain), TRUE);
718 gtk_widget_set_sensitive(PWidget(wMain), TRUE);
719 #else
720 GTK_WIDGET_SET_FLAGS(PWidget(wMain), GTK_CAN_FOCUS);
721 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(PWidget(wMain)), GTK_SENSITIVE);
722 #endif
723 gtk_widget_set_events(PWidget(wMain),
724 GDK_EXPOSURE_MASK
725 | GDK_STRUCTURE_MASK
726 | GDK_KEY_PRESS_MASK
727 | GDK_KEY_RELEASE_MASK
728 | GDK_FOCUS_CHANGE_MASK
729 | GDK_LEAVE_NOTIFY_MASK
730 | GDK_BUTTON_PRESS_MASK
731 | GDK_BUTTON_RELEASE_MASK
732 | GDK_POINTER_MOTION_MASK
733 | GDK_POINTER_MOTION_HINT_MASK);
735 wText = gtk_drawing_area_new();
736 gtk_widget_set_parent(PWidget(wText), PWidget(wMain));
737 GtkWidget *widtxt = PWidget(wText); // No code inside the G_OBJECT macro
738 gtk_widget_show(widtxt);
739 #if GTK_CHECK_VERSION(3,0,0)
740 g_signal_connect(G_OBJECT(widtxt), "draw",
741 G_CALLBACK(ScintillaGTK::DrawText), this);
742 #else
743 g_signal_connect(G_OBJECT(widtxt), "expose_event",
744 G_CALLBACK(ScintillaGTK::ExposeText), this);
745 #endif
746 gtk_widget_set_events(widtxt, GDK_EXPOSURE_MASK);
747 // Avoid background drawing flash
748 gtk_widget_set_double_buffered(widtxt, FALSE);
749 gtk_widget_set_size_request(widtxt, 100, 100);
750 adjustmentv = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 201.0, 1.0, 20.0, 20.0));
751 scrollbarv = gtk_vscrollbar_new(GTK_ADJUSTMENT(adjustmentv));
752 #if GTK_CHECK_VERSION(2,20,0)
753 gtk_widget_set_can_focus(PWidget(scrollbarv), FALSE);
754 #else
755 GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarv), GTK_CAN_FOCUS);
756 #endif
757 g_signal_connect(G_OBJECT(adjustmentv), "value_changed",
758 G_CALLBACK(ScrollSignal), this);
759 gtk_widget_set_parent(PWidget(scrollbarv), PWidget(wMain));
760 gtk_widget_show(PWidget(scrollbarv));
762 adjustmenth = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 101.0, 1.0, 20.0, 20.0));
763 scrollbarh = gtk_hscrollbar_new(GTK_ADJUSTMENT(adjustmenth));
764 #if GTK_CHECK_VERSION(2,20,0)
765 gtk_widget_set_can_focus(PWidget(scrollbarh), FALSE);
766 #else
767 GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarh), GTK_CAN_FOCUS);
768 #endif
769 g_signal_connect(G_OBJECT(adjustmenth), "value_changed",
770 G_CALLBACK(ScrollHSignal), this);
771 gtk_widget_set_parent(PWidget(scrollbarh), PWidget(wMain));
772 gtk_widget_show(PWidget(scrollbarh));
774 gtk_widget_grab_focus(PWidget(wMain));
776 gtk_drag_dest_set(GTK_WIDGET(PWidget(wMain)),
777 GTK_DEST_DEFAULT_ALL, clipboardPasteTargets, nClipboardPasteTargets,
778 static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE));
780 // Set caret period based on GTK settings
781 gboolean blinkOn = false;
782 if (g_object_class_find_property(G_OBJECT_GET_CLASS(
783 G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink")) {
784 g_object_get(G_OBJECT(
785 gtk_settings_get_default()), "gtk-cursor-blink", &blinkOn, NULL);
787 if (blinkOn &&
788 g_object_class_find_property(G_OBJECT_GET_CLASS(
789 G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink-time")) {
790 gint value;
791 g_object_get(G_OBJECT(
792 gtk_settings_get_default()), "gtk-cursor-blink-time", &value, NULL);
793 caret.period = gint(value / 1.75);
794 } else {
795 caret.period = 0;
798 SetTicking(true);
801 void ScintillaGTK::Finalise() {
802 SetTicking(false);
803 ScintillaBase::Finalise();
806 void ScintillaGTK::DisplayCursor(Window::Cursor c) {
807 if (cursorMode == SC_CURSORNORMAL)
808 wText.SetCursor(c);
809 else
810 wText.SetCursor(static_cast<Window::Cursor>(cursorMode));
813 bool ScintillaGTK::DragThreshold(Point ptStart, Point ptNow) {
814 return gtk_drag_check_threshold(GTK_WIDGET(PWidget(wMain)),
815 ptStart.x, ptStart.y, ptNow.x, ptNow.y);
818 void ScintillaGTK::StartDrag() {
819 dragWasDropped = false;
820 inDragDrop = ddDragging;
821 GtkTargetList *tl = gtk_target_list_new(clipboardCopyTargets, nClipboardCopyTargets);
822 gtk_drag_begin(GTK_WIDGET(PWidget(wMain)),
824 static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE),
825 evbtn.button,
826 reinterpret_cast<GdkEvent *>(&evbtn));
829 static char *ConvertText(int *lenResult, char *s, size_t len, const char *charSetDest,
830 const char *charSetSource, bool transliterations, bool silent=false) {
831 // s is not const because of different versions of iconv disagreeing about const
832 *lenResult = 0;
833 char *destForm = 0;
834 Converter conv(charSetDest, charSetSource, transliterations);
835 if (conv) {
836 destForm = new char[len*3+1];
837 char *pin = s;
838 size_t inLeft = len;
839 char *pout = destForm;
840 size_t outLeft = len*3+1;
841 size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
842 if (conversions == ((size_t)(-1))) {
843 if (!silent)
844 fprintf(stderr, "iconv %s->%s failed for %s\n",
845 charSetSource, charSetDest, static_cast<char *>(s));
846 delete []destForm;
847 destForm = 0;
848 } else {
849 //fprintf(stderr, "iconv OK %s %d\n", destForm, pout - destForm);
850 *pout = '\0';
851 *lenResult = pout - destForm;
853 } else {
854 fprintf(stderr, "Can not iconv %s %s\n", charSetDest, charSetSource);
856 if (!destForm) {
857 destForm = new char[1];
858 destForm[0] = '\0';
859 *lenResult = 0;
861 return destForm;
864 // Returns the target converted to UTF8.
865 // Return the length in bytes.
866 int ScintillaGTK::TargetAsUTF8(char *text) {
867 int targetLength = targetEnd - targetStart;
868 if (IsUnicodeMode()) {
869 if (text) {
870 pdoc->GetCharRange(text, targetStart, targetLength);
872 } else {
873 // Need to convert
874 const char *charSetBuffer = CharacterSetID();
875 if (*charSetBuffer) {
876 //~ fprintf(stderr, "AsUTF8 %s %d %0d-%0d\n", charSetBuffer, targetLength, targetStart, targetEnd);
877 char *s = new char[targetLength];
878 if (s) {
879 pdoc->GetCharRange(s, targetStart, targetLength);
880 //~ fprintf(stderr, " \"%s\"\n", s);
881 if (text) {
882 char *tmputf = ConvertText(&targetLength, s, targetLength, "UTF-8", charSetBuffer, false);
883 memcpy(text, tmputf, targetLength);
884 delete []tmputf;
885 //~ fprintf(stderr, " \"%s\"\n", text);
887 delete []s;
889 } else {
890 if (text) {
891 pdoc->GetCharRange(text, targetStart, targetLength);
895 //~ fprintf(stderr, "Length = %d bytes\n", targetLength);
896 return targetLength;
899 // Translates a nul terminated UTF8 string into the document encoding.
900 // Return the length of the result in bytes.
901 int ScintillaGTK::EncodedFromUTF8(char *utf8, char *encoded) {
902 int inputLength = (lengthForEncode >= 0) ? lengthForEncode : strlen(utf8);
903 if (IsUnicodeMode()) {
904 if (encoded) {
905 memcpy(encoded, utf8, inputLength);
907 return inputLength;
908 } else {
909 // Need to convert
910 const char *charSetBuffer = CharacterSetID();
911 if (*charSetBuffer) {
912 int outLength = 0;
913 char *tmpEncoded = ConvertText(&outLength, utf8, inputLength, charSetBuffer, "UTF-8", true);
914 if (tmpEncoded) {
915 if (encoded) {
916 memcpy(encoded, tmpEncoded, outLength);
918 delete []tmpEncoded;
920 return outLength;
921 } else {
922 if (encoded) {
923 memcpy(encoded, utf8, inputLength);
925 return inputLength;
928 // Fail
929 return 0;
932 bool ScintillaGTK::ValidCodePage(int codePage) const {
933 return codePage == 0
934 || codePage == SC_CP_UTF8
935 || codePage == 932
936 || codePage == 936
937 || codePage == 949
938 || codePage == 950
939 || codePage == 1361;
942 sptr_t ScintillaGTK::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
943 try {
944 switch (iMessage) {
946 case SCI_GRABFOCUS:
947 gtk_widget_grab_focus(PWidget(wMain));
948 break;
950 case SCI_GETDIRECTFUNCTION:
951 return reinterpret_cast<sptr_t>(DirectFunction);
953 case SCI_GETDIRECTPOINTER:
954 return reinterpret_cast<sptr_t>(this);
956 #ifdef SCI_LEXER
957 case SCI_LOADLEXERLIBRARY:
958 LexerManager::GetInstance()->Load(reinterpret_cast<const char*>(lParam));
959 break;
960 #endif
961 case SCI_TARGETASUTF8:
962 return TargetAsUTF8(reinterpret_cast<char*>(lParam));
964 case SCI_ENCODEDFROMUTF8:
965 return EncodedFromUTF8(reinterpret_cast<char*>(wParam),
966 reinterpret_cast<char*>(lParam));
968 case SCI_SETRECTANGULARSELECTIONMODIFIER:
969 rectangularSelectionModifier = wParam;
970 break;
972 case SCI_GETRECTANGULARSELECTIONMODIFIER:
973 return rectangularSelectionModifier;
975 default:
976 return ScintillaBase::WndProc(iMessage, wParam, lParam);
978 } catch (std::bad_alloc&) {
979 errorStatus = SC_STATUS_BADALLOC;
980 } catch (...) {
981 errorStatus = SC_STATUS_FAILURE;
983 return 0l;
986 sptr_t ScintillaGTK::DefWndProc(unsigned int, uptr_t, sptr_t) {
987 return 0;
990 void ScintillaGTK::SetTicking(bool on) {
991 if (timer.ticking != on) {
992 timer.ticking = on;
993 if (timer.ticking) {
994 timer.tickerID = reinterpret_cast<TickerID>(g_timeout_add(timer.tickSize,
995 reinterpret_cast<GSourceFunc>(TimeOut), this));
996 } else {
997 g_source_remove(GPOINTER_TO_UINT(timer.tickerID));
1000 timer.ticksToWait = caret.period;
1003 bool ScintillaGTK::SetIdle(bool on) {
1004 if (on) {
1005 // Start idler, if it's not running.
1006 if (!idler.state) {
1007 idler.state = true;
1008 idler.idlerID = reinterpret_cast<IdlerID>(
1009 g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
1010 reinterpret_cast<GSourceFunc>(IdleCallback), this, NULL));
1012 } else {
1013 // Stop idler, if it's running
1014 if (idler.state) {
1015 idler.state = false;
1016 g_source_remove(GPOINTER_TO_UINT(idler.idlerID));
1019 return true;
1022 void ScintillaGTK::SetMouseCapture(bool on) {
1023 if (mouseDownCaptures) {
1024 if (on) {
1025 gtk_grab_add(GTK_WIDGET(PWidget(wMain)));
1026 } else {
1027 gtk_grab_remove(GTK_WIDGET(PWidget(wMain)));
1030 capturedMouse = on;
1033 bool ScintillaGTK::HaveMouseCapture() {
1034 return capturedMouse;
1037 #if GTK_CHECK_VERSION(3,0,0)
1039 // Is crcTest completely in crcContainer?
1040 static bool CRectContains(const cairo_rectangle_t &crcContainer, const cairo_rectangle_t &crcTest) {
1041 return
1042 (crcTest.x >= crcContainer.x) && ((crcTest.x + crcTest.width) <= (crcContainer.x + crcContainer.width)) &&
1043 (crcTest.y >= crcContainer.y) && ((crcTest.y + crcTest.height) <= (crcContainer.y + crcContainer.height));
1046 // Is crcTest completely in crcListContainer?
1047 // May incorrectly return false if complex shape
1048 static bool CRectListContains(const cairo_rectangle_list_t *crcListContainer, const cairo_rectangle_t &crcTest) {
1049 for (int r=0; r<crcListContainer->num_rectangles; r++) {
1050 if (CRectContains(crcListContainer->rectangles[r], crcTest))
1051 return true;
1053 return false;
1056 #endif
1058 bool ScintillaGTK::PaintContains(PRectangle rc) {
1059 // This allows optimization when a rectangle is completely in the update region.
1060 // It is OK to return false when too difficult to determine as that just performs extra drawing
1061 bool contains = true;
1062 if (paintState == painting) {
1063 if (!rcPaint.Contains(rc)) {
1064 contains = false;
1065 } else if (rgnUpdate) {
1066 #if GTK_CHECK_VERSION(3,0,0)
1067 cairo_rectangle_t grc = {rc.left, rc.top,
1068 rc.right - rc.left, rc.bottom - rc.top};
1069 contains = CRectListContains(rgnUpdate, grc);
1070 #else
1071 GdkRectangle grc = {rc.left, rc.top,
1072 rc.right - rc.left, rc.bottom - rc.top};
1073 if (gdk_region_rect_in(rgnUpdate, &grc) != GDK_OVERLAP_RECTANGLE_IN) {
1074 contains = false;
1076 #endif
1079 return contains;
1082 // Redraw all of text area. This paint will not be abandoned.
1083 void ScintillaGTK::FullPaint() {
1084 wText.InvalidateAll();
1087 PRectangle ScintillaGTK::GetClientRectangle() {
1088 PRectangle rc = wMain.GetClientPosition();
1089 if (verticalScrollBarVisible)
1090 rc.right -= scrollBarWidth;
1091 if (horizontalScrollBarVisible && (wrapState == eWrapNone))
1092 rc.bottom -= scrollBarHeight;
1093 // Move to origin
1094 rc.right -= rc.left;
1095 rc.bottom -= rc.top;
1096 rc.left = 0;
1097 rc.top = 0;
1098 return rc;
1101 // Synchronously paint a rectangle of the window.
1102 void ScintillaGTK::SyncPaint(PRectangle rc) {
1103 paintState = painting;
1104 rcPaint = rc;
1105 PRectangle rcClient = GetClientRectangle();
1106 paintingAllText = rcPaint.Contains(rcClient);
1107 if (PWindow(wText)) {
1108 Surface *sw = Surface::Allocate();
1109 if (sw) {
1110 #if GTK_CHECK_VERSION(3,0,0)
1111 cairo_t *cr = gdk_cairo_create(PWindow(wText));
1112 sw->Init(cr, PWidget(wText));
1113 #else
1114 sw->Init(PWindow(wText), PWidget(wText));
1115 #endif
1116 Paint(sw, rc);
1117 sw->Release();
1118 delete sw;
1119 #if GTK_CHECK_VERSION(3,0,0)
1120 cairo_destroy(cr);
1121 #endif
1124 if (paintState == paintAbandoned) {
1125 // Painting area was insufficient to cover new styling or brace highlight positions
1126 FullPaint();
1128 paintState = notPainting;
1131 void ScintillaGTK::ScrollText(int linesToMove) {
1132 int diff = vs.lineHeight * -linesToMove;
1133 //Platform::DebugPrintf("ScintillaGTK::ScrollText %d %d %0d,%0d %0d,%0d\n", linesToMove, diff,
1134 // rc.left, rc.top, rc.right, rc.bottom);
1135 GtkWidget *wi = PWidget(wText);
1137 gdk_window_scroll(WindowFromWidget(wi), 0, -diff);
1138 gdk_window_process_updates(WindowFromWidget(wi), FALSE);
1141 void ScintillaGTK::SetVerticalScrollPos() {
1142 DwellEnd(true);
1143 gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmentv), topLine);
1146 void ScintillaGTK::SetHorizontalScrollPos() {
1147 DwellEnd(true);
1148 gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmenth), xOffset / 2);
1151 bool ScintillaGTK::ModifyScrollBars(int nMax, int nPage) {
1152 bool modified = false;
1153 int pageScroll = LinesToScroll();
1155 #if GTK_CHECK_VERSION(3,0,0)
1156 if (gtk_adjustment_get_upper(adjustmentv) != (nMax + 1) ||
1157 gtk_adjustment_get_page_size(adjustmentv) != nPage ||
1158 gtk_adjustment_get_page_increment(adjustmentv) != pageScroll) {
1159 gtk_adjustment_set_upper(adjustmentv, nMax + 1);
1160 gtk_adjustment_set_page_size(adjustmentv, nPage);
1161 gtk_adjustment_set_page_increment(adjustmentv, pageScroll);
1162 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv));
1163 modified = true;
1165 #else
1166 if (GTK_ADJUSTMENT(adjustmentv)->upper != (nMax + 1) ||
1167 GTK_ADJUSTMENT(adjustmentv)->page_size != nPage ||
1168 GTK_ADJUSTMENT(adjustmentv)->page_increment != pageScroll) {
1169 GTK_ADJUSTMENT(adjustmentv)->upper = nMax + 1;
1170 GTK_ADJUSTMENT(adjustmentv)->page_size = nPage;
1171 GTK_ADJUSTMENT(adjustmentv)->page_increment = pageScroll;
1172 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv));
1173 modified = true;
1175 #endif
1177 PRectangle rcText = GetTextRectangle();
1178 int horizEndPreferred = scrollWidth;
1179 if (horizEndPreferred < 0)
1180 horizEndPreferred = 0;
1181 unsigned int pageWidth = rcText.Width();
1182 unsigned int pageIncrement = pageWidth / 3;
1183 unsigned int charWidth = vs.styles[STYLE_DEFAULT].aveCharWidth;
1184 #if GTK_CHECK_VERSION(3,0,0)
1185 if (gtk_adjustment_get_upper(adjustmenth) != horizEndPreferred ||
1186 gtk_adjustment_get_page_size(adjustmenth) != pageWidth ||
1187 gtk_adjustment_get_page_increment(adjustmenth) != pageIncrement ||
1188 gtk_adjustment_get_step_increment(adjustmenth) != charWidth) {
1189 gtk_adjustment_set_upper(adjustmenth, horizEndPreferred);
1190 gtk_adjustment_set_page_size(adjustmenth, pageWidth);
1191 gtk_adjustment_set_page_increment(adjustmenth, pageIncrement);
1192 gtk_adjustment_set_step_increment(adjustmenth, charWidth);
1193 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth));
1194 modified = true;
1196 #else
1197 if (GTK_ADJUSTMENT(adjustmenth)->upper != horizEndPreferred ||
1198 GTK_ADJUSTMENT(adjustmenth)->page_size != pageWidth ||
1199 GTK_ADJUSTMENT(adjustmenth)->page_increment != pageIncrement ||
1200 GTK_ADJUSTMENT(adjustmenth)->step_increment != charWidth) {
1201 GTK_ADJUSTMENT(adjustmenth)->upper = horizEndPreferred;
1202 GTK_ADJUSTMENT(adjustmenth)->step_increment = charWidth;
1203 GTK_ADJUSTMENT(adjustmenth)->page_size = pageWidth;
1204 GTK_ADJUSTMENT(adjustmenth)->page_increment = pageIncrement;
1205 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth));
1206 modified = true;
1208 #endif
1209 return modified;
1212 void ScintillaGTK::ReconfigureScrollBars() {
1213 PRectangle rc = wMain.GetClientPosition();
1214 Resize(rc.Width(), rc.Height());
1217 void ScintillaGTK::NotifyChange() {
1218 g_signal_emit(G_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL], 0,
1219 Platform::LongFromTwoShorts(GetCtrlID(), SCEN_CHANGE), PWidget(wMain));
1222 void ScintillaGTK::NotifyFocus(bool focus) {
1223 g_signal_emit(G_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL], 0,
1224 Platform::LongFromTwoShorts
1225 (GetCtrlID(), focus ? SCEN_SETFOCUS : SCEN_KILLFOCUS), PWidget(wMain));
1228 void ScintillaGTK::NotifyParent(SCNotification scn) {
1229 scn.nmhdr.hwndFrom = PWidget(wMain);
1230 scn.nmhdr.idFrom = GetCtrlID();
1231 g_signal_emit(G_OBJECT(sci), scintilla_signals[NOTIFY_SIGNAL], 0,
1232 GetCtrlID(), &scn);
1235 void ScintillaGTK::NotifyKey(int key, int modifiers) {
1236 SCNotification scn = {0};
1237 scn.nmhdr.code = SCN_KEY;
1238 scn.ch = key;
1239 scn.modifiers = modifiers;
1241 NotifyParent(scn);
1244 void ScintillaGTK::NotifyURIDropped(const char *list) {
1245 SCNotification scn = {0};
1246 scn.nmhdr.code = SCN_URIDROPPED;
1247 scn.text = list;
1249 NotifyParent(scn);
1252 const char *CharacterSetID(int characterSet);
1254 const char *ScintillaGTK::CharacterSetID() const {
1255 return ::CharacterSetID(vs.styles[STYLE_DEFAULT].characterSet);
1258 class CaseFolderUTF8 : public CaseFolderTable {
1259 public:
1260 CaseFolderUTF8() {
1261 StandardASCII();
1263 virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) {
1264 if ((lenMixed == 1) && (sizeFolded > 0)) {
1265 folded[0] = mapping[static_cast<unsigned char>(mixed[0])];
1266 return 1;
1267 } else {
1268 gchar *mapped = g_utf8_casefold(mixed, lenMixed);
1269 size_t lenMapped = strlen(mapped);
1270 if (lenMapped < sizeFolded) {
1271 memcpy(folded, mapped, lenMapped);
1272 } else {
1273 lenMapped = 0;
1275 g_free(mapped);
1276 return lenMapped;
1281 class CaseFolderDBCS : public CaseFolderTable {
1282 const char *charSet;
1283 public:
1284 CaseFolderDBCS(const char *charSet_) : charSet(charSet_) {
1285 StandardASCII();
1287 virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) {
1288 if ((lenMixed == 1) && (sizeFolded > 0)) {
1289 folded[0] = mapping[static_cast<unsigned char>(mixed[0])];
1290 return 1;
1291 } else if (*charSet) {
1292 int convertedLength = lenMixed;
1293 char *sUTF8 = ConvertText(&convertedLength, const_cast<char *>(mixed), lenMixed,
1294 "UTF-8", charSet, false);
1295 if (sUTF8) {
1296 gchar *mapped = g_utf8_casefold(sUTF8, strlen(sUTF8));
1297 size_t lenMapped = strlen(mapped);
1298 if (lenMapped < sizeFolded) {
1299 memcpy(folded, mapped, lenMapped);
1300 } else {
1301 folded[0] = '\0';
1302 lenMapped = 1;
1304 g_free(mapped);
1305 delete []sUTF8;
1306 return lenMapped;
1309 // Something failed so return a single NUL byte
1310 folded[0] = '\0';
1311 return 1;
1315 CaseFolder *ScintillaGTK::CaseFolderForEncoding() {
1316 if (pdoc->dbcsCodePage == SC_CP_UTF8) {
1317 return new CaseFolderUTF8();
1318 } else {
1319 const char *charSetBuffer = CharacterSetID();
1320 if (charSetBuffer) {
1321 if (pdoc->dbcsCodePage == 0) {
1322 CaseFolderTable *pcf = new CaseFolderTable();
1323 pcf->StandardASCII();
1324 // Only for single byte encodings
1325 for (int i=0x80; i<0x100; i++) {
1326 char sCharacter[2] = "A";
1327 sCharacter[0] = i;
1328 int convertedLength = 1;
1329 const char *sUTF8 = ConvertText(&convertedLength, sCharacter, 1,
1330 "UTF-8", charSetBuffer, false);
1331 if (sUTF8) {
1332 gchar *mapped = g_utf8_casefold(sUTF8, strlen(sUTF8));
1333 if (mapped) {
1334 int mappedLength = strlen(mapped);
1335 const char *mappedBack = ConvertText(&mappedLength, mapped,
1336 mappedLength, charSetBuffer, "UTF-8", false, true);
1337 if (mappedBack && (strlen(mappedBack) == 1) && (mappedBack[0] != sCharacter[0])) {
1338 pcf->SetTranslation(sCharacter[0], mappedBack[0]);
1340 delete []mappedBack;
1341 g_free(mapped);
1344 delete []sUTF8;
1346 return pcf;
1347 } else {
1348 return new CaseFolderDBCS(charSetBuffer);
1351 return 0;
1355 std::string ScintillaGTK::CaseMapString(const std::string &s, int caseMapping) {
1356 if (s.size() == 0)
1357 return std::string();
1359 if (caseMapping == cmSame)
1360 return s;
1362 const char *needsFree1 = 0; // Must be freed with delete []
1363 const char *charSetBuffer = CharacterSetID();
1364 const char *sUTF8 = s.c_str();
1365 int rangeBytes = s.size();
1367 int convertedLength = rangeBytes;
1368 // Change text to UTF-8
1369 if (!IsUnicodeMode()) {
1370 // Need to convert
1371 if (*charSetBuffer) {
1372 sUTF8 = ConvertText(&convertedLength, const_cast<char *>(s.c_str()), rangeBytes,
1373 "UTF-8", charSetBuffer, false);
1374 needsFree1 = sUTF8;
1377 gchar *mapped; // Must be freed with g_free
1378 if (caseMapping == cmUpper) {
1379 mapped = g_utf8_strup(sUTF8, convertedLength);
1380 } else {
1381 mapped = g_utf8_strdown(sUTF8, convertedLength);
1383 int mappedLength = strlen(mapped);
1384 char *mappedBack = mapped;
1386 char *needsFree2 = 0; // Must be freed with delete []
1387 if (!IsUnicodeMode()) {
1388 if (*charSetBuffer) {
1389 mappedBack = ConvertText(&mappedLength, mapped, mappedLength, charSetBuffer, "UTF-8", false);
1390 needsFree2 = mappedBack;
1394 std::string ret(mappedBack, mappedLength);
1395 g_free(mapped);
1396 delete []needsFree1;
1397 delete []needsFree2;
1398 return ret;
1401 int ScintillaGTK::KeyDefault(int key, int modifiers) {
1402 if (!(modifiers & SCI_CTRL) && !(modifiers & SCI_ALT)) {
1403 if (key < 256) {
1404 NotifyKey(key, modifiers);
1405 return 0;
1406 } else {
1407 // Pass up to container in case it is an accelerator
1408 NotifyKey(key, modifiers);
1409 return 0;
1411 } else {
1412 // Pass up to container in case it is an accelerator
1413 NotifyKey(key, modifiers);
1414 return 0;
1416 //Platform::DebugPrintf("SK-key: %d %x %x\n",key, modifiers);
1419 void ScintillaGTK::CopyToClipboard(const SelectionText &selectedText) {
1420 #ifndef USE_GTK_CLIPBOARD
1421 copyText.Copy(selectedText);
1422 gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)),
1423 atomClipboard,
1424 GDK_CURRENT_TIME);
1425 #else
1426 SelectionText *clipText = new SelectionText();
1427 clipText->Copy(selectedText);
1428 StoreOnClipboard(clipText);
1429 #endif
1432 void ScintillaGTK::Copy() {
1433 if (!sel.Empty()) {
1434 #ifndef USE_GTK_CLIPBOARD
1435 CopySelectionRange(&copyText);
1436 gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)),
1437 atomClipboard,
1438 GDK_CURRENT_TIME);
1439 #else
1440 SelectionText *clipText = new SelectionText();
1441 CopySelectionRange(clipText);
1442 StoreOnClipboard(clipText);
1443 #endif
1444 #if PLAT_GTK_WIN32
1445 if (sel.IsRectangular()) {
1446 ::OpenClipboard(NULL);
1447 ::SetClipboardData(cfColumnSelect, 0);
1448 ::CloseClipboard();
1450 #endif
1454 void ScintillaGTK::Paste() {
1455 atomSought = atomUTF8;
1456 gtk_selection_convert(GTK_WIDGET(PWidget(wMain)),
1457 atomClipboard, atomSought, GDK_CURRENT_TIME);
1460 void ScintillaGTK::CreateCallTipWindow(PRectangle rc) {
1461 if (!ct.wCallTip.Created()) {
1462 ct.wCallTip = gtk_window_new(GTK_WINDOW_POPUP);
1463 ct.wDraw = gtk_drawing_area_new();
1464 GtkWidget *widcdrw = PWidget(ct.wDraw); // // No code inside the G_OBJECT macro
1465 gtk_container_add(GTK_CONTAINER(PWidget(ct.wCallTip)), widcdrw);
1466 #if GTK_CHECK_VERSION(3,0,0)
1467 g_signal_connect(G_OBJECT(widcdrw), "draw",
1468 G_CALLBACK(ScintillaGTK::DrawCT), &ct);
1469 #else
1470 g_signal_connect(G_OBJECT(widcdrw), "expose_event",
1471 G_CALLBACK(ScintillaGTK::ExposeCT), &ct);
1472 #endif
1473 g_signal_connect(G_OBJECT(widcdrw), "button_press_event",
1474 G_CALLBACK(ScintillaGTK::PressCT), static_cast<void *>(this));
1475 gtk_widget_set_events(widcdrw,
1476 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
1478 gtk_widget_set_size_request(PWidget(ct.wDraw), rc.Width(), rc.Height());
1479 ct.wDraw.Show();
1480 if (PWindow(ct.wCallTip)) {
1481 gdk_window_resize(PWindow(ct.wCallTip), rc.Width(), rc.Height());
1485 void ScintillaGTK::AddToPopUp(const char *label, int cmd, bool enabled) {
1486 GtkWidget *menuItem;
1487 if (label[0])
1488 menuItem = gtk_menu_item_new_with_label(label);
1489 else
1490 menuItem = gtk_separator_menu_item_new();
1491 gtk_menu_shell_append(GTK_MENU_SHELL(popup.GetID()), menuItem);
1492 g_object_set_data(G_OBJECT(menuItem), "CmdNum", reinterpret_cast<void *>(cmd));
1493 g_signal_connect(G_OBJECT(menuItem),"activate", G_CALLBACK(PopUpCB), this);
1495 if (cmd) {
1496 if (menuItem)
1497 gtk_widget_set_sensitive(menuItem, enabled);
1501 bool ScintillaGTK::OwnPrimarySelection() {
1502 return ((gdk_selection_owner_get(GDK_SELECTION_PRIMARY)
1503 == PWindow(wMain)) &&
1504 (PWindow(wMain) != NULL));
1507 void ScintillaGTK::ClaimSelection() {
1508 // X Windows has a 'primary selection' as well as the clipboard.
1509 // Whenever the user selects some text, we become the primary selection
1510 if (!sel.Empty() && IS_WIDGET_REALIZED(GTK_WIDGET(PWidget(wMain)))) {
1511 primarySelection = true;
1512 gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)),
1513 GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
1514 primary.Free();
1515 } else if (OwnPrimarySelection()) {
1516 primarySelection = true;
1517 if (primary.s == NULL)
1518 gtk_selection_owner_set(NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
1519 } else {
1520 primarySelection = false;
1521 primary.Free();
1525 #if GTK_CHECK_VERSION(3,0,0)
1526 static const guchar *DataOfGSD(GtkSelectionData *sd) { return gtk_selection_data_get_data(sd); }
1527 static gint LengthOfGSD(GtkSelectionData *sd) { return gtk_selection_data_get_length(sd); }
1528 static GdkAtom TypeOfGSD(GtkSelectionData *sd) { return gtk_selection_data_get_data_type(sd); }
1529 static GdkAtom SelectionOfGSD(GtkSelectionData *sd) { return gtk_selection_data_get_selection(sd); }
1530 #else
1531 static const guchar *DataOfGSD(GtkSelectionData *sd) { return sd->data; }
1532 static gint LengthOfGSD(GtkSelectionData *sd) { return sd->length; }
1533 static GdkAtom TypeOfGSD(GtkSelectionData *sd) { return sd->type; }
1534 static GdkAtom SelectionOfGSD(GtkSelectionData *sd) { return sd->selection; }
1535 #endif
1537 // Detect rectangular text, convert line ends to current mode, convert from or to UTF-8
1538 void ScintillaGTK::GetGtkSelectionText(GtkSelectionData *selectionData, SelectionText &selText) {
1539 const char *data = reinterpret_cast<const char *>(DataOfGSD(selectionData));
1540 int len = LengthOfGSD(selectionData);
1541 GdkAtom selectionTypeData = TypeOfGSD(selectionData);
1543 // Return empty string if selection is not a string
1544 if ((selectionTypeData != GDK_TARGET_STRING) && (selectionTypeData != atomUTF8)) {
1545 char *empty = new char[1];
1546 empty[0] = '\0';
1547 selText.Set(empty, 0, SC_CP_UTF8, 0, false, false);
1548 return;
1551 // Check for "\n\0" ending to string indicating that selection is rectangular
1552 bool isRectangular;
1553 #if PLAT_GTK_WIN32
1554 isRectangular = ::IsClipboardFormatAvailable(cfColumnSelect) != 0;
1555 #else
1556 isRectangular = ((len > 2) && (data[len - 1] == 0 && data[len - 2] == '\n'));
1557 if (isRectangular)
1558 len--; // Forget the extra '\0'
1559 #endif
1561 char *dest;
1562 if (selectionTypeData == GDK_TARGET_STRING) {
1563 dest = Document::TransformLineEnds(&len, data, len, pdoc->eolMode);
1564 if (IsUnicodeMode()) {
1565 // Unknown encoding so assume in Latin1
1566 char *destPrevious = dest;
1567 dest = UTF8FromLatin1(dest, len);
1568 selText.Set(dest, len, SC_CP_UTF8, 0, selText.rectangular, false);
1569 delete []destPrevious;
1570 } else {
1571 // Assume buffer is in same encoding as selection
1572 selText.Set(dest, len, pdoc->dbcsCodePage,
1573 vs.styles[STYLE_DEFAULT].characterSet, isRectangular, false);
1575 } else { // UTF-8
1576 dest = Document::TransformLineEnds(&len, data, len, pdoc->eolMode);
1577 selText.Set(dest, len, SC_CP_UTF8, 0, isRectangular, false);
1578 const char *charSetBuffer = CharacterSetID();
1579 if (!IsUnicodeMode() && *charSetBuffer) {
1580 // Convert to locale
1581 dest = ConvertText(&len, selText.s, selText.len, charSetBuffer, "UTF-8", true);
1582 selText.Set(dest, len, pdoc->dbcsCodePage,
1583 vs.styles[STYLE_DEFAULT].characterSet, selText.rectangular, false);
1588 void ScintillaGTK::ReceivedSelection(GtkSelectionData *selection_data) {
1589 try {
1590 if ((SelectionOfGSD(selection_data) == atomClipboard) ||
1591 (SelectionOfGSD(selection_data) == GDK_SELECTION_PRIMARY)) {
1592 if ((atomSought == atomUTF8) && (LengthOfGSD(selection_data) <= 0)) {
1593 atomSought = atomString;
1594 gtk_selection_convert(GTK_WIDGET(PWidget(wMain)),
1595 SelectionOfGSD(selection_data), atomSought, GDK_CURRENT_TIME);
1596 } else if ((LengthOfGSD(selection_data) > 0) &&
1597 ((TypeOfGSD(selection_data) == GDK_TARGET_STRING) || (TypeOfGSD(selection_data) == atomUTF8))) {
1598 SelectionText selText;
1599 GetGtkSelectionText(selection_data, selText);
1601 UndoGroup ug(pdoc);
1602 if (SelectionOfGSD(selection_data) != GDK_SELECTION_PRIMARY) {
1603 ClearSelection(multiPasteMode == SC_MULTIPASTE_EACH);
1605 SelectionPosition selStart = sel.IsRectangular() ?
1606 sel.Rectangular().Start() :
1607 sel.Range(sel.Main()).Start();
1609 if (selText.rectangular) {
1610 PasteRectangular(selStart, selText.s, selText.len);
1611 } else {
1612 InsertPaste(selStart, selText.s, selText.len);
1614 EnsureCaretVisible();
1617 // else fprintf(stderr, "Target non string %d %d\n", (int)(selection_data->type),
1618 // (int)(atomUTF8));
1619 Redraw();
1620 } catch (...) {
1621 errorStatus = SC_STATUS_FAILURE;
1625 void ScintillaGTK::ReceivedDrop(GtkSelectionData *selection_data) {
1626 dragWasDropped = true;
1627 if (TypeOfGSD(selection_data) == atomUriList || TypeOfGSD(selection_data) == atomDROPFILES_DND) {
1628 char *ptr = new char[LengthOfGSD(selection_data) + 1];
1629 ptr[LengthOfGSD(selection_data)] = '\0';
1630 memcpy(ptr, DataOfGSD(selection_data), LengthOfGSD(selection_data));
1631 NotifyURIDropped(ptr);
1632 delete []ptr;
1633 } else if ((TypeOfGSD(selection_data) == GDK_TARGET_STRING) || (TypeOfGSD(selection_data) == atomUTF8)) {
1634 if (TypeOfGSD(selection_data) > 0) {
1635 SelectionText selText;
1636 GetGtkSelectionText(selection_data, selText);
1637 DropAt(posDrop, selText.s, false, selText.rectangular);
1639 } else if (LengthOfGSD(selection_data) > 0) {
1640 //~ fprintf(stderr, "ReceivedDrop other %p\n", static_cast<void *>(selection_data->type));
1642 Redraw();
1647 void ScintillaGTK::GetSelection(GtkSelectionData *selection_data, guint info, SelectionText *text) {
1648 #if PLAT_GTK_WIN32
1649 // GDK on Win32 expands any \n into \r\n, so make a copy of
1650 // the clip text now with newlines converted to \n. Use { } to hide symbols
1651 // from code below
1652 SelectionText *newline_normalized = NULL;
1654 int tmpstr_len;
1655 char *tmpstr = Document::TransformLineEnds(&tmpstr_len, text->s, text->len, SC_EOL_LF);
1656 newline_normalized = new SelectionText();
1657 newline_normalized->Set(tmpstr, tmpstr_len, SC_CP_UTF8, 0, text->rectangular, false);
1658 text = newline_normalized;
1660 #endif
1662 // Convert text to utf8 if it isn't already
1663 SelectionText *converted = 0;
1664 if ((text->codePage != SC_CP_UTF8) && (info == TARGET_UTF8_STRING)) {
1665 const char *charSet = ::CharacterSetID(text->characterSet);
1666 if (*charSet) {
1667 int new_len;
1668 char* tmputf = ConvertText(&new_len, text->s, text->len, "UTF-8", charSet, false);
1669 converted = new SelectionText();
1670 converted->Set(tmputf, new_len, SC_CP_UTF8, 0, text->rectangular, false);
1671 text = converted;
1675 // Here is a somewhat evil kludge.
1676 // As I can not work out how to store data on the clipboard in multiple formats
1677 // and need some way to mark the clipping as being stream or rectangular,
1678 // the terminating \0 is included in the length for rectangular clippings.
1679 // All other tested aplications behave benignly by ignoring the \0.
1680 // The #if is here because on Windows cfColumnSelect clip entry is used
1681 // instead as standard indicator of rectangularness (so no need to kludge)
1682 const char *textData = text->s ? text->s : "";
1683 int len = strlen(textData);
1684 #if PLAT_GTK_WIN32 == 0
1685 if (text->rectangular)
1686 len++;
1687 #endif
1689 if (info == TARGET_UTF8_STRING) {
1690 gtk_selection_data_set_text(selection_data, textData, len);
1691 } else {
1692 gtk_selection_data_set(selection_data,
1693 static_cast<GdkAtom>(GDK_SELECTION_TYPE_STRING),
1694 8, reinterpret_cast<const unsigned char *>(textData), len);
1696 delete converted;
1698 #if PLAT_GTK_WIN32
1699 delete newline_normalized;
1700 #endif
1703 #ifdef USE_GTK_CLIPBOARD
1704 void ScintillaGTK::StoreOnClipboard(SelectionText *clipText) {
1705 GtkClipboard *clipBoard =
1706 gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain)), atomClipboard);
1707 if (clipBoard == NULL) // Occurs if widget isn't in a toplevel
1708 return;
1710 if (gtk_clipboard_set_with_data(clipBoard, clipboardCopyTargets, nClipboardCopyTargets,
1711 ClipboardGetSelection, ClipboardClearSelection, clipText)) {
1712 gtk_clipboard_set_can_store(clipBoard, clipboardCopyTargets, nClipboardCopyTargets);
1716 void ScintillaGTK::ClipboardGetSelection(GtkClipboard *, GtkSelectionData *selection_data, guint info, void *data) {
1717 GetSelection(selection_data, info, static_cast<SelectionText*>(data));
1720 void ScintillaGTK::ClipboardClearSelection(GtkClipboard *, void *data) {
1721 SelectionText *obj = static_cast<SelectionText*>(data);
1722 delete obj;
1724 #endif
1726 void ScintillaGTK::UnclaimSelection(GdkEventSelection *selection_event) {
1727 try {
1728 //Platform::DebugPrintf("UnclaimSelection\n");
1729 if (selection_event->selection == GDK_SELECTION_PRIMARY) {
1730 //Platform::DebugPrintf("UnclaimPrimarySelection\n");
1731 if (!OwnPrimarySelection()) {
1732 primary.Free();
1733 primarySelection = false;
1734 FullPaint();
1737 } catch (...) {
1738 errorStatus = SC_STATUS_FAILURE;
1742 void ScintillaGTK::Resize(int width, int height) {
1743 //Platform::DebugPrintf("Resize %d %d\n", width, height);
1744 //printf("Resize %d %d\n", width, height);
1746 // Not always needed, but some themes can have different sizes of scrollbars
1747 #if GTK_CHECK_VERSION(3,0,0)
1748 GtkRequisition requisition;
1749 gtk_widget_get_requisition(PWidget(scrollbarv), &requisition);
1750 scrollBarWidth = requisition.width;
1751 gtk_widget_get_requisition(PWidget(scrollbarh), &requisition);
1752 scrollBarHeight = requisition.height;
1753 #else
1754 scrollBarWidth = GTK_WIDGET(PWidget(scrollbarv))->requisition.width;
1755 scrollBarHeight = GTK_WIDGET(PWidget(scrollbarh))->requisition.height;
1756 #endif
1758 // These allocations should never produce negative sizes as they would wrap around to huge
1759 // unsigned numbers inside GTK+ causing warnings.
1760 bool showSBHorizontal = horizontalScrollBarVisible && (wrapState == eWrapNone);
1761 int horizontalScrollBarHeight = scrollBarHeight;
1762 if (!showSBHorizontal)
1763 horizontalScrollBarHeight = 0;
1765 GtkAllocation alloc;
1766 if (showSBHorizontal) {
1767 gtk_widget_show(GTK_WIDGET(PWidget(scrollbarh)));
1768 alloc.x = 0;
1769 alloc.y = height - scrollBarHeight;
1770 alloc.width = Platform::Maximum(1, width - scrollBarWidth);
1771 alloc.height = horizontalScrollBarHeight;
1772 gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarh)), &alloc);
1773 } else {
1774 gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarh)));
1777 if (verticalScrollBarVisible) {
1778 gtk_widget_show(GTK_WIDGET(PWidget(scrollbarv)));
1779 alloc.x = width - scrollBarWidth;
1780 alloc.y = 0;
1781 alloc.width = scrollBarWidth;
1782 alloc.height = Platform::Maximum(1, height - scrollBarHeight);
1783 if (!showSBHorizontal)
1784 alloc.height += scrollBarWidth-1;
1785 gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarv)), &alloc);
1786 } else {
1787 gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarv)));
1789 if (IS_WIDGET_MAPPED(PWidget(wMain))) {
1790 ChangeSize();
1793 alloc.x = 0;
1794 alloc.y = 0;
1795 alloc.width = Platform::Maximum(1, width - scrollBarWidth);
1796 alloc.height = Platform::Maximum(1, height - scrollBarHeight);
1797 if (!showSBHorizontal)
1798 alloc.height += scrollBarHeight;
1799 if (!verticalScrollBarVisible)
1800 alloc.width += scrollBarWidth;
1801 gtk_widget_size_allocate(GTK_WIDGET(PWidget(wText)), &alloc);
1804 static void SetAdjustmentValue(GtkAdjustment *object, int value) {
1805 GtkAdjustment *adjustment = GTK_ADJUSTMENT(object);
1806 #if GTK_CHECK_VERSION(3,0,0)
1807 int maxValue = static_cast<int>(
1808 gtk_adjustment_get_upper(adjustment) - gtk_adjustment_get_page_size(adjustment));
1809 #else
1810 int maxValue = static_cast<int>(
1811 adjustment->upper - adjustment->page_size);
1812 #endif
1814 if (value > maxValue)
1815 value = maxValue;
1816 if (value < 0)
1817 value = 0;
1818 gtk_adjustment_set_value(adjustment, value);
1821 static int modifierTranslated(int sciModifier) {
1822 switch (sciModifier) {
1823 case SCMOD_SHIFT:
1824 return GDK_SHIFT_MASK;
1825 case SCMOD_CTRL:
1826 return GDK_CONTROL_MASK;
1827 case SCMOD_ALT:
1828 return GDK_MOD1_MASK;
1829 case SCMOD_SUPER:
1830 return GDK_MOD4_MASK;
1831 default:
1832 return 0;
1836 gint ScintillaGTK::PressThis(GdkEventButton *event) {
1837 try {
1838 //Platform::DebugPrintf("Press %x time=%d state = %x button = %x\n",this,event->time, event->state, event->button);
1839 // Do not use GTK+ double click events as Scintilla has its own double click detection
1840 if (event->type != GDK_BUTTON_PRESS)
1841 return FALSE;
1843 evbtn = *event;
1844 Point pt;
1845 pt.x = int(event->x);
1846 pt.y = int(event->y);
1847 PRectangle rcClient = GetClientRectangle();
1848 //Platform::DebugPrintf("Press %0d,%0d in %0d,%0d %0d,%0d\n",
1849 // pt.x, pt.y, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1850 if ((pt.x > rcClient.right) || (pt.y > rcClient.bottom)) {
1851 Platform::DebugPrintf("Bad location\n");
1852 return FALSE;
1855 bool ctrl = (event->state & GDK_CONTROL_MASK) != 0;
1857 gtk_widget_grab_focus(PWidget(wMain));
1858 if (event->button == 1) {
1859 // On X, instead of sending literal modifiers use the user specified
1860 // modifier, defaulting to control instead of alt.
1861 // This is because most X window managers grab alt + click for moving
1862 ButtonDown(pt, event->time,
1863 (event->state & GDK_SHIFT_MASK) != 0,
1864 (event->state & GDK_CONTROL_MASK) != 0,
1865 (event->state & modifierTranslated(rectangularSelectionModifier)) != 0);
1866 } else if (event->button == 2) {
1867 // Grab the primary selection if it exists
1868 SelectionPosition pos = SPositionFromLocation(pt, false, false, UserVirtualSpace());
1869 if (OwnPrimarySelection() && primary.s == NULL)
1870 CopySelectionRange(&primary);
1872 sel.Clear();
1873 SetSelection(pos, pos);
1874 atomSought = atomUTF8;
1875 gtk_selection_convert(GTK_WIDGET(PWidget(wMain)), GDK_SELECTION_PRIMARY,
1876 atomSought, event->time);
1877 } else if (event->button == 3) {
1878 if (!PointInSelection(pt))
1879 SetEmptySelection(PositionFromLocation(pt));
1880 if (displayPopupMenu) {
1881 // PopUp menu
1882 // Convert to screen
1883 int ox = 0;
1884 int oy = 0;
1885 gdk_window_get_origin(PWindow(wMain), &ox, &oy);
1886 ContextMenu(Point(pt.x + ox, pt.y + oy));
1887 } else {
1888 return FALSE;
1890 } else if (event->button == 4) {
1891 // Wheel scrolling up (only GTK 1.x does it this way)
1892 if (ctrl)
1893 SetAdjustmentValue(adjustmenth, (xOffset / 2) - 6);
1894 else
1895 SetAdjustmentValue(adjustmentv, topLine - 3);
1896 } else if (event->button == 5) {
1897 // Wheel scrolling down (only GTK 1.x does it this way)
1898 if (ctrl)
1899 SetAdjustmentValue(adjustmenth, (xOffset / 2) + 6);
1900 else
1901 SetAdjustmentValue(adjustmentv, topLine + 3);
1903 } catch (...) {
1904 errorStatus = SC_STATUS_FAILURE;
1906 return TRUE;
1909 gint ScintillaGTK::Press(GtkWidget *widget, GdkEventButton *event) {
1910 if (event->window != WindowFromWidget(widget))
1911 return FALSE;
1912 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
1913 return sciThis->PressThis(event);
1916 gint ScintillaGTK::MouseRelease(GtkWidget *widget, GdkEventButton *event) {
1917 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
1918 try {
1919 //Platform::DebugPrintf("Release %x %d %d\n",sciThis,event->time,event->state);
1920 if (!sciThis->HaveMouseCapture())
1921 return FALSE;
1922 if (event->button == 1) {
1923 Point pt;
1924 pt.x = int(event->x);
1925 pt.y = int(event->y);
1926 //Platform::DebugPrintf("Up %x %x %d %d %d\n",
1927 // sciThis,event->window,event->time, pt.x, pt.y);
1928 if (event->window != PWindow(sciThis->wMain))
1929 // If mouse released on scroll bar then the position is relative to the
1930 // scrollbar, not the drawing window so just repeat the most recent point.
1931 pt = sciThis->ptMouseLast;
1932 sciThis->ButtonUp(pt, event->time, (event->state & 4) != 0);
1934 } catch (...) {
1935 sciThis->errorStatus = SC_STATUS_FAILURE;
1937 return FALSE;
1940 // win32gtk and GTK >= 2 use SCROLL_* events instead of passing the
1941 // button4/5/6/7 events to the GTK app
1942 gint ScintillaGTK::ScrollEvent(GtkWidget *widget,
1943 GdkEventScroll *event) {
1944 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
1945 try {
1947 if (widget == NULL || event == NULL)
1948 return FALSE;
1950 // Compute amount and direction to scroll (even tho on win32 there is
1951 // intensity of scrolling info in the native message, gtk doesn't
1952 // support this so we simulate similarly adaptive scrolling)
1953 // Note that this is disabled on OS X (Darwin) where the X11 server already has
1954 // and adaptive scrolling algorithm that fights with this one
1955 int cLineScroll;
1956 #if defined(__MWERKS__) || defined(__APPLE_CPP__) || defined(__APPLE_CC__)
1957 cLineScroll = sciThis->linesPerScroll;
1958 if (cLineScroll == 0)
1959 cLineScroll = 4;
1960 sciThis->wheelMouseIntensity = cLineScroll;
1961 #else
1962 int timeDelta = 1000000;
1963 GTimeVal curTime;
1964 g_get_current_time(&curTime);
1965 if (curTime.tv_sec == sciThis->lastWheelMouseTime.tv_sec)
1966 timeDelta = curTime.tv_usec - sciThis->lastWheelMouseTime.tv_usec;
1967 else if (curTime.tv_sec == sciThis->lastWheelMouseTime.tv_sec + 1)
1968 timeDelta = 1000000 + (curTime.tv_usec - sciThis->lastWheelMouseTime.tv_usec);
1969 if ((event->direction == sciThis->lastWheelMouseDirection) && (timeDelta < 250000)) {
1970 if (sciThis->wheelMouseIntensity < 12)
1971 sciThis->wheelMouseIntensity++;
1972 cLineScroll = sciThis->wheelMouseIntensity;
1973 } else {
1974 cLineScroll = sciThis->linesPerScroll;
1975 if (cLineScroll == 0)
1976 cLineScroll = 4;
1977 sciThis->wheelMouseIntensity = cLineScroll;
1979 #endif
1980 if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_LEFT) {
1981 cLineScroll *= -1;
1983 g_get_current_time(&sciThis->lastWheelMouseTime);
1984 sciThis->lastWheelMouseDirection = event->direction;
1986 // Note: Unpatched versions of win32gtk don't set the 'state' value so
1987 // only regular scrolling is supported there. Also, unpatched win32gtk
1988 // issues spurious button 2 mouse events during wheeling, which can cause
1989 // problems (a patch for both was submitted by archaeopteryx.com on 13Jun2001)
1991 // Data zoom not supported
1992 if (event->state & GDK_SHIFT_MASK) {
1993 return FALSE;
1996 // Horizontal scrolling
1997 if (event->direction == GDK_SCROLL_LEFT || event->direction == GDK_SCROLL_RIGHT) {
1998 sciThis->HorizontalScrollTo(sciThis->xOffset + cLineScroll);
2000 // Text font size zoom
2001 } else if (event->state & GDK_CONTROL_MASK) {
2002 if (cLineScroll < 0) {
2003 sciThis->KeyCommand(SCI_ZOOMIN);
2004 } else {
2005 sciThis->KeyCommand(SCI_ZOOMOUT);
2008 // Regular scrolling
2009 } else {
2010 sciThis->ScrollTo(sciThis->topLine + cLineScroll);
2012 return TRUE;
2013 } catch (...) {
2014 sciThis->errorStatus = SC_STATUS_FAILURE;
2016 return FALSE;
2019 gint ScintillaGTK::Motion(GtkWidget *widget, GdkEventMotion *event) {
2020 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2021 try {
2022 //Platform::DebugPrintf("Motion %x %d\n",sciThis,event->time);
2023 if (event->window != WindowFromWidget(widget))
2024 return FALSE;
2025 int x = 0;
2026 int y = 0;
2027 GdkModifierType state;
2028 if (event->is_hint) {
2029 gdk_window_get_pointer(event->window, &x, &y, &state);
2030 } else {
2031 x = static_cast<int>(event->x);
2032 y = static_cast<int>(event->y);
2033 state = static_cast<GdkModifierType>(event->state);
2035 //Platform::DebugPrintf("Move %x %x %d %c %d %d\n",
2036 // sciThis,event->window,event->time,event->is_hint? 'h' :'.', x, y);
2037 Point pt(x, y);
2038 sciThis->ButtonMove(pt);
2039 } catch (...) {
2040 sciThis->errorStatus = SC_STATUS_FAILURE;
2042 return FALSE;
2045 // Map the keypad keys to their equivalent functions
2046 static int KeyTranslate(int keyIn) {
2047 switch (keyIn) {
2048 #if GTK_CHECK_VERSION(3,0,0)
2049 case GDK_KEY_ISO_Left_Tab:
2050 return SCK_TAB;
2051 case GDK_KEY_KP_Down:
2052 return SCK_DOWN;
2053 case GDK_KEY_KP_Up:
2054 return SCK_UP;
2055 case GDK_KEY_KP_Left:
2056 return SCK_LEFT;
2057 case GDK_KEY_KP_Right:
2058 return SCK_RIGHT;
2059 case GDK_KEY_KP_Home:
2060 return SCK_HOME;
2061 case GDK_KEY_KP_End:
2062 return SCK_END;
2063 case GDK_KEY_KP_Page_Up:
2064 return SCK_PRIOR;
2065 case GDK_KEY_KP_Page_Down:
2066 return SCK_NEXT;
2067 case GDK_KEY_KP_Delete:
2068 return SCK_DELETE;
2069 case GDK_KEY_KP_Insert:
2070 return SCK_INSERT;
2071 case GDK_KEY_KP_Enter:
2072 return SCK_RETURN;
2074 case GDK_KEY_Down:
2075 return SCK_DOWN;
2076 case GDK_KEY_Up:
2077 return SCK_UP;
2078 case GDK_KEY_Left:
2079 return SCK_LEFT;
2080 case GDK_KEY_Right:
2081 return SCK_RIGHT;
2082 case GDK_KEY_Home:
2083 return SCK_HOME;
2084 case GDK_KEY_End:
2085 return SCK_END;
2086 case GDK_KEY_Page_Up:
2087 return SCK_PRIOR;
2088 case GDK_KEY_Page_Down:
2089 return SCK_NEXT;
2090 case GDK_KEY_Delete:
2091 return SCK_DELETE;
2092 case GDK_KEY_Insert:
2093 return SCK_INSERT;
2094 case GDK_KEY_Escape:
2095 return SCK_ESCAPE;
2096 case GDK_KEY_BackSpace:
2097 return SCK_BACK;
2098 case GDK_KEY_Tab:
2099 return SCK_TAB;
2100 case GDK_KEY_Return:
2101 return SCK_RETURN;
2102 case GDK_KEY_KP_Add:
2103 return SCK_ADD;
2104 case GDK_KEY_KP_Subtract:
2105 return SCK_SUBTRACT;
2106 case GDK_KEY_KP_Divide:
2107 return SCK_DIVIDE;
2108 case GDK_KEY_Super_L:
2109 return SCK_WIN;
2110 case GDK_KEY_Super_R:
2111 return SCK_RWIN;
2112 case GDK_KEY_Menu:
2113 return SCK_MENU;
2115 #else
2117 case GDK_ISO_Left_Tab:
2118 return SCK_TAB;
2119 case GDK_KP_Down:
2120 return SCK_DOWN;
2121 case GDK_KP_Up:
2122 return SCK_UP;
2123 case GDK_KP_Left:
2124 return SCK_LEFT;
2125 case GDK_KP_Right:
2126 return SCK_RIGHT;
2127 case GDK_KP_Home:
2128 return SCK_HOME;
2129 case GDK_KP_End:
2130 return SCK_END;
2131 case GDK_KP_Page_Up:
2132 return SCK_PRIOR;
2133 case GDK_KP_Page_Down:
2134 return SCK_NEXT;
2135 case GDK_KP_Delete:
2136 return SCK_DELETE;
2137 case GDK_KP_Insert:
2138 return SCK_INSERT;
2139 case GDK_KP_Enter:
2140 return SCK_RETURN;
2142 case GDK_Down:
2143 return SCK_DOWN;
2144 case GDK_Up:
2145 return SCK_UP;
2146 case GDK_Left:
2147 return SCK_LEFT;
2148 case GDK_Right:
2149 return SCK_RIGHT;
2150 case GDK_Home:
2151 return SCK_HOME;
2152 case GDK_End:
2153 return SCK_END;
2154 case GDK_Page_Up:
2155 return SCK_PRIOR;
2156 case GDK_Page_Down:
2157 return SCK_NEXT;
2158 case GDK_Delete:
2159 return SCK_DELETE;
2160 case GDK_Insert:
2161 return SCK_INSERT;
2162 case GDK_Escape:
2163 return SCK_ESCAPE;
2164 case GDK_BackSpace:
2165 return SCK_BACK;
2166 case GDK_Tab:
2167 return SCK_TAB;
2168 case GDK_Return:
2169 return SCK_RETURN;
2170 case GDK_KP_Add:
2171 return SCK_ADD;
2172 case GDK_KP_Subtract:
2173 return SCK_SUBTRACT;
2174 case GDK_KP_Divide:
2175 return SCK_DIVIDE;
2176 case GDK_Super_L:
2177 return SCK_WIN;
2178 case GDK_Super_R:
2179 return SCK_RWIN;
2180 case GDK_Menu:
2181 return SCK_MENU;
2182 #endif
2183 default:
2184 return keyIn;
2188 gboolean ScintillaGTK::KeyThis(GdkEventKey *event) {
2189 try {
2190 //fprintf(stderr, "SC-key: %d %x [%s]\n",
2191 // event->keyval, event->state, (event->length > 0) ? event->string : "empty");
2192 if (gtk_im_context_filter_keypress(im_context, event)) {
2193 return 1;
2195 if (!event->keyval) {
2196 return true;
2199 bool shift = (event->state & GDK_SHIFT_MASK) != 0;
2200 bool ctrl = (event->state & GDK_CONTROL_MASK) != 0;
2201 bool alt = (event->state & GDK_MOD1_MASK) != 0;
2202 guint key = event->keyval;
2203 if (ctrl && (key < 128))
2204 key = toupper(key);
2205 #if GTK_CHECK_VERSION(3,0,0)
2206 else if (!ctrl && (key >= GDK_KEY_KP_Multiply && key <= GDK_KEY_KP_9))
2207 #else
2208 else if (!ctrl && (key >= GDK_KP_Multiply && key <= GDK_KP_9))
2209 #endif
2210 key &= 0x7F;
2211 // Hack for keys over 256 and below command keys but makes Hungarian work.
2212 // This will have to change for Unicode
2213 else if (key >= 0xFE00)
2214 key = KeyTranslate(key);
2216 bool consumed = false;
2217 bool added = KeyDown(key, shift, ctrl, alt, &consumed) != 0;
2218 if (!consumed)
2219 consumed = added;
2220 //fprintf(stderr, "SK-key: %d %x %x\n",event->keyval, event->state, consumed);
2221 if (event->keyval == 0xffffff && event->length > 0) {
2222 ClearSelection();
2223 if (pdoc->InsertCString(CurrentPosition(), event->string)) {
2224 MovePositionTo(CurrentPosition() + event->length);
2227 return consumed;
2228 } catch (...) {
2229 errorStatus = SC_STATUS_FAILURE;
2231 return FALSE;
2234 gboolean ScintillaGTK::KeyPress(GtkWidget *widget, GdkEventKey *event) {
2235 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2236 return sciThis->KeyThis(event);
2239 gboolean ScintillaGTK::KeyRelease(GtkWidget *, GdkEventKey * /*event*/) {
2240 //Platform::DebugPrintf("SC-keyrel: %d %x %3s\n",event->keyval, event->state, event->string);
2241 return FALSE;
2244 gboolean ScintillaGTK::ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose) {
2245 try {
2246 gchar *str;
2247 gint cursor_pos;
2248 PangoAttrList *attrs;
2250 gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos);
2251 PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str);
2252 pango_layout_set_attributes(layout, attrs);
2254 #ifndef USE_CAIRO
2255 GdkGC *gc = gdk_gc_new(widget->window);
2256 GdkColor color[2] = { {0, 0x0000, 0x0000, 0x0000},
2257 {0, 0xffff, 0xffff, 0xffff}
2259 gdk_colormap_alloc_color(gdk_colormap_get_system(), color, FALSE, TRUE);
2260 gdk_colormap_alloc_color(gdk_colormap_get_system(), color + 1, FALSE, TRUE);
2262 gdk_gc_set_foreground(gc, color + 1);
2263 gdk_draw_rectangle(widget->window, gc, TRUE, ose->area.x, ose->area.y,
2264 ose->area.width, ose->area.height);
2266 gdk_gc_set_foreground(gc, color);
2267 gdk_gc_set_background(gc, color + 1);
2268 gdk_draw_layout(widget->window, gc, 0, 0, layout);
2269 g_object_unref(gc);
2270 #endif
2271 g_free(str);
2272 pango_attr_list_unref(attrs);
2273 g_object_unref(layout);
2274 } catch (...) {
2275 errorStatus = SC_STATUS_FAILURE;
2277 return TRUE;
2280 gboolean ScintillaGTK::ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis) {
2281 return sciThis->ExposePreeditThis(widget, ose);
2284 void ScintillaGTK::CommitThis(char *utfVal) {
2285 try {
2286 //~ fprintf(stderr, "Commit '%s'\n", utfVal);
2287 if (IsUnicodeMode()) {
2288 AddCharUTF(utfVal, strlen(utfVal));
2289 } else {
2290 const char *source = CharacterSetID();
2291 if (*source) {
2292 Converter conv(source, "UTF-8", true);
2293 if (conv) {
2294 char localeVal[4] = "\0\0\0";
2295 char *pin = utfVal;
2296 size_t inLeft = strlen(utfVal);
2297 char *pout = localeVal;
2298 size_t outLeft = sizeof(localeVal);
2299 size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
2300 if (conversions != ((size_t)(-1))) {
2301 *pout = '\0';
2302 for (int i = 0; localeVal[i]; i++) {
2303 AddChar(localeVal[i]);
2305 } else {
2306 fprintf(stderr, "Conversion failed '%s'\n", utfVal);
2311 } catch (...) {
2312 errorStatus = SC_STATUS_FAILURE;
2316 void ScintillaGTK::Commit(GtkIMContext *, char *str, ScintillaGTK *sciThis) {
2317 sciThis->CommitThis(str);
2320 void ScintillaGTK::PreeditChangedThis() {
2321 try {
2322 gchar *str;
2323 PangoAttrList *attrs;
2324 gint cursor_pos;
2325 gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos);
2326 if (strlen(str) > 0) {
2327 PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str);
2328 pango_layout_set_attributes(layout, attrs);
2330 gint w, h;
2331 pango_layout_get_pixel_size(layout, &w, &h);
2332 g_object_unref(layout);
2334 gint x, y;
2335 gdk_window_get_origin(PWindow(wText), &x, &y);
2337 Point pt = PointMainCaret();
2338 if (pt.x < 0)
2339 pt.x = 0;
2340 if (pt.y < 0)
2341 pt.y = 0;
2343 gtk_window_move(GTK_WINDOW(PWidget(wPreedit)), x + pt.x, y + pt.y);
2344 gtk_window_resize(GTK_WINDOW(PWidget(wPreedit)), w, h);
2345 gtk_widget_show(PWidget(wPreedit));
2346 gtk_widget_queue_draw_area(PWidget(wPreeditDraw), 0, 0, w, h);
2347 } else {
2348 gtk_widget_hide(PWidget(wPreedit));
2350 g_free(str);
2351 pango_attr_list_unref(attrs);
2352 } catch (...) {
2353 errorStatus = SC_STATUS_FAILURE;
2357 void ScintillaGTK::PreeditChanged(GtkIMContext *, ScintillaGTK *sciThis) {
2358 sciThis->PreeditChangedThis();
2361 void ScintillaGTK::StyleSetText(GtkWidget *widget, GtkStyle *, void*) {
2362 RealizeText(widget, NULL);
2365 void ScintillaGTK::RealizeText(GtkWidget *widget, void*) {
2366 // Set NULL background to avoid automatic clearing so Scintilla responsible for all drawing
2367 if (WindowFromWidget(widget)) {
2368 #if GTK_CHECK_VERSION(3,0,0)
2369 gdk_window_set_background_pattern(WindowFromWidget(widget), NULL);
2370 #else
2371 gdk_window_set_back_pixmap(WindowFromWidget(widget), NULL, FALSE);
2372 #endif
2376 void ScintillaGTK::Destroy(GObject *object) {
2377 try {
2378 ScintillaObject *scio = reinterpret_cast<ScintillaObject *>(object);
2379 // This avoids a double destruction
2380 if (!scio->pscin)
2381 return;
2382 ScintillaGTK *sciThis = reinterpret_cast<ScintillaGTK *>(scio->pscin);
2383 //Platform::DebugPrintf("Destroying %x %x\n", sciThis, object);
2384 sciThis->Finalise();
2386 delete sciThis;
2387 scio->pscin = 0;
2388 } catch (...) {
2389 // Its dead so nowhere to save the status
2393 #if GTK_CHECK_VERSION(3,0,0)
2395 gboolean ScintillaGTK::DrawTextThis(cairo_t *cr) {
2396 try {
2397 paintState = painting;
2399 rcPaint = GetClientRectangle();
2401 PLATFORM_ASSERT(rgnUpdate == NULL);
2402 rgnUpdate = cairo_copy_clip_rectangle_list(cr);
2403 if (rgnUpdate && rgnUpdate->status != CAIRO_STATUS_SUCCESS) {
2404 // If not successful then ignore
2405 fprintf(stderr, "DrawTextThis failed to copy update region %d [%d]\n", rgnUpdate->status, rgnUpdate->num_rectangles);
2406 cairo_rectangle_list_destroy(rgnUpdate);
2407 rgnUpdate = 0;
2410 double x1, y1, x2, y2;
2411 cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
2412 rcPaint.left = x1;
2413 rcPaint.top = y1;
2414 rcPaint.right = x2;
2415 rcPaint.bottom = y2;
2416 PRectangle rcClient = GetClientRectangle();
2417 paintingAllText = rcPaint.Contains(rcClient);
2418 Surface *surfaceWindow = Surface::Allocate();
2419 if (surfaceWindow) {
2420 surfaceWindow->Init(cr, PWidget(wText));
2421 Paint(surfaceWindow, rcPaint);
2422 surfaceWindow->Release();
2423 delete surfaceWindow;
2425 if (paintState == paintAbandoned) {
2426 // Painting area was insufficient to cover new styling or brace highlight positions
2427 FullPaint();
2429 paintState = notPainting;
2431 if (rgnUpdate) {
2432 cairo_rectangle_list_destroy(rgnUpdate);
2434 rgnUpdate = 0;
2435 paintState = notPainting;
2436 } catch (...) {
2437 errorStatus = SC_STATUS_FAILURE;
2440 return FALSE;
2443 gboolean ScintillaGTK::DrawText(GtkWidget *, cairo_t *cr, ScintillaGTK *sciThis) {
2444 return sciThis->DrawTextThis(cr);
2447 gboolean ScintillaGTK::DrawThis(cairo_t *cr) {
2448 try {
2449 gtk_container_propagate_draw(
2450 GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarh), cr);
2451 gtk_container_propagate_draw(
2452 GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarv), cr);
2453 } catch (...) {
2454 errorStatus = SC_STATUS_FAILURE;
2456 return FALSE;
2459 gboolean ScintillaGTK::DrawMain(GtkWidget *widget, cairo_t *cr) {
2460 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2461 return sciThis->DrawThis(cr);
2464 #else
2466 gboolean ScintillaGTK::ExposeTextThis(GtkWidget * /*widget*/, GdkEventExpose *ose) {
2467 try {
2468 paintState = painting;
2470 rcPaint.left = ose->area.x;
2471 rcPaint.top = ose->area.y;
2472 rcPaint.right = ose->area.x + ose->area.width;
2473 rcPaint.bottom = ose->area.y + ose->area.height;
2475 PLATFORM_ASSERT(rgnUpdate == NULL);
2476 rgnUpdate = gdk_region_copy(ose->region);
2477 PRectangle rcClient = GetClientRectangle();
2478 paintingAllText = rcPaint.Contains(rcClient);
2479 Surface *surfaceWindow = Surface::Allocate();
2480 if (surfaceWindow) {
2481 surfaceWindow->Init(PWindow(wText), PWidget(wText));
2482 Paint(surfaceWindow, rcPaint);
2483 surfaceWindow->Release();
2484 delete surfaceWindow;
2486 if (paintState == paintAbandoned) {
2487 // Painting area was insufficient to cover new styling or brace highlight positions
2488 FullPaint();
2490 paintState = notPainting;
2492 if (rgnUpdate) {
2493 gdk_region_destroy(rgnUpdate);
2495 rgnUpdate = 0;
2496 } catch (...) {
2497 errorStatus = SC_STATUS_FAILURE;
2500 return FALSE;
2503 gboolean ScintillaGTK::ExposeText(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis) {
2504 return sciThis->ExposeTextThis(widget, ose);
2507 gboolean ScintillaGTK::ExposeMain(GtkWidget *widget, GdkEventExpose *ose) {
2508 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2509 //Platform::DebugPrintf("Expose Main %0d,%0d %0d,%0d\n",
2510 //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2511 return sciThis->Expose(widget, ose);
2514 gboolean ScintillaGTK::Expose(GtkWidget *, GdkEventExpose *ose) {
2515 try {
2516 //fprintf(stderr, "Expose %0d,%0d %0d,%0d\n",
2517 //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2519 // The text is painted in ExposeText
2520 gtk_container_propagate_expose(
2521 GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarh), ose);
2522 gtk_container_propagate_expose(
2523 GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarv), ose);
2525 } catch (...) {
2526 errorStatus = SC_STATUS_FAILURE;
2528 return FALSE;
2531 #endif
2533 void ScintillaGTK::ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) {
2534 try {
2535 #if GTK_CHECK_VERSION(3,0,0)
2536 sciThis->ScrollTo(static_cast<int>(gtk_adjustment_get_value(adj)), false);
2537 #else
2538 sciThis->ScrollTo(static_cast<int>(adj->value), false);
2539 #endif
2540 } catch (...) {
2541 sciThis->errorStatus = SC_STATUS_FAILURE;
2545 void ScintillaGTK::ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) {
2546 try {
2547 #if GTK_CHECK_VERSION(3,0,0)
2548 sciThis->HorizontalScrollTo(static_cast<int>(gtk_adjustment_get_value(adj) * 2));
2549 #else
2550 sciThis->HorizontalScrollTo(static_cast<int>(adj->value * 2));
2551 #endif
2552 } catch (...) {
2553 sciThis->errorStatus = SC_STATUS_FAILURE;
2557 void ScintillaGTK::SelectionReceived(GtkWidget *widget,
2558 GtkSelectionData *selection_data, guint) {
2559 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2560 //Platform::DebugPrintf("Selection received\n");
2561 sciThis->ReceivedSelection(selection_data);
2564 void ScintillaGTK::SelectionGet(GtkWidget *widget,
2565 GtkSelectionData *selection_data, guint info, guint) {
2566 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2567 try {
2568 //Platform::DebugPrintf("Selection get\n");
2569 if (SelectionOfGSD(selection_data) == GDK_SELECTION_PRIMARY) {
2570 if (sciThis->primary.s == NULL) {
2571 sciThis->CopySelectionRange(&sciThis->primary);
2573 sciThis->GetSelection(selection_data, info, &sciThis->primary);
2575 #ifndef USE_GTK_CLIPBOARD
2576 else {
2577 sciThis->GetSelection(selection_data, info, &sciThis->copyText);
2579 #endif
2580 } catch (...) {
2581 sciThis->errorStatus = SC_STATUS_FAILURE;
2585 gint ScintillaGTK::SelectionClear(GtkWidget *widget, GdkEventSelection *selection_event) {
2586 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2587 //Platform::DebugPrintf("Selection clear\n");
2588 sciThis->UnclaimSelection(selection_event);
2589 if (GTK_WIDGET_CLASS(sciThis->parentClass)->selection_clear_event) {
2590 return GTK_WIDGET_CLASS(sciThis->parentClass)->selection_clear_event(widget, selection_event);
2592 return TRUE;
2595 void ScintillaGTK::DragBegin(GtkWidget *, GdkDragContext *) {
2596 //Platform::DebugPrintf("DragBegin\n");
2599 gboolean ScintillaGTK::DragMotionThis(GdkDragContext *context,
2600 gint x, gint y, guint dragtime) {
2601 try {
2602 Point npt(x, y);
2603 SetDragPosition(SPositionFromLocation(npt, false, false, UserVirtualSpace()));
2604 #if GTK_CHECK_VERSION(3,0,0)
2605 GdkDragAction preferredAction = gdk_drag_context_get_suggested_action(context);
2606 GdkDragAction actions = gdk_drag_context_get_actions(context);
2607 #else
2608 GdkDragAction preferredAction = context->suggested_action;
2609 GdkDragAction actions = context->actions;
2610 #endif
2611 SelectionPosition pos = SPositionFromLocation(npt);
2612 if ((inDragDrop == ddDragging) && (PositionInSelection(pos.Position()))) {
2613 // Avoid dragging selection onto itself as that produces a move
2614 // with no real effect but which creates undo actions.
2615 preferredAction = static_cast<GdkDragAction>(0);
2616 } else if (actions == static_cast<GdkDragAction>
2617 (GDK_ACTION_COPY | GDK_ACTION_MOVE)) {
2618 preferredAction = GDK_ACTION_MOVE;
2620 gdk_drag_status(context, preferredAction, dragtime);
2621 } catch (...) {
2622 errorStatus = SC_STATUS_FAILURE;
2624 return FALSE;
2627 gboolean ScintillaGTK::DragMotion(GtkWidget *widget, GdkDragContext *context,
2628 gint x, gint y, guint dragtime) {
2629 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2630 return sciThis->DragMotionThis(context, x, y, dragtime);
2633 void ScintillaGTK::DragLeave(GtkWidget *widget, GdkDragContext * /*context*/, guint) {
2634 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2635 try {
2636 sciThis->SetDragPosition(SelectionPosition(invalidPosition));
2637 //Platform::DebugPrintf("DragLeave %x\n", sciThis);
2638 } catch (...) {
2639 sciThis->errorStatus = SC_STATUS_FAILURE;
2643 void ScintillaGTK::DragEnd(GtkWidget *widget, GdkDragContext * /*context*/) {
2644 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2645 try {
2646 // If drag did not result in drop here or elsewhere
2647 if (!sciThis->dragWasDropped)
2648 sciThis->SetEmptySelection(sciThis->posDrag);
2649 sciThis->SetDragPosition(SelectionPosition(invalidPosition));
2650 //Platform::DebugPrintf("DragEnd %x %d\n", sciThis, sciThis->dragWasDropped);
2651 sciThis->inDragDrop = ddNone;
2652 } catch (...) {
2653 sciThis->errorStatus = SC_STATUS_FAILURE;
2657 gboolean ScintillaGTK::Drop(GtkWidget *widget, GdkDragContext * /*context*/,
2658 gint, gint, guint) {
2659 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2660 try {
2661 //Platform::DebugPrintf("Drop %x\n", sciThis);
2662 sciThis->SetDragPosition(SelectionPosition(invalidPosition));
2663 } catch (...) {
2664 sciThis->errorStatus = SC_STATUS_FAILURE;
2666 return FALSE;
2669 void ScintillaGTK::DragDataReceived(GtkWidget *widget, GdkDragContext * /*context*/,
2670 gint, gint, GtkSelectionData *selection_data, guint /*info*/, guint) {
2671 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2672 try {
2673 sciThis->ReceivedDrop(selection_data);
2674 sciThis->SetDragPosition(SelectionPosition(invalidPosition));
2675 } catch (...) {
2676 sciThis->errorStatus = SC_STATUS_FAILURE;
2680 void ScintillaGTK::DragDataGet(GtkWidget *widget, GdkDragContext *context,
2681 GtkSelectionData *selection_data, guint info, guint) {
2682 ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2683 try {
2684 sciThis->dragWasDropped = true;
2685 if (!sciThis->sel.Empty()) {
2686 sciThis->GetSelection(selection_data, info, &sciThis->drag);
2688 #if GTK_CHECK_VERSION(3,0,0)
2689 GdkDragAction action = gdk_drag_context_get_selected_action(context);
2690 #else
2691 GdkDragAction action = context->action;
2692 #endif
2693 if (action == GDK_ACTION_MOVE) {
2694 for (size_t r=0; r<sciThis->sel.Count(); r++) {
2695 if (sciThis->posDrop >= sciThis->sel.Range(r).Start()) {
2696 if (sciThis->posDrop > sciThis->sel.Range(r).End()) {
2697 sciThis->posDrop.Add(-sciThis->sel.Range(r).Length());
2698 } else {
2699 sciThis->posDrop.Add(-SelectionRange(sciThis->posDrop, sciThis->sel.Range(r).Start()).Length());
2703 sciThis->ClearSelection();
2705 sciThis->SetDragPosition(SelectionPosition(invalidPosition));
2706 } catch (...) {
2707 sciThis->errorStatus = SC_STATUS_FAILURE;
2711 int ScintillaGTK::TimeOut(ScintillaGTK *sciThis) {
2712 sciThis->Tick();
2713 return 1;
2716 gboolean ScintillaGTK::IdleCallback(ScintillaGTK *sciThis) {
2717 // Idler will be automatically stopped, if there is nothing
2718 // to do while idle.
2719 gdk_threads_enter();
2720 bool ret = sciThis->Idle();
2721 if (ret == false) {
2722 // FIXME: This will remove the idler from GTK, we don't want to
2723 // remove it as it is removed automatically when this function
2724 // returns false (although, it should be harmless).
2725 sciThis->SetIdle(false);
2727 gdk_threads_leave();
2728 return ret;
2731 gboolean ScintillaGTK::StyleIdle(ScintillaGTK *sciThis) {
2732 gdk_threads_enter();
2733 sciThis->IdleStyling();
2734 gdk_threads_leave();
2735 // Idler will be automatically stopped
2736 return FALSE;
2739 void ScintillaGTK::QueueStyling(int upTo) {
2740 Editor::QueueStyling(upTo);
2741 if (!styleNeeded.active) {
2742 // Only allow one style needed to be queued
2743 styleNeeded.active = true;
2744 g_idle_add_full(G_PRIORITY_HIGH_IDLE,
2745 reinterpret_cast<GSourceFunc>(StyleIdle), this, NULL);
2749 void ScintillaGTK::PopUpCB(GtkMenuItem *menuItem, ScintillaGTK *sciThis) {
2750 guint action = (sptr_t)(g_object_get_data(G_OBJECT(menuItem), "CmdNum"));
2751 if (action) {
2752 sciThis->Command(action);
2756 gboolean ScintillaGTK::PressCT(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis) {
2757 try {
2758 if (event->window != WindowFromWidget(widget))
2759 return FALSE;
2760 if (event->type != GDK_BUTTON_PRESS)
2761 return FALSE;
2762 Point pt;
2763 pt.x = int(event->x);
2764 pt.y = int(event->y);
2765 sciThis->ct.MouseClick(pt);
2766 sciThis->CallTipClick();
2767 } catch (...) {
2769 return TRUE;
2772 #if GTK_CHECK_VERSION(3,0,0)
2774 gboolean ScintillaGTK::DrawCT(GtkWidget *widget, cairo_t *cr, CallTip *ctip) {
2775 try {
2776 Surface *surfaceWindow = Surface::Allocate();
2777 if (surfaceWindow) {
2778 surfaceWindow->Init(cr, widget);
2779 surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == ctip->codePage);
2780 surfaceWindow->SetDBCSMode(ctip->codePage);
2781 ctip->PaintCT(surfaceWindow);
2782 surfaceWindow->Release();
2783 delete surfaceWindow;
2785 } catch (...) {
2786 // No pointer back to Scintilla to save status
2788 return TRUE;
2791 #else
2793 gboolean ScintillaGTK::ExposeCT(GtkWidget *widget, GdkEventExpose * /*ose*/, CallTip *ctip) {
2794 try {
2795 Surface *surfaceWindow = Surface::Allocate();
2796 if (surfaceWindow) {
2797 surfaceWindow->Init(WindowFromWidget(widget), widget);
2798 surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == ctip->codePage);
2799 surfaceWindow->SetDBCSMode(ctip->codePage);
2800 ctip->PaintCT(surfaceWindow);
2801 surfaceWindow->Release();
2802 delete surfaceWindow;
2804 } catch (...) {
2805 // No pointer back to Scintilla to save status
2807 return TRUE;
2810 #endif
2812 sptr_t ScintillaGTK::DirectFunction(
2813 ScintillaGTK *sciThis, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
2814 return sciThis->WndProc(iMessage, wParam, lParam);
2817 sptr_t scintilla_send_message(ScintillaObject *sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
2818 ScintillaGTK *psci = reinterpret_cast<ScintillaGTK *>(sci->pscin);
2819 return psci->WndProc(iMessage, wParam, lParam);
2822 static void scintilla_class_init(ScintillaClass *klass);
2823 static void scintilla_init(ScintillaObject *sci);
2825 extern void Platform_Initialise();
2826 extern void Platform_Finalise();
2828 GType scintilla_get_type() {
2829 static GType scintilla_type = 0;
2830 try {
2832 if (!scintilla_type) {
2833 scintilla_type = g_type_from_name("Scintilla");
2834 if (!scintilla_type) {
2835 static GTypeInfo scintilla_info = {
2836 (guint16) sizeof (ScintillaClass),
2837 NULL, //(GBaseInitFunc)
2838 NULL, //(GBaseFinalizeFunc)
2839 (GClassInitFunc) scintilla_class_init,
2840 NULL, //(GClassFinalizeFunc)
2841 NULL, //gconstpointer data
2842 (guint16) sizeof (ScintillaObject),
2843 0, //n_preallocs
2844 (GInstanceInitFunc) scintilla_init,
2845 NULL //(GTypeValueTable*)
2848 scintilla_type = g_type_register_static(
2849 GTK_TYPE_CONTAINER, "Scintilla", &scintilla_info, (GTypeFlags) 0);
2853 } catch (...) {
2855 return scintilla_type;
2858 void ScintillaGTK::ClassInit(OBJECT_CLASS* object_class, GtkWidgetClass *widget_class, GtkContainerClass *container_class) {
2859 Platform_Initialise();
2860 #ifdef SCI_LEXER
2861 Scintilla_LinkLexers();
2862 #endif
2863 atomClipboard = gdk_atom_intern("CLIPBOARD", FALSE);
2864 atomUTF8 = gdk_atom_intern("UTF8_STRING", FALSE);
2865 atomString = GDK_SELECTION_TYPE_STRING;
2866 atomUriList = gdk_atom_intern("text/uri-list", FALSE);
2867 atomDROPFILES_DND = gdk_atom_intern("DROPFILES_DND", FALSE);
2869 // Define default signal handlers for the class: Could move more
2870 // of the signal handlers here (those that currently attached to wDraw
2871 // in Initialise() may require coordinate translation?)
2873 object_class->finalize = Destroy;
2874 #if GTK_CHECK_VERSION(3,0,0)
2875 widget_class->get_preferred_width = GetPreferredWidth;
2876 widget_class->get_preferred_height = GetPreferredHeight;
2877 #else
2878 widget_class->size_request = SizeRequest;
2879 #endif
2880 widget_class->size_allocate = SizeAllocate;
2881 #if GTK_CHECK_VERSION(3,0,0)
2882 widget_class->draw = DrawMain;
2883 #else
2884 widget_class->expose_event = ExposeMain;
2885 #endif
2886 widget_class->motion_notify_event = Motion;
2887 widget_class->button_press_event = Press;
2888 widget_class->button_release_event = MouseRelease;
2889 widget_class->scroll_event = ScrollEvent;
2890 widget_class->key_press_event = KeyPress;
2891 widget_class->key_release_event = KeyRelease;
2892 widget_class->focus_in_event = FocusIn;
2893 widget_class->focus_out_event = FocusOut;
2894 widget_class->selection_received = SelectionReceived;
2895 widget_class->selection_get = SelectionGet;
2896 widget_class->selection_clear_event = SelectionClear;
2898 widget_class->drag_data_received = DragDataReceived;
2899 widget_class->drag_motion = DragMotion;
2900 widget_class->drag_leave = DragLeave;
2901 widget_class->drag_end = DragEnd;
2902 widget_class->drag_drop = Drop;
2903 widget_class->drag_data_get = DragDataGet;
2905 widget_class->realize = Realize;
2906 widget_class->unrealize = UnRealize;
2907 widget_class->map = Map;
2908 widget_class->unmap = UnMap;
2910 container_class->forall = MainForAll;
2913 #define SIG_MARSHAL scintilla_marshal_NONE__INT_POINTER
2914 #define MARSHAL_ARGUMENTS G_TYPE_INT, G_TYPE_POINTER
2916 static void scintilla_class_init(ScintillaClass *klass) {
2917 try {
2918 OBJECT_CLASS *object_class = (OBJECT_CLASS*) klass;
2919 GtkWidgetClass *widget_class = (GtkWidgetClass*) klass;
2920 GtkContainerClass *container_class = (GtkContainerClass*) klass;
2922 GSignalFlags sigflags = GSignalFlags(G_SIGNAL_ACTION | G_SIGNAL_RUN_LAST);
2923 scintilla_signals[COMMAND_SIGNAL] = g_signal_new(
2924 "command",
2925 G_TYPE_FROM_CLASS(object_class),
2926 sigflags,
2927 G_STRUCT_OFFSET(ScintillaClass, command),
2928 NULL, //(GSignalAccumulator)
2929 NULL, //(gpointer)
2930 SIG_MARSHAL,
2931 G_TYPE_NONE,
2932 2, MARSHAL_ARGUMENTS);
2934 scintilla_signals[NOTIFY_SIGNAL] = g_signal_new(
2935 SCINTILLA_NOTIFY,
2936 G_TYPE_FROM_CLASS(object_class),
2937 sigflags,
2938 G_STRUCT_OFFSET(ScintillaClass, notify),
2939 NULL,
2940 NULL,
2941 SIG_MARSHAL,
2942 G_TYPE_NONE,
2943 2, MARSHAL_ARGUMENTS);
2945 klass->command = NULL;
2946 klass->notify = NULL;
2948 ScintillaGTK::ClassInit(object_class, widget_class, container_class);
2949 } catch (...) {
2953 static void scintilla_init(ScintillaObject *sci) {
2954 try {
2955 #if GTK_CHECK_VERSION(2,20,0)
2956 gtk_widget_set_can_focus(GTK_WIDGET(sci), TRUE);
2957 #else
2958 GTK_WIDGET_SET_FLAGS(sci, GTK_CAN_FOCUS);
2959 #endif
2960 sci->pscin = new ScintillaGTK(sci);
2961 } catch (...) {
2965 GtkWidget* scintilla_new() {
2966 return GTK_WIDGET(g_object_new(scintilla_get_type(), NULL));
2969 void scintilla_set_id(ScintillaObject *sci, uptr_t id) {
2970 ScintillaGTK *psci = reinterpret_cast<ScintillaGTK *>(sci->pscin);
2971 psci->ctrlID = id;
2974 void scintilla_release_resources(void) {
2975 try {
2976 Platform_Finalise();
2977 } catch (...) {