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