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