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.
17 #include <gdk/gdkkeysyms.h>
25 #include "Scintilla.h"
26 #include "ScintillaWidget.h"
30 #include "PropSetSimple.h"
35 #include "SplitVector.h"
36 #include "Partitioning.h"
37 #include "RunStyles.h"
38 #include "ContractionState.h"
39 #include "CellBuffer.h"
42 #include "Indicator.h"
44 #include "LineMarker.h"
46 #include "AutoComplete.h"
47 #include "ViewStyle.h"
48 #include "Decoration.h"
49 #include "CharClassify.h"
51 #include "Selection.h"
52 #include "PositionCache.h"
54 #include "ScintillaBase.h"
55 #include "UniConversion.h"
57 #include "gtk/gtksignal.h"
58 #include "gtk/gtkmarshal.h"
59 #include "scintilla-marshal.h"
64 #include "ExternalLexer.h"
67 #include "Converter.h"
70 // Constant conditional expressions are because of GTK+ headers
71 #pragma warning(disable: 4127)
72 // Ignore unreferenced local functions in GTK+ headers
73 #pragma warning(disable: 4505)
76 #if GTK_CHECK_VERSION(2,6,0)
77 #define USE_GTK_CLIPBOARD
80 #define OBJECT_CLASS GObjectClass
83 using namespace Scintilla
;
86 extern char *UTF8FromLatin1(const char *s
, int &len
);
88 class ScintillaGTK
: public ScintillaBase
{
89 _ScintillaObject
*sci
;
93 GtkObject
*adjustmentv
;
94 GtkObject
*adjustmenth
;
98 // Because clipboard access is asynchronous, copyText is created by Copy
99 #ifndef USE_GTK_CLIPBOARD
100 SelectionText copyText
;
103 SelectionText primary
;
105 GdkEventButton evbtn
;
109 int rectangularSelectionModifier
;
111 GtkWidgetClass
*parentClass
;
113 static GdkAtom atomClipboard
;
114 static GdkAtom atomUTF8
;
115 static GdkAtom atomString
;
116 static GdkAtom atomUriList
;
117 static GdkAtom atomDROPFILES_DND
;
121 CLIPFORMAT cfColumnSelect
;
126 GtkIMContext
*im_context
;
128 // Wheel mouse support
129 unsigned int linesPerScroll
;
130 GTimeVal lastWheelMouseTime
;
131 gint lastWheelMouseDirection
;
132 gint wheelMouseIntensity
;
134 GdkRegion
*rgnUpdate
;
136 // Private so ScintillaGTK objects can not be copied
137 ScintillaGTK(const ScintillaGTK
&);
138 ScintillaGTK
&operator=(const ScintillaGTK
&);
141 ScintillaGTK(_ScintillaObject
*sci_
);
142 virtual ~ScintillaGTK();
143 static void ClassInit(OBJECT_CLASS
* object_class
, GtkWidgetClass
*widget_class
, GtkContainerClass
*container_class
);
145 virtual void Initialise();
146 virtual void Finalise();
147 virtual void DisplayCursor(Window::Cursor c
);
148 virtual bool DragThreshold(Point ptStart
, Point ptNow
);
149 virtual void StartDrag();
150 int TargetAsUTF8(char *text
);
151 int EncodedFromUTF8(char *utf8
, char *encoded
);
152 virtual bool ValidCodePage(int codePage
) const;
153 public: // Public for scintilla_send_message
154 virtual sptr_t
WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
156 virtual sptr_t
DefWndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
157 virtual void SetTicking(bool on
);
158 virtual bool SetIdle(bool on
);
159 virtual void SetMouseCapture(bool on
);
160 virtual bool HaveMouseCapture();
161 virtual bool PaintContains(PRectangle rc
);
163 virtual PRectangle
GetClientRectangle();
164 void SyncPaint(PRectangle rc
);
165 virtual void ScrollText(int linesToMove
);
166 virtual void SetVerticalScrollPos();
167 virtual void SetHorizontalScrollPos();
168 virtual bool ModifyScrollBars(int nMax
, int nPage
);
169 void ReconfigureScrollBars();
170 virtual void NotifyChange();
171 virtual void NotifyFocus(bool focus
);
172 virtual void NotifyParent(SCNotification scn
);
173 void NotifyKey(int key
, int modifiers
);
174 void NotifyURIDropped(const char *list
);
175 const char *CharacterSetID() const;
176 virtual CaseFolder
*CaseFolderForEncoding();
177 virtual std::string
CaseMapString(const std::string
&s
, int caseMapping
);
178 virtual int KeyDefault(int key
, int modifiers
);
179 virtual void CopyToClipboard(const SelectionText
&selectedText
);
181 virtual void Paste();
182 virtual void CreateCallTipWindow(PRectangle rc
);
183 virtual void AddToPopUp(const char *label
, int cmd
= 0, bool enabled
= true);
184 bool OwnPrimarySelection();
185 virtual void ClaimSelection();
186 void GetGtkSelectionText(GtkSelectionData
*selectionData
, SelectionText
&selText
);
187 void ReceivedSelection(GtkSelectionData
*selection_data
);
188 void ReceivedDrop(GtkSelectionData
*selection_data
);
189 static void GetSelection(GtkSelectionData
*selection_data
, guint info
, SelectionText
*selected
);
190 #ifdef USE_GTK_CLIPBOARD
191 void StoreOnClipboard(SelectionText
*clipText
);
192 static void ClipboardGetSelection(GtkClipboard
* clip
, GtkSelectionData
*selection_data
, guint info
, void *data
);
193 static void ClipboardClearSelection(GtkClipboard
* clip
, void *data
);
196 void UnclaimSelection(GdkEventSelection
*selection_event
);
197 void Resize(int width
, int height
);
199 // Callback functions
200 void RealizeThis(GtkWidget
*widget
);
201 static void Realize(GtkWidget
*widget
);
202 void UnRealizeThis(GtkWidget
*widget
);
203 static void UnRealize(GtkWidget
*widget
);
205 static void Map(GtkWidget
*widget
);
207 static void UnMap(GtkWidget
*widget
);
208 static gint
CursorMoved(GtkWidget
*widget
, int xoffset
, int yoffset
, ScintillaGTK
*sciThis
);
209 gint
FocusInThis(GtkWidget
*widget
);
210 static gint
FocusIn(GtkWidget
*widget
, GdkEventFocus
*event
);
211 gint
FocusOutThis(GtkWidget
*widget
);
212 static gint
FocusOut(GtkWidget
*widget
, GdkEventFocus
*event
);
213 static void SizeRequest(GtkWidget
*widget
, GtkRequisition
*requisition
);
214 static void SizeAllocate(GtkWidget
*widget
, GtkAllocation
*allocation
);
215 gint
Expose(GtkWidget
*widget
, GdkEventExpose
*ose
);
216 static gint
ExposeMain(GtkWidget
*widget
, GdkEventExpose
*ose
);
217 static void Draw(GtkWidget
*widget
, GdkRectangle
*area
);
218 void ForAll(GtkCallback callback
, gpointer callback_data
);
219 static void MainForAll(GtkContainer
*container
, gboolean include_internals
, GtkCallback callback
, gpointer callback_data
);
221 static void ScrollSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
);
222 static void ScrollHSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
);
223 gint
PressThis(GdkEventButton
*event
);
224 static gint
Press(GtkWidget
*widget
, GdkEventButton
*event
);
225 static gint
MouseRelease(GtkWidget
*widget
, GdkEventButton
*event
);
226 static gint
ScrollEvent(GtkWidget
*widget
, GdkEventScroll
*event
);
227 static gint
Motion(GtkWidget
*widget
, GdkEventMotion
*event
);
228 gboolean
KeyThis(GdkEventKey
*event
);
229 static gboolean
KeyPress(GtkWidget
*widget
, GdkEventKey
*event
);
230 static gboolean
KeyRelease(GtkWidget
*widget
, GdkEventKey
*event
);
231 gboolean
ExposePreeditThis(GtkWidget
*widget
, GdkEventExpose
*ose
);
232 static gboolean
ExposePreedit(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
);
233 void CommitThis(char *str
);
234 static void Commit(GtkIMContext
*context
, char *str
, ScintillaGTK
*sciThis
);
235 void PreeditChangedThis();
236 static void PreeditChanged(GtkIMContext
*context
, ScintillaGTK
*sciThis
);
237 static gint
StyleSetText(GtkWidget
*widget
, GtkStyle
*previous
, void*);
238 static gint
RealizeText(GtkWidget
*widget
, void*);
239 static void Destroy(GObject
*object
);
240 static void SelectionReceived(GtkWidget
*widget
, GtkSelectionData
*selection_data
,
242 static void SelectionGet(GtkWidget
*widget
, GtkSelectionData
*selection_data
,
243 guint info
, guint time
);
244 static gint
SelectionClear(GtkWidget
*widget
, GdkEventSelection
*selection_event
);
245 static void DragBegin(GtkWidget
*widget
, GdkDragContext
*context
);
246 gboolean
DragMotionThis(GdkDragContext
*context
, gint x
, gint y
, guint dragtime
);
247 static gboolean
DragMotion(GtkWidget
*widget
, GdkDragContext
*context
,
248 gint x
, gint y
, guint dragtime
);
249 static void DragLeave(GtkWidget
*widget
, GdkDragContext
*context
,
251 static void DragEnd(GtkWidget
*widget
, GdkDragContext
*context
);
252 static gboolean
Drop(GtkWidget
*widget
, GdkDragContext
*context
,
253 gint x
, gint y
, guint time
);
254 static void DragDataReceived(GtkWidget
*widget
, GdkDragContext
*context
,
255 gint x
, gint y
, GtkSelectionData
*selection_data
, guint info
, guint time
);
256 static void DragDataGet(GtkWidget
*widget
, GdkDragContext
*context
,
257 GtkSelectionData
*selection_data
, guint info
, guint time
);
258 static gint
TimeOut(ScintillaGTK
*sciThis
);
259 static gboolean
IdleCallback(ScintillaGTK
*sciThis
);
260 static gboolean
StyleIdle(ScintillaGTK
*sciThis
);
261 virtual void QueueStyling(int upTo
);
262 static void PopUpCB(ScintillaGTK
*sciThis
, guint action
, GtkWidget
*widget
);
264 gint
ExposeTextThis(GtkWidget
*widget
, GdkEventExpose
*ose
);
265 static gint
ExposeText(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
);
267 static gint
ExposeCT(GtkWidget
*widget
, GdkEventExpose
*ose
, CallTip
*ct
);
268 static gint
PressCT(GtkWidget
*widget
, GdkEventButton
*event
, ScintillaGTK
*sciThis
);
270 static sptr_t
DirectFunction(ScintillaGTK
*sciThis
,
271 unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
280 static gint scintilla_signals
[LAST_SIGNAL
] = { 0 };
285 TARGET_COMPOUND_TEXT
,
290 GdkAtom
ScintillaGTK::atomClipboard
= 0;
291 GdkAtom
ScintillaGTK::atomUTF8
= 0;
292 GdkAtom
ScintillaGTK::atomString
= 0;
293 GdkAtom
ScintillaGTK::atomUriList
= 0;
294 GdkAtom
ScintillaGTK::atomDROPFILES_DND
= 0;
296 static const GtkTargetEntry clipboardCopyTargets
[] = {
297 { (gchar
*) "UTF8_STRING", 0, TARGET_UTF8_STRING
},
298 { (gchar
*) "STRING", 0, TARGET_STRING
},
300 static const gint nClipboardCopyTargets
= sizeof(clipboardCopyTargets
) / sizeof(clipboardCopyTargets
[0]);
302 static const GtkTargetEntry clipboardPasteTargets
[] = {
303 { (gchar
*) "text/uri-list", 0, TARGET_URI
},
304 { (gchar
*) "UTF8_STRING", 0, TARGET_UTF8_STRING
},
305 { (gchar
*) "STRING", 0, TARGET_STRING
},
307 static const gint nClipboardPasteTargets
= sizeof(clipboardPasteTargets
) / sizeof(clipboardPasteTargets
[0]);
309 static GtkWidget
*PWidget(Window
&w
) {
310 return reinterpret_cast<GtkWidget
*>(w
.GetID());
313 static ScintillaGTK
*ScintillaFromWidget(GtkWidget
*widget
) {
314 ScintillaObject
*scio
= reinterpret_cast<ScintillaObject
*>(widget
);
315 return reinterpret_cast<ScintillaGTK
*>(scio
->pscin
);
318 ScintillaGTK::ScintillaGTK(_ScintillaObject
*sci_
) :
319 adjustmentv(0), adjustmenth(0),
320 scrollBarWidth(30), scrollBarHeight(30),
321 capturedMouse(false), dragWasDropped(false),
322 lastKey(0), rectangularSelectionModifier(SCMOD_CTRL
), parentClass(0),
324 lastWheelMouseDirection(0),
325 wheelMouseIntensity(0),
328 wMain
= GTK_WIDGET(sci
);
331 rectangularSelectionModifier
= SCMOD_ALT
;
333 rectangularSelectionModifier
= SCMOD_CTRL
;
337 // There does not seem to be a real standard for indicating that the clipboard
338 // contains a rectangular selection, so copy Developer Studio.
339 cfColumnSelect
= static_cast<CLIPFORMAT
>(
340 ::RegisterClipboardFormat("MSDEVColumnSelect"));
342 // Get intellimouse parameters when running on win32; otherwise use
343 // reasonable default
344 #ifndef SPI_GETWHEELSCROLLLINES
345 #define SPI_GETWHEELSCROLLLINES 104
347 ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &linesPerScroll
, 0);
351 lastWheelMouseTime
.tv_sec
= 0;
352 lastWheelMouseTime
.tv_usec
= 0;
357 ScintillaGTK::~ScintillaGTK() {
360 void ScintillaGTK::RealizeThis(GtkWidget
*widget
) {
361 //Platform::DebugPrintf("ScintillaGTK::realize this\n");
362 GTK_WIDGET_SET_FLAGS(widget
, GTK_REALIZED
);
364 attrs
.window_type
= GDK_WINDOW_CHILD
;
365 attrs
.x
= widget
->allocation
.x
;
366 attrs
.y
= widget
->allocation
.y
;
367 attrs
.width
= widget
->allocation
.width
;
368 attrs
.height
= widget
->allocation
.height
;
369 attrs
.wclass
= GDK_INPUT_OUTPUT
;
370 attrs
.visual
= gtk_widget_get_visual(widget
);
371 attrs
.colormap
= gtk_widget_get_colormap(widget
);
372 attrs
.event_mask
= gtk_widget_get_events(widget
) | GDK_EXPOSURE_MASK
;
373 GdkCursor
*cursor
= gdk_cursor_new(GDK_XTERM
);
374 attrs
.cursor
= cursor
;
375 widget
->window
= gdk_window_new(gtk_widget_get_parent_window(widget
), &attrs
,
376 GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
| GDK_WA_COLORMAP
| GDK_WA_CURSOR
);
377 gdk_window_set_user_data(widget
->window
, widget
);
378 gdk_window_set_background(widget
->window
, &widget
->style
->bg
[GTK_STATE_NORMAL
]);
379 gdk_window_show(widget
->window
);
380 gdk_cursor_destroy(cursor
);
381 widget
->style
= gtk_style_attach(widget
->style
, widget
->window
);
382 wPreedit
= gtk_window_new(GTK_WINDOW_POPUP
);
383 wPreeditDraw
= gtk_drawing_area_new();
384 GtkWidget
*predrw
= PWidget(wPreeditDraw
); // No code inside the G_OBJECT macro
385 g_signal_connect(G_OBJECT(predrw
), "expose_event",
386 G_CALLBACK(ExposePreedit
), this);
387 gtk_container_add(GTK_CONTAINER(PWidget(wPreedit
)), predrw
);
388 gtk_widget_realize(PWidget(wPreedit
));
389 gtk_widget_realize(predrw
);
390 gtk_widget_show(predrw
);
392 im_context
= gtk_im_multicontext_new();
393 g_signal_connect(G_OBJECT(im_context
), "commit",
394 G_CALLBACK(Commit
), this);
395 g_signal_connect(G_OBJECT(im_context
), "preedit_changed",
396 G_CALLBACK(PreeditChanged
), this);
397 gtk_im_context_set_client_window(im_context
, widget
->window
);
398 GtkWidget
*widtxt
= PWidget(wText
); // // No code inside the G_OBJECT macro
399 g_signal_connect_after(G_OBJECT(widtxt
), "style_set",
400 G_CALLBACK(ScintillaGTK::StyleSetText
), NULL
);
401 g_signal_connect_after(G_OBJECT(widtxt
), "realize",
402 G_CALLBACK(ScintillaGTK::RealizeText
), NULL
);
403 gtk_widget_realize(widtxt
);
404 gtk_widget_realize(PWidget(scrollbarv
));
405 gtk_widget_realize(PWidget(scrollbarh
));
408 void ScintillaGTK::Realize(GtkWidget
*widget
) {
409 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
410 sciThis
->RealizeThis(widget
);
413 void ScintillaGTK::UnRealizeThis(GtkWidget
*widget
) {
415 if (GTK_WIDGET_MAPPED(widget
)) {
416 gtk_widget_unmap(widget
);
418 GTK_WIDGET_UNSET_FLAGS(widget
, GTK_REALIZED
);
419 gtk_widget_unrealize(PWidget(wText
));
420 gtk_widget_unrealize(PWidget(scrollbarv
));
421 gtk_widget_unrealize(PWidget(scrollbarh
));
422 gtk_widget_unrealize(PWidget(wPreedit
));
423 gtk_widget_unrealize(PWidget(wPreeditDraw
));
424 g_object_unref(im_context
);
426 if (GTK_WIDGET_CLASS(parentClass
)->unrealize
)
427 GTK_WIDGET_CLASS(parentClass
)->unrealize(widget
);
431 errorStatus
= SC_STATUS_FAILURE
;
435 void ScintillaGTK::UnRealize(GtkWidget
*widget
) {
436 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
437 sciThis
->UnRealizeThis(widget
);
440 static void MapWidget(GtkWidget
*widget
) {
442 GTK_WIDGET_VISIBLE(widget
) &&
443 !GTK_WIDGET_MAPPED(widget
)) {
444 gtk_widget_map(widget
);
448 void ScintillaGTK::MapThis() {
450 //Platform::DebugPrintf("ScintillaGTK::map this\n");
451 GTK_WIDGET_SET_FLAGS(PWidget(wMain
), GTK_MAPPED
);
452 MapWidget(PWidget(wText
));
453 MapWidget(PWidget(scrollbarh
));
454 MapWidget(PWidget(scrollbarv
));
455 wMain
.SetCursor(Window::cursorArrow
);
456 scrollbarv
.SetCursor(Window::cursorArrow
);
457 scrollbarh
.SetCursor(Window::cursorArrow
);
459 gdk_window_show(PWidget(wMain
)->window
);
461 errorStatus
= SC_STATUS_FAILURE
;
465 void ScintillaGTK::Map(GtkWidget
*widget
) {
466 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
470 void ScintillaGTK::UnMapThis() {
472 //Platform::DebugPrintf("ScintillaGTK::unmap this\n");
473 GTK_WIDGET_UNSET_FLAGS(PWidget(wMain
), GTK_MAPPED
);
475 gdk_window_hide(PWidget(wMain
)->window
);
476 gtk_widget_unmap(PWidget(wText
));
477 gtk_widget_unmap(PWidget(scrollbarh
));
478 gtk_widget_unmap(PWidget(scrollbarv
));
480 errorStatus
= SC_STATUS_FAILURE
;
484 void ScintillaGTK::UnMap(GtkWidget
*widget
) {
485 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
486 sciThis
->UnMapThis();
489 void ScintillaGTK::ForAll(GtkCallback callback
, gpointer callback_data
) {
491 (*callback
) (PWidget(wText
), callback_data
);
492 (*callback
) (PWidget(scrollbarv
), callback_data
);
493 (*callback
) (PWidget(scrollbarh
), callback_data
);
495 errorStatus
= SC_STATUS_FAILURE
;
499 void ScintillaGTK::MainForAll(GtkContainer
*container
, gboolean include_internals
, GtkCallback callback
, gpointer callback_data
) {
500 ScintillaGTK
*sciThis
= ScintillaFromWidget((GtkWidget
*)container
);
502 if (callback
!= NULL
&& include_internals
) {
503 sciThis
->ForAll(callback
, callback_data
);
507 gint
ScintillaGTK::CursorMoved(GtkWidget
*, int xoffset
, int yoffset
, ScintillaGTK
*sciThis
) {
513 gtk_im_context_set_cursor_location(sciThis
->im_context
, &area
);
517 gint
ScintillaGTK::FocusInThis(GtkWidget
*widget
) {
519 GTK_WIDGET_SET_FLAGS(widget
, GTK_HAS_FOCUS
);
521 if (im_context
!= NULL
) {
525 gtk_im_context_get_preedit_string(im_context
, &str
, NULL
, &cursor_pos
);
526 if (PWidget(wPreedit
) != NULL
) {
527 if (strlen(str
) > 0) {
528 gtk_widget_show(PWidget(wPreedit
));
530 gtk_widget_hide(PWidget(wPreedit
));
534 gtk_im_context_focus_in(im_context
);
538 errorStatus
= SC_STATUS_FAILURE
;
543 gint
ScintillaGTK::FocusIn(GtkWidget
*widget
, GdkEventFocus
* /*event*/) {
544 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
545 return sciThis
->FocusInThis(widget
);
548 gint
ScintillaGTK::FocusOutThis(GtkWidget
*widget
) {
550 GTK_WIDGET_UNSET_FLAGS(widget
, GTK_HAS_FOCUS
);
551 SetFocusState(false);
553 if (PWidget(wPreedit
) != NULL
)
554 gtk_widget_hide(PWidget(wPreedit
));
555 if (im_context
!= NULL
)
556 gtk_im_context_focus_out(im_context
);
559 errorStatus
= SC_STATUS_FAILURE
;
564 gint
ScintillaGTK::FocusOut(GtkWidget
*widget
, GdkEventFocus
* /*event*/) {
565 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
566 return sciThis
->FocusOutThis(widget
);
569 void ScintillaGTK::SizeRequest(GtkWidget
*widget
, GtkRequisition
*requisition
) {
570 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
571 requisition
->width
= 600;
572 requisition
->height
= gdk_screen_height();
573 GtkRequisition child_requisition
;
574 gtk_widget_size_request(PWidget(sciThis
->scrollbarh
), &child_requisition
);
575 gtk_widget_size_request(PWidget(sciThis
->scrollbarv
), &child_requisition
);
578 void ScintillaGTK::SizeAllocate(GtkWidget
*widget
, GtkAllocation
*allocation
) {
579 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
581 widget
->allocation
= *allocation
;
582 if (GTK_WIDGET_REALIZED(widget
))
583 gdk_window_move_resize(widget
->window
,
584 widget
->allocation
.x
,
585 widget
->allocation
.y
,
586 widget
->allocation
.width
,
587 widget
->allocation
.height
);
589 sciThis
->Resize(allocation
->width
, allocation
->height
);
592 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
596 void ScintillaGTK::Initialise() {
597 //Platform::DebugPrintf("ScintillaGTK::Initialise\n");
598 parentClass
= reinterpret_cast<GtkWidgetClass
*>(
599 gtk_type_class(gtk_container_get_type()));
601 GTK_WIDGET_SET_FLAGS(PWidget(wMain
), GTK_CAN_FOCUS
);
602 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(PWidget(wMain
)), GTK_SENSITIVE
);
603 gtk_widget_set_events(PWidget(wMain
),
607 | GDK_KEY_RELEASE_MASK
608 | GDK_FOCUS_CHANGE_MASK
609 | GDK_LEAVE_NOTIFY_MASK
610 | GDK_BUTTON_PRESS_MASK
611 | GDK_BUTTON_RELEASE_MASK
612 | GDK_POINTER_MOTION_MASK
613 | GDK_POINTER_MOTION_HINT_MASK
);
615 wText
= gtk_drawing_area_new();
616 gtk_widget_set_parent(PWidget(wText
), PWidget(wMain
));
617 GtkWidget
*widtxt
= PWidget(wText
); // No code inside the G_OBJECT macro
618 gtk_widget_show(widtxt
);
619 g_signal_connect(G_OBJECT(widtxt
), "expose_event",
620 G_CALLBACK(ScintillaGTK::ExposeText
), this);
621 gtk_widget_set_events(widtxt
, GDK_EXPOSURE_MASK
);
622 // Avoid background drawing flash
623 gtk_widget_set_double_buffered(widtxt
, FALSE
);
624 gtk_drawing_area_size(GTK_DRAWING_AREA(widtxt
),
626 adjustmentv
= gtk_adjustment_new(0.0, 0.0, 201.0, 1.0, 20.0, 20.0);
627 scrollbarv
= gtk_vscrollbar_new(GTK_ADJUSTMENT(adjustmentv
));
628 GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarv
), GTK_CAN_FOCUS
);
629 g_signal_connect(G_OBJECT(adjustmentv
), "value_changed",
630 G_CALLBACK(ScrollSignal
), this);
631 gtk_widget_set_parent(PWidget(scrollbarv
), PWidget(wMain
));
632 gtk_widget_show(PWidget(scrollbarv
));
634 adjustmenth
= gtk_adjustment_new(0.0, 0.0, 101.0, 1.0, 20.0, 20.0);
635 scrollbarh
= gtk_hscrollbar_new(GTK_ADJUSTMENT(adjustmenth
));
636 GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarh
), GTK_CAN_FOCUS
);
637 g_signal_connect(G_OBJECT(adjustmenth
), "value_changed",
638 G_CALLBACK(ScrollHSignal
), this);
639 gtk_widget_set_parent(PWidget(scrollbarh
), PWidget(wMain
));
640 gtk_widget_show(PWidget(scrollbarh
));
642 gtk_widget_grab_focus(PWidget(wMain
));
644 gtk_selection_add_targets(GTK_WIDGET(PWidget(wMain
)), GDK_SELECTION_PRIMARY
,
645 clipboardCopyTargets
, nClipboardCopyTargets
);
647 #ifndef USE_GTK_CLIPBOARD
648 gtk_selection_add_targets(GTK_WIDGET(PWidget(wMain
)), atomClipboard
,
649 clipboardPasteTargets
, nClipboardPasteTargets
);
652 gtk_drag_dest_set(GTK_WIDGET(PWidget(wMain
)),
653 GTK_DEST_DEFAULT_ALL
, clipboardPasteTargets
, nClipboardPasteTargets
,
654 static_cast<GdkDragAction
>(GDK_ACTION_COPY
| GDK_ACTION_MOVE
));
656 // Set caret period based on GTK settings
657 gboolean blinkOn
= false;
658 if (g_object_class_find_property(G_OBJECT_GET_CLASS(
659 G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink")) {
660 g_object_get(G_OBJECT(
661 gtk_settings_get_default()), "gtk-cursor-blink", &blinkOn
, NULL
);
664 g_object_class_find_property(G_OBJECT_GET_CLASS(
665 G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink-time")) {
667 g_object_get(G_OBJECT(
668 gtk_settings_get_default()), "gtk-cursor-blink-time", &value
, NULL
);
669 caret
.period
= gint(value
/ 1.75);
677 void ScintillaGTK::Finalise() {
679 ScintillaBase::Finalise();
682 void ScintillaGTK::DisplayCursor(Window::Cursor c
) {
683 if (cursorMode
== SC_CURSORNORMAL
)
686 wText
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
689 bool ScintillaGTK::DragThreshold(Point ptStart
, Point ptNow
) {
690 return gtk_drag_check_threshold(GTK_WIDGET(PWidget(wMain
)),
691 ptStart
.x
, ptStart
.y
, ptNow
.x
, ptNow
.y
);
694 void ScintillaGTK::StartDrag() {
695 dragWasDropped
= false;
696 inDragDrop
= ddDragging
;
697 GtkTargetList
*tl
= gtk_target_list_new(clipboardCopyTargets
, nClipboardCopyTargets
);
698 gtk_drag_begin(GTK_WIDGET(PWidget(wMain
)),
700 static_cast<GdkDragAction
>(GDK_ACTION_COPY
| GDK_ACTION_MOVE
),
702 reinterpret_cast<GdkEvent
*>(&evbtn
));
705 static char *ConvertText(int *lenResult
, char *s
, size_t len
, const char *charSetDest
,
706 const char *charSetSource
, bool transliterations
, bool silent
=false) {
707 // s is not const because of different versions of iconv disagreeing about const
710 Converter
conv(charSetDest
, charSetSource
, transliterations
);
712 destForm
= new char[len
*3+1];
715 char *pout
= destForm
;
716 size_t outLeft
= len
*3+1;
717 size_t conversions
= conv
.Convert(&pin
, &inLeft
, &pout
, &outLeft
);
718 if (conversions
== ((size_t)(-1))) {
720 fprintf(stderr
, "iconv %s->%s failed for %s\n",
721 charSetSource
, charSetDest
, static_cast<char *>(s
));
725 //fprintf(stderr, "iconv OK %s %d\n", destForm, pout - destForm);
727 *lenResult
= pout
- destForm
;
730 fprintf(stderr
, "Can not iconv %s %s\n", charSetDest
, charSetSource
);
733 destForm
= new char[1];
740 // Returns the target converted to UTF8.
741 // Return the length in bytes.
742 int ScintillaGTK::TargetAsUTF8(char *text
) {
743 int targetLength
= targetEnd
- targetStart
;
744 if (IsUnicodeMode()) {
746 pdoc
->GetCharRange(text
, targetStart
, targetLength
);
750 const char *charSetBuffer
= CharacterSetID();
751 if (*charSetBuffer
) {
752 //~ fprintf(stderr, "AsUTF8 %s %d %0d-%0d\n", charSetBuffer, targetLength, targetStart, targetEnd);
753 char *s
= new char[targetLength
];
755 pdoc
->GetCharRange(s
, targetStart
, targetLength
);
756 //~ fprintf(stderr, " \"%s\"\n", s);
758 char *tmputf
= ConvertText(&targetLength
, s
, targetLength
, "UTF-8", charSetBuffer
, false);
759 memcpy(text
, tmputf
, targetLength
);
761 //~ fprintf(stderr, " \"%s\"\n", text);
767 pdoc
->GetCharRange(text
, targetStart
, targetLength
);
771 //~ fprintf(stderr, "Length = %d bytes\n", targetLength);
775 // Translates a nul terminated UTF8 string into the document encoding.
776 // Return the length of the result in bytes.
777 int ScintillaGTK::EncodedFromUTF8(char *utf8
, char *encoded
) {
778 int inputLength
= (lengthForEncode
>= 0) ? lengthForEncode
: strlen(utf8
);
779 if (IsUnicodeMode()) {
781 memcpy(encoded
, utf8
, inputLength
);
786 const char *charSetBuffer
= CharacterSetID();
787 if (*charSetBuffer
) {
789 char *tmpEncoded
= ConvertText(&outLength
, utf8
, inputLength
, charSetBuffer
, "UTF-8", true);
792 memcpy(encoded
, tmpEncoded
, outLength
);
799 memcpy(encoded
, utf8
, inputLength
);
808 bool ScintillaGTK::ValidCodePage(int codePage
) const {
810 || codePage
== SC_CP_UTF8
814 || codePage
== SC_CP_DBCS
;
817 sptr_t
ScintillaGTK::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
822 gtk_widget_grab_focus(PWidget(wMain
));
825 case SCI_GETDIRECTFUNCTION
:
826 return reinterpret_cast<sptr_t
>(DirectFunction
);
828 case SCI_GETDIRECTPOINTER
:
829 return reinterpret_cast<sptr_t
>(this);
832 case SCI_LOADLEXERLIBRARY
:
833 LexerManager::GetInstance()->Load(reinterpret_cast<const char*>(lParam
));
836 case SCI_TARGETASUTF8
:
837 return TargetAsUTF8(reinterpret_cast<char*>(lParam
));
839 case SCI_ENCODEDFROMUTF8
:
840 return EncodedFromUTF8(reinterpret_cast<char*>(wParam
),
841 reinterpret_cast<char*>(lParam
));
843 case SCI_SETRECTANGULARSELECTIONMODIFIER
:
844 rectangularSelectionModifier
= wParam
;
847 case SCI_GETRECTANGULARSELECTIONMODIFIER
:
848 return rectangularSelectionModifier
;
851 return ScintillaBase::WndProc(iMessage
, wParam
, lParam
);
853 } catch (std::bad_alloc
&) {
854 errorStatus
= SC_STATUS_BADALLOC
;
856 errorStatus
= SC_STATUS_FAILURE
;
861 sptr_t
ScintillaGTK::DefWndProc(unsigned int, uptr_t
, sptr_t
) {
865 void ScintillaGTK::SetTicking(bool on
) {
866 if (timer
.ticking
!= on
) {
869 timer
.tickerID
= reinterpret_cast<TickerID
>(gtk_timeout_add(timer
.tickSize
, (GtkFunction
)TimeOut
, this));
871 gtk_timeout_remove(GPOINTER_TO_UINT(timer
.tickerID
));
874 timer
.ticksToWait
= caret
.period
;
877 bool ScintillaGTK::SetIdle(bool on
) {
879 // Start idler, if it's not running.
882 idler
.idlerID
= reinterpret_cast<IdlerID
>(
883 g_idle_add_full(G_PRIORITY_DEFAULT_IDLE
,
884 reinterpret_cast<GSourceFunc
>(IdleCallback
), this, NULL
));
887 // Stop idler, if it's running
890 g_source_remove(GPOINTER_TO_UINT(idler
.idlerID
));
896 void ScintillaGTK::SetMouseCapture(bool on
) {
897 if (mouseDownCaptures
) {
899 gtk_grab_add(GTK_WIDGET(PWidget(wMain
)));
901 gtk_grab_remove(GTK_WIDGET(PWidget(wMain
)));
907 bool ScintillaGTK::HaveMouseCapture() {
908 return capturedMouse
;
911 bool ScintillaGTK::PaintContains(PRectangle rc
) {
912 bool contains
= true;
913 if (paintState
== painting
) {
914 if (!rcPaint
.Contains(rc
)) {
916 } else if (rgnUpdate
) {
917 GdkRectangle grc
= {rc
.left
, rc
.top
,
918 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
};
919 if (gdk_region_rect_in(rgnUpdate
, &grc
) != GDK_OVERLAP_RECTANGLE_IN
) {
927 // Redraw all of text area. This paint will not be abandoned.
928 void ScintillaGTK::FullPaint() {
929 wText
.InvalidateAll();
932 PRectangle
ScintillaGTK::GetClientRectangle() {
933 PRectangle rc
= wMain
.GetClientPosition();
934 if (verticalScrollBarVisible
)
935 rc
.right
-= scrollBarWidth
;
936 if (horizontalScrollBarVisible
&& (wrapState
== eWrapNone
))
937 rc
.bottom
-= scrollBarHeight
;
946 // Synchronously paint a rectangle of the window.
947 void ScintillaGTK::SyncPaint(PRectangle rc
) {
948 paintState
= painting
;
950 PRectangle rcClient
= GetClientRectangle();
951 paintingAllText
= rcPaint
.Contains(rcClient
);
952 if ((PWidget(wText
))->window
) {
953 Surface
*sw
= Surface::Allocate();
955 sw
->Init(PWidget(wText
)->window
, PWidget(wText
));
961 if (paintState
== paintAbandoned
) {
962 // Painting area was insufficient to cover new styling or brace highlight positions
965 paintState
= notPainting
;
968 void ScintillaGTK::ScrollText(int linesToMove
) {
969 int diff
= vs
.lineHeight
* -linesToMove
;
970 //Platform::DebugPrintf("ScintillaGTK::ScrollText %d %d %0d,%0d %0d,%0d\n", linesToMove, diff,
971 // rc.left, rc.top, rc.right, rc.bottom);
972 GtkWidget
*wi
= PWidget(wText
);
974 gdk_window_scroll(wi
->window
, 0, -diff
);
975 gdk_window_process_updates(wi
->window
, FALSE
);
978 void ScintillaGTK::SetVerticalScrollPos() {
980 gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmentv
), topLine
);
983 void ScintillaGTK::SetHorizontalScrollPos() {
985 gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmenth
), xOffset
/ 2);
988 bool ScintillaGTK::ModifyScrollBars(int nMax
, int nPage
) {
989 bool modified
= false;
990 int pageScroll
= LinesToScroll();
992 if (GTK_ADJUSTMENT(adjustmentv
)->upper
!= (nMax
+ 1) ||
993 GTK_ADJUSTMENT(adjustmentv
)->page_size
!= nPage
||
994 GTK_ADJUSTMENT(adjustmentv
)->page_increment
!= pageScroll
) {
995 GTK_ADJUSTMENT(adjustmentv
)->upper
= nMax
+ 1;
996 GTK_ADJUSTMENT(adjustmentv
)->page_size
= nPage
;
997 GTK_ADJUSTMENT(adjustmentv
)->page_increment
= pageScroll
;
998 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv
));
1002 PRectangle rcText
= GetTextRectangle();
1003 int horizEndPreferred
= scrollWidth
;
1004 if (horizEndPreferred
< 0)
1005 horizEndPreferred
= 0;
1006 unsigned int pageWidth
= rcText
.Width();
1007 unsigned int pageIncrement
= pageWidth
/ 3;
1008 unsigned int charWidth
= vs
.styles
[STYLE_DEFAULT
].aveCharWidth
;
1009 if (GTK_ADJUSTMENT(adjustmenth
)->upper
!= horizEndPreferred
||
1010 GTK_ADJUSTMENT(adjustmenth
)->page_size
!= pageWidth
||
1011 GTK_ADJUSTMENT(adjustmenth
)->page_increment
!= pageIncrement
||
1012 GTK_ADJUSTMENT(adjustmenth
)->step_increment
!= charWidth
) {
1013 GTK_ADJUSTMENT(adjustmenth
)->upper
= horizEndPreferred
;
1014 GTK_ADJUSTMENT(adjustmenth
)->step_increment
= charWidth
;
1015 GTK_ADJUSTMENT(adjustmenth
)->page_size
= pageWidth
;
1016 GTK_ADJUSTMENT(adjustmenth
)->page_increment
= pageIncrement
;
1017 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth
));
1023 void ScintillaGTK::ReconfigureScrollBars() {
1024 PRectangle rc
= wMain
.GetClientPosition();
1025 Resize(rc
.Width(), rc
.Height());
1028 void ScintillaGTK::NotifyChange() {
1029 g_signal_emit(G_OBJECT(sci
), scintilla_signals
[COMMAND_SIGNAL
], 0,
1030 Platform::LongFromTwoShorts(GetCtrlID(), SCEN_CHANGE
), PWidget(wMain
));
1033 void ScintillaGTK::NotifyFocus(bool focus
) {
1034 g_signal_emit(G_OBJECT(sci
), scintilla_signals
[COMMAND_SIGNAL
], 0,
1035 Platform::LongFromTwoShorts
1036 (GetCtrlID(), focus
? SCEN_SETFOCUS
: SCEN_KILLFOCUS
), PWidget(wMain
));
1039 void ScintillaGTK::NotifyParent(SCNotification scn
) {
1040 scn
.nmhdr
.hwndFrom
= PWidget(wMain
);
1041 scn
.nmhdr
.idFrom
= GetCtrlID();
1042 g_signal_emit(G_OBJECT(sci
), scintilla_signals
[NOTIFY_SIGNAL
], 0,
1046 void ScintillaGTK::NotifyKey(int key
, int modifiers
) {
1047 SCNotification scn
= {0};
1048 scn
.nmhdr
.code
= SCN_KEY
;
1050 scn
.modifiers
= modifiers
;
1055 void ScintillaGTK::NotifyURIDropped(const char *list
) {
1056 SCNotification scn
= {0};
1057 scn
.nmhdr
.code
= SCN_URIDROPPED
;
1063 const char *CharacterSetID(int characterSet
);
1065 const char *ScintillaGTK::CharacterSetID() const {
1066 return ::CharacterSetID(vs
.styles
[STYLE_DEFAULT
].characterSet
);
1069 class CaseFolderUTF8
: public CaseFolderTable
{
1074 virtual size_t Fold(char *folded
, size_t sizeFolded
, const char *mixed
, size_t lenMixed
) {
1075 if ((lenMixed
== 1) && (sizeFolded
> 0)) {
1076 folded
[0] = mapping
[static_cast<unsigned char>(mixed
[0])];
1079 gchar
*mapped
= g_utf8_casefold(mixed
, lenMixed
);
1080 size_t lenMapped
= strlen(mapped
);
1081 if (lenMapped
< sizeFolded
) {
1082 memcpy(folded
, mapped
, lenMapped
);
1092 CaseFolder
*ScintillaGTK::CaseFolderForEncoding() {
1093 if (pdoc
->dbcsCodePage
== SC_CP_UTF8
) {
1094 return new CaseFolderUTF8();
1096 CaseFolderTable
*pcf
= new CaseFolderTable();
1097 const char *charSetBuffer
= CharacterSetID();
1098 if ((pdoc
->dbcsCodePage
== 0) && charSetBuffer
) {
1099 pcf
->StandardASCII();
1100 // Only for single byte encodings
1101 for (int i
=0x80; i
<0x100; i
++) {
1102 char sCharacter
[2] = "A";
1104 int convertedLength
= 1;
1105 const char *sUTF8
= ConvertText(&convertedLength
, sCharacter
, 1,
1106 "UTF-8", charSetBuffer
, false);
1108 gchar
*mapped
= g_utf8_casefold(sUTF8
, strlen(sUTF8
));
1110 int mappedLength
= strlen(mapped
);
1111 const char *mappedBack
= ConvertText(&mappedLength
, mapped
,
1112 mappedLength
, charSetBuffer
, "UTF-8", false, true);
1113 if (mappedBack
&& (strlen(mappedBack
) == 1) && (mappedBack
[0] != sCharacter
[0])) {
1114 pcf
->SetTranslation(sCharacter
[0], mappedBack
[0]);
1116 delete []mappedBack
;
1127 std::string
ScintillaGTK::CaseMapString(const std::string
&s
, int caseMapping
) {
1129 return std::string();
1131 if (caseMapping
== cmSame
)
1134 const char *needsFree1
= 0; // Must be freed with delete []
1135 const char *charSetBuffer
= CharacterSetID();
1136 const char *sUTF8
= s
.c_str();
1137 int rangeBytes
= s
.size();
1139 int convertedLength
= rangeBytes
;
1140 // Change text to UTF-8
1141 if (!IsUnicodeMode()) {
1143 if (*charSetBuffer
) {
1144 sUTF8
= ConvertText(&convertedLength
, const_cast<char *>(s
.c_str()), rangeBytes
,
1145 "UTF-8", charSetBuffer
, false);
1149 gchar
*mapped
; // Must be freed with g_free
1150 if (caseMapping
== cmUpper
) {
1151 mapped
= g_utf8_strup(sUTF8
, convertedLength
);
1153 mapped
= g_utf8_strdown(sUTF8
, convertedLength
);
1155 int mappedLength
= strlen(mapped
);
1156 char *mappedBack
= mapped
;
1158 char *needsFree2
= 0; // Must be freed with delete []
1159 if (!IsUnicodeMode()) {
1160 if (*charSetBuffer
) {
1161 mappedBack
= ConvertText(&mappedLength
, mapped
, mappedLength
, charSetBuffer
, "UTF-8", false);
1162 needsFree2
= mappedBack
;
1166 std::string
ret(mappedBack
, mappedLength
);
1168 delete []needsFree1
;
1169 delete []needsFree2
;
1173 int ScintillaGTK::KeyDefault(int key
, int modifiers
) {
1174 if (!(modifiers
& SCI_CTRL
) && !(modifiers
& SCI_ALT
)) {
1176 NotifyKey(key
, modifiers
);
1179 // Pass up to container in case it is an accelerator
1180 NotifyKey(key
, modifiers
);
1184 // Pass up to container in case it is an accelerator
1185 NotifyKey(key
, modifiers
);
1188 //Platform::DebugPrintf("SK-key: %d %x %x\n",key, modifiers);
1191 void ScintillaGTK::CopyToClipboard(const SelectionText
&selectedText
) {
1192 #ifndef USE_GTK_CLIPBOARD
1193 copyText
.Copy(selectedText
);
1194 gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain
)),
1198 SelectionText
*clipText
= new SelectionText();
1199 clipText
->Copy(selectedText
);
1200 StoreOnClipboard(clipText
);
1204 void ScintillaGTK::Copy() {
1206 #ifndef USE_GTK_CLIPBOARD
1207 CopySelectionRange(©Text
);
1208 gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain
)),
1212 SelectionText
*clipText
= new SelectionText();
1213 CopySelectionRange(clipText
);
1214 StoreOnClipboard(clipText
);
1217 if (sel
.IsRectangular()) {
1218 ::OpenClipboard(NULL
);
1219 ::SetClipboardData(cfColumnSelect
, 0);
1226 void ScintillaGTK::Paste() {
1227 atomSought
= atomUTF8
;
1228 gtk_selection_convert(GTK_WIDGET(PWidget(wMain
)),
1229 atomClipboard
, atomSought
, GDK_CURRENT_TIME
);
1232 void ScintillaGTK::CreateCallTipWindow(PRectangle rc
) {
1233 if (!ct
.wCallTip
.Created()) {
1234 ct
.wCallTip
= gtk_window_new(GTK_WINDOW_POPUP
);
1235 ct
.wDraw
= gtk_drawing_area_new();
1236 GtkWidget
*widcdrw
= PWidget(ct
.wDraw
); // // No code inside the G_OBJECT macro
1237 gtk_container_add(GTK_CONTAINER(PWidget(ct
.wCallTip
)), widcdrw
);
1238 g_signal_connect(G_OBJECT(widcdrw
), "expose_event",
1239 G_CALLBACK(ScintillaGTK::ExposeCT
), &ct
);
1240 g_signal_connect(G_OBJECT(widcdrw
), "button_press_event",
1241 G_CALLBACK(ScintillaGTK::PressCT
), static_cast<void *>(this));
1242 gtk_widget_set_events(widcdrw
,
1243 GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
);
1245 gtk_drawing_area_size(GTK_DRAWING_AREA(PWidget(ct
.wDraw
)),
1246 rc
.Width(), rc
.Height());
1248 if (PWidget(ct
.wCallTip
)->window
) {
1249 gdk_window_resize(PWidget(ct
.wCallTip
)->window
, rc
.Width(), rc
.Height());
1253 void ScintillaGTK::AddToPopUp(const char *label
, int cmd
, bool enabled
) {
1254 char fulllabel
[200];
1255 strcpy(fulllabel
, "/");
1256 strcat(fulllabel
, label
);
1257 GtkItemFactoryCallback menuSig
= GtkItemFactoryCallback(PopUpCB
);
1258 GtkItemFactoryEntry itemEntry
= {
1262 const_cast<gchar
*>(label
[0] ? "<Item>" : "<Separator>"),
1265 gtk_item_factory_create_item(GTK_ITEM_FACTORY(popup
.GetID()),
1266 &itemEntry
, this, 1);
1268 GtkWidget
*item
= gtk_item_factory_get_widget_by_action(
1269 reinterpret_cast<GtkItemFactory
*>(popup
.GetID()), cmd
);
1271 gtk_widget_set_sensitive(item
, enabled
);
1275 bool ScintillaGTK::OwnPrimarySelection() {
1276 return ((gdk_selection_owner_get(GDK_SELECTION_PRIMARY
)
1277 == GTK_WIDGET(PWidget(wMain
))->window
) &&
1278 (GTK_WIDGET(PWidget(wMain
))->window
!= NULL
));
1281 void ScintillaGTK::ClaimSelection() {
1282 // X Windows has a 'primary selection' as well as the clipboard.
1283 // Whenever the user selects some text, we become the primary selection
1284 if (!sel
.Empty() && GTK_WIDGET_REALIZED(GTK_WIDGET(PWidget(wMain
)))) {
1285 primarySelection
= true;
1286 gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain
)),
1287 GDK_SELECTION_PRIMARY
, GDK_CURRENT_TIME
);
1289 } else if (OwnPrimarySelection()) {
1290 primarySelection
= true;
1291 if (primary
.s
== NULL
)
1292 gtk_selection_owner_set(NULL
, GDK_SELECTION_PRIMARY
, GDK_CURRENT_TIME
);
1294 primarySelection
= false;
1299 // Detect rectangular text, convert line ends to current mode, convert from or to UTF-8
1300 void ScintillaGTK::GetGtkSelectionText(GtkSelectionData
*selectionData
, SelectionText
&selText
) {
1301 char *data
= reinterpret_cast<char *>(selectionData
->data
);
1302 int len
= selectionData
->length
;
1303 GdkAtom selectionTypeData
= selectionData
->type
;
1305 // Return empty string if selection is not a string
1306 if ((selectionTypeData
!= GDK_TARGET_STRING
) && (selectionTypeData
!= atomUTF8
)) {
1307 char *empty
= new char[1];
1309 selText
.Set(empty
, 0, SC_CP_UTF8
, 0, false, false);
1313 // Check for "\n\0" ending to string indicating that selection is rectangular
1316 isRectangular
= ::IsClipboardFormatAvailable(cfColumnSelect
) != 0;
1318 isRectangular
= ((len
> 2) && (data
[len
- 1] == 0 && data
[len
- 2] == '\n'));
1320 len
--; // Forget the extra '\0'
1324 if (selectionTypeData
== GDK_TARGET_STRING
) {
1325 dest
= Document::TransformLineEnds(&len
, data
, len
, pdoc
->eolMode
);
1326 if (IsUnicodeMode()) {
1327 // Unknown encoding so assume in Latin1
1328 char *destPrevious
= dest
;
1329 dest
= UTF8FromLatin1(dest
, len
);
1330 selText
.Set(dest
, len
, SC_CP_UTF8
, 0, selText
.rectangular
, false);
1331 delete []destPrevious
;
1333 // Assume buffer is in same encoding as selection
1334 selText
.Set(dest
, len
, pdoc
->dbcsCodePage
,
1335 vs
.styles
[STYLE_DEFAULT
].characterSet
, isRectangular
, false);
1338 dest
= Document::TransformLineEnds(&len
, data
, len
, pdoc
->eolMode
);
1339 selText
.Set(dest
, len
, SC_CP_UTF8
, 0, isRectangular
, false);
1340 const char *charSetBuffer
= CharacterSetID();
1341 if (!IsUnicodeMode() && *charSetBuffer
) {
1342 // Convert to locale
1343 dest
= ConvertText(&len
, selText
.s
, selText
.len
, charSetBuffer
, "UTF-8", true);
1344 selText
.Set(dest
, len
, pdoc
->dbcsCodePage
,
1345 vs
.styles
[STYLE_DEFAULT
].characterSet
, selText
.rectangular
, false);
1350 void ScintillaGTK::ReceivedSelection(GtkSelectionData
*selection_data
) {
1352 if ((selection_data
->selection
== atomClipboard
) ||
1353 (selection_data
->selection
== GDK_SELECTION_PRIMARY
)) {
1354 if ((atomSought
== atomUTF8
) && (selection_data
->length
<= 0)) {
1355 atomSought
= atomString
;
1356 gtk_selection_convert(GTK_WIDGET(PWidget(wMain
)),
1357 selection_data
->selection
, atomSought
, GDK_CURRENT_TIME
);
1358 } else if ((selection_data
->length
> 0) &&
1359 ((selection_data
->type
== GDK_TARGET_STRING
) || (selection_data
->type
== atomUTF8
))) {
1360 SelectionText selText
;
1361 GetGtkSelectionText(selection_data
, selText
);
1364 if (selection_data
->selection
!= GDK_SELECTION_PRIMARY
) {
1367 SelectionPosition selStart
= sel
.IsRectangular() ?
1368 sel
.Rectangular().Start() :
1369 sel
.Range(sel
.Main()).Start();
1371 if (selText
.rectangular
) {
1372 PasteRectangular(selStart
, selText
.s
, selText
.len
);
1374 InsertPaste(selStart
, selText
.s
, selText
.len
);
1376 EnsureCaretVisible();
1379 // else fprintf(stderr, "Target non string %d %d\n", (int)(selection_data->type),
1380 // (int)(atomUTF8));
1383 errorStatus
= SC_STATUS_FAILURE
;
1387 void ScintillaGTK::ReceivedDrop(GtkSelectionData
*selection_data
) {
1388 dragWasDropped
= true;
1389 if (selection_data
->type
== atomUriList
|| selection_data
->type
== atomDROPFILES_DND
) {
1390 char *ptr
= new char[selection_data
->length
+ 1];
1391 ptr
[selection_data
->length
] = '\0';
1392 memcpy(ptr
, selection_data
->data
, selection_data
->length
);
1393 NotifyURIDropped(ptr
);
1395 } else if ((selection_data
->type
== GDK_TARGET_STRING
) || (selection_data
->type
== atomUTF8
)) {
1396 if (selection_data
->length
> 0) {
1397 SelectionText selText
;
1398 GetGtkSelectionText(selection_data
, selText
);
1399 DropAt(posDrop
, selText
.s
, false, selText
.rectangular
);
1401 } else if (selection_data
->length
> 0) {
1402 //~ fprintf(stderr, "ReceivedDrop other %p\n", static_cast<void *>(selection_data->type));
1409 void ScintillaGTK::GetSelection(GtkSelectionData
*selection_data
, guint info
, SelectionText
*text
) {
1411 // GDK on Win32 expands any \n into \r\n, so make a copy of
1412 // the clip text now with newlines converted to \n. Use { } to hide symbols
1414 SelectionText
*newline_normalized
= NULL
;
1417 char *tmpstr
= Document::TransformLineEnds(&tmpstr_len
, text
->s
, text
->len
, SC_EOL_LF
);
1418 newline_normalized
= new SelectionText();
1419 newline_normalized
->Set(tmpstr
, tmpstr_len
, SC_CP_UTF8
, 0, text
->rectangular
, false);
1420 text
= newline_normalized
;
1424 // Convert text to utf8 if it isn't already
1425 SelectionText
*converted
= 0;
1426 if ((text
->codePage
!= SC_CP_UTF8
) && (info
== TARGET_UTF8_STRING
)) {
1427 const char *charSet
= ::CharacterSetID(text
->characterSet
);
1430 char* tmputf
= ConvertText(&new_len
, text
->s
, text
->len
, "UTF-8", charSet
, false);
1431 converted
= new SelectionText();
1432 converted
->Set(tmputf
, new_len
, SC_CP_UTF8
, 0, text
->rectangular
, false);
1437 // Here is a somewhat evil kludge.
1438 // As I can not work out how to store data on the clipboard in multiple formats
1439 // and need some way to mark the clipping as being stream or rectangular,
1440 // the terminating \0 is included in the length for rectangular clippings.
1441 // All other tested aplications behave benignly by ignoring the \0.
1442 // The #if is here because on Windows cfColumnSelect clip entry is used
1443 // instead as standard indicator of rectangularness (so no need to kludge)
1444 const char *textData
= text
->s
? text
->s
: "";
1445 int len
= strlen(textData
);
1446 #if PLAT_GTK_WIN32 == 0
1447 if (text
->rectangular
)
1451 if (info
== TARGET_UTF8_STRING
) {
1452 gtk_selection_data_set_text(selection_data
, textData
, len
);
1454 gtk_selection_data_set(selection_data
,
1455 static_cast<GdkAtom
>(GDK_SELECTION_TYPE_STRING
),
1456 8, reinterpret_cast<const unsigned char *>(textData
), len
);
1461 delete newline_normalized
;
1465 #ifdef USE_GTK_CLIPBOARD
1466 void ScintillaGTK::StoreOnClipboard(SelectionText
*clipText
) {
1467 GtkClipboard
*clipBoard
=
1468 gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain
)), atomClipboard
);
1469 if (clipBoard
== NULL
) // Occurs if widget isn't in a toplevel
1472 if (gtk_clipboard_set_with_data(clipBoard
, clipboardCopyTargets
, nClipboardCopyTargets
,
1473 ClipboardGetSelection
, ClipboardClearSelection
, clipText
)) {
1474 gtk_clipboard_set_can_store(clipBoard
, clipboardCopyTargets
, nClipboardCopyTargets
);
1478 void ScintillaGTK::ClipboardGetSelection(GtkClipboard
*, GtkSelectionData
*selection_data
, guint info
, void *data
) {
1479 GetSelection(selection_data
, info
, static_cast<SelectionText
*>(data
));
1482 void ScintillaGTK::ClipboardClearSelection(GtkClipboard
*, void *data
) {
1483 SelectionText
*obj
= static_cast<SelectionText
*>(data
);
1488 void ScintillaGTK::UnclaimSelection(GdkEventSelection
*selection_event
) {
1490 //Platform::DebugPrintf("UnclaimSelection\n");
1491 if (selection_event
->selection
== GDK_SELECTION_PRIMARY
) {
1492 //Platform::DebugPrintf("UnclaimPrimarySelection\n");
1493 if (!OwnPrimarySelection()) {
1495 primarySelection
= false;
1500 errorStatus
= SC_STATUS_FAILURE
;
1504 void ScintillaGTK::Resize(int width
, int height
) {
1505 //Platform::DebugPrintf("Resize %d %d\n", width, height);
1506 //printf("Resize %d %d\n", width, height);
1508 // Not always needed, but some themes can have different sizes of scrollbars
1509 scrollBarWidth
= GTK_WIDGET(PWidget(scrollbarv
))->requisition
.width
;
1510 scrollBarHeight
= GTK_WIDGET(PWidget(scrollbarh
))->requisition
.height
;
1512 // These allocations should never produce negative sizes as they would wrap around to huge
1513 // unsigned numbers inside GTK+ causing warnings.
1514 bool showSBHorizontal
= horizontalScrollBarVisible
&& (wrapState
== eWrapNone
);
1515 int horizontalScrollBarHeight
= scrollBarHeight
;
1516 if (!showSBHorizontal
)
1517 horizontalScrollBarHeight
= 0;
1519 GtkAllocation alloc
;
1520 if (showSBHorizontal
) {
1521 gtk_widget_show(GTK_WIDGET(PWidget(scrollbarh
)));
1523 alloc
.y
= height
- scrollBarHeight
;
1524 alloc
.width
= Platform::Maximum(1, width
- scrollBarWidth
) + 1;
1525 alloc
.height
= horizontalScrollBarHeight
;
1526 gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarh
)), &alloc
);
1528 gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarh
)));
1531 if (verticalScrollBarVisible
) {
1532 gtk_widget_show(GTK_WIDGET(PWidget(scrollbarv
)));
1533 alloc
.x
= width
- scrollBarWidth
;
1535 alloc
.width
= scrollBarWidth
;
1536 alloc
.height
= Platform::Maximum(1, height
- scrollBarHeight
) + 1;
1537 if (!showSBHorizontal
)
1538 alloc
.height
+= scrollBarWidth
-1;
1539 gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarv
)), &alloc
);
1541 gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarv
)));
1543 if (GTK_WIDGET_MAPPED(PWidget(wMain
))) {
1549 alloc
.width
= Platform::Maximum(1, width
- scrollBarWidth
);
1550 alloc
.height
= Platform::Maximum(1, height
- scrollBarHeight
);
1551 if (!showSBHorizontal
)
1552 alloc
.height
+= scrollBarHeight
;
1553 if (!verticalScrollBarVisible
)
1554 alloc
.width
+= scrollBarWidth
;
1555 gtk_widget_size_allocate(GTK_WIDGET(PWidget(wText
)), &alloc
);
1558 static void SetAdjustmentValue(GtkObject
*object
, int value
) {
1559 GtkAdjustment
*adjustment
= GTK_ADJUSTMENT(object
);
1560 int maxValue
= static_cast<int>(
1561 adjustment
->upper
- adjustment
->page_size
);
1562 if (value
> maxValue
)
1566 gtk_adjustment_set_value(adjustment
, value
);
1569 static int modifierTranslated(int sciModifier
) {
1570 switch (sciModifier
) {
1572 return GDK_SHIFT_MASK
;
1574 return GDK_CONTROL_MASK
;
1576 return GDK_MOD1_MASK
;
1578 return GDK_MOD4_MASK
;
1584 gint
ScintillaGTK::PressThis(GdkEventButton
*event
) {
1586 //Platform::DebugPrintf("Press %x time=%d state = %x button = %x\n",this,event->time, event->state, event->button);
1587 // Do not use GTK+ double click events as Scintilla has its own double click detection
1588 if (event
->type
!= GDK_BUTTON_PRESS
)
1593 pt
.x
= int(event
->x
);
1594 pt
.y
= int(event
->y
);
1595 PRectangle rcClient
= GetClientRectangle();
1596 //Platform::DebugPrintf("Press %0d,%0d in %0d,%0d %0d,%0d\n",
1597 // pt.x, pt.y, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1598 if ((pt
.x
> rcClient
.right
) || (pt
.y
> rcClient
.bottom
)) {
1599 Platform::DebugPrintf("Bad location\n");
1603 bool ctrl
= (event
->state
& GDK_CONTROL_MASK
) != 0;
1605 gtk_widget_grab_focus(PWidget(wMain
));
1606 if (event
->button
== 1) {
1607 // On X, instead of sending literal modifiers use the user specified
1608 // modifier, defaulting to control instead of alt.
1609 // This is because most X window managers grab alt + click for moving
1610 ButtonDown(pt
, event
->time
,
1611 (event
->state
& GDK_SHIFT_MASK
) != 0,
1612 (event
->state
& GDK_CONTROL_MASK
) != 0,
1613 (event
->state
& modifierTranslated(rectangularSelectionModifier
)) != 0);
1614 } else if (event
->button
== 2) {
1615 // Grab the primary selection if it exists
1616 SelectionPosition pos
= SPositionFromLocation(pt
, false, false, UserVirtualSpace());
1617 if (OwnPrimarySelection() && primary
.s
== NULL
)
1618 CopySelectionRange(&primary
);
1621 SetSelection(pos
, pos
);
1622 atomSought
= atomUTF8
;
1623 gtk_selection_convert(GTK_WIDGET(PWidget(wMain
)), GDK_SELECTION_PRIMARY
,
1624 atomSought
, event
->time
);
1625 } else if (event
->button
== 3) {
1626 if (displayPopupMenu
) {
1628 // Convert to screen
1631 gdk_window_get_origin(PWidget(wMain
)->window
, &ox
, &oy
);
1632 ContextMenu(Point(pt
.x
+ ox
, pt
.y
+ oy
));
1636 } else if (event
->button
== 4) {
1637 // Wheel scrolling up (only GTK 1.x does it this way)
1639 SetAdjustmentValue(adjustmenth
, (xOffset
/ 2) - 6);
1641 SetAdjustmentValue(adjustmentv
, topLine
- 3);
1642 } else if (event
->button
== 5) {
1643 // Wheel scrolling down (only GTK 1.x does it this way)
1645 SetAdjustmentValue(adjustmenth
, (xOffset
/ 2) + 6);
1647 SetAdjustmentValue(adjustmentv
, topLine
+ 3);
1650 errorStatus
= SC_STATUS_FAILURE
;
1655 gint
ScintillaGTK::Press(GtkWidget
*widget
, GdkEventButton
*event
) {
1656 if (event
->window
!= widget
->window
)
1658 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1659 return sciThis
->PressThis(event
);
1662 gint
ScintillaGTK::MouseRelease(GtkWidget
*widget
, GdkEventButton
*event
) {
1663 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1665 //Platform::DebugPrintf("Release %x %d %d\n",sciThis,event->time,event->state);
1666 if (!sciThis
->HaveMouseCapture())
1668 if (event
->button
== 1) {
1670 pt
.x
= int(event
->x
);
1671 pt
.y
= int(event
->y
);
1672 //Platform::DebugPrintf("Up %x %x %d %d %d\n",
1673 // sciThis,event->window,event->time, pt.x, pt.y);
1674 if (event
->window
!= PWidget(sciThis
->wMain
)->window
)
1675 // If mouse released on scroll bar then the position is relative to the
1676 // scrollbar, not the drawing window so just repeat the most recent point.
1677 pt
= sciThis
->ptMouseLast
;
1678 sciThis
->ButtonUp(pt
, event
->time
, (event
->state
& 4) != 0);
1681 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
1686 // win32gtk and GTK >= 2 use SCROLL_* events instead of passing the
1687 // button4/5/6/7 events to the GTK app
1688 gint
ScintillaGTK::ScrollEvent(GtkWidget
*widget
,
1689 GdkEventScroll
*event
) {
1690 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1693 if (widget
== NULL
|| event
== NULL
)
1696 // Compute amount and direction to scroll (even tho on win32 there is
1697 // intensity of scrolling info in the native message, gtk doesn't
1698 // support this so we simulate similarly adaptive scrolling)
1699 // Note that this is disabled on OS X (Darwin) where the X11 server already has
1700 // and adaptive scrolling algorithm that fights with this one
1702 #if defined(__MWERKS__) || defined(__APPLE_CPP__) || defined(__APPLE_CC__)
1703 cLineScroll
= sciThis
->linesPerScroll
;
1704 if (cLineScroll
== 0)
1706 sciThis
->wheelMouseIntensity
= cLineScroll
;
1708 int timeDelta
= 1000000;
1710 g_get_current_time(&curTime
);
1711 if (curTime
.tv_sec
== sciThis
->lastWheelMouseTime
.tv_sec
)
1712 timeDelta
= curTime
.tv_usec
- sciThis
->lastWheelMouseTime
.tv_usec
;
1713 else if (curTime
.tv_sec
== sciThis
->lastWheelMouseTime
.tv_sec
+ 1)
1714 timeDelta
= 1000000 + (curTime
.tv_usec
- sciThis
->lastWheelMouseTime
.tv_usec
);
1715 if ((event
->direction
== sciThis
->lastWheelMouseDirection
) && (timeDelta
< 250000)) {
1716 if (sciThis
->wheelMouseIntensity
< 12)
1717 sciThis
->wheelMouseIntensity
++;
1718 cLineScroll
= sciThis
->wheelMouseIntensity
;
1720 cLineScroll
= sciThis
->linesPerScroll
;
1721 if (cLineScroll
== 0)
1723 sciThis
->wheelMouseIntensity
= cLineScroll
;
1726 if (event
->direction
== GDK_SCROLL_UP
|| event
->direction
== GDK_SCROLL_LEFT
) {
1729 g_get_current_time(&sciThis
->lastWheelMouseTime
);
1730 sciThis
->lastWheelMouseDirection
= event
->direction
;
1732 // Note: Unpatched versions of win32gtk don't set the 'state' value so
1733 // only regular scrolling is supported there. Also, unpatched win32gtk
1734 // issues spurious button 2 mouse events during wheeling, which can cause
1735 // problems (a patch for both was submitted by archaeopteryx.com on 13Jun2001)
1737 // Data zoom not supported
1738 if (event
->state
& GDK_SHIFT_MASK
) {
1742 // Horizontal scrolling
1743 if (event
->direction
== GDK_SCROLL_LEFT
|| event
->direction
== GDK_SCROLL_RIGHT
) {
1744 sciThis
->HorizontalScrollTo(sciThis
->xOffset
+ cLineScroll
);
1746 // Text font size zoom
1747 } else if (event
->state
& GDK_CONTROL_MASK
) {
1748 if (cLineScroll
< 0) {
1749 sciThis
->KeyCommand(SCI_ZOOMIN
);
1751 sciThis
->KeyCommand(SCI_ZOOMOUT
);
1754 // Regular scrolling
1756 sciThis
->ScrollTo(sciThis
->topLine
+ cLineScroll
);
1760 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
1765 gint
ScintillaGTK::Motion(GtkWidget
*widget
, GdkEventMotion
*event
) {
1766 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1768 //Platform::DebugPrintf("Motion %x %d\n",sciThis,event->time);
1769 if (event
->window
!= widget
->window
)
1773 GdkModifierType state
;
1774 if (event
->is_hint
) {
1775 gdk_window_get_pointer(event
->window
, &x
, &y
, &state
);
1777 x
= static_cast<int>(event
->x
);
1778 y
= static_cast<int>(event
->y
);
1779 state
= static_cast<GdkModifierType
>(event
->state
);
1781 //Platform::DebugPrintf("Move %x %x %d %c %d %d\n",
1782 // sciThis,event->window,event->time,event->is_hint? 'h' :'.', x, y);
1784 sciThis
->ButtonMove(pt
);
1786 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
1791 // Map the keypad keys to their equivalent functions
1792 static int KeyTranslate(int keyIn
) {
1794 case GDK_ISO_Left_Tab
:
1808 case GDK_KP_Page_Up
:
1810 case GDK_KP_Page_Down
:
1849 case GDK_KP_Subtract
:
1850 return SCK_SUBTRACT
;
1864 gboolean
ScintillaGTK::KeyThis(GdkEventKey
*event
) {
1866 //fprintf(stderr, "SC-key: %d %x [%s]\n",
1867 // event->keyval, event->state, (event->length > 0) ? event->string : "empty");
1868 if (gtk_im_context_filter_keypress(im_context
, event
)) {
1871 if (!event
->keyval
) {
1875 bool shift
= (event
->state
& GDK_SHIFT_MASK
) != 0;
1876 bool ctrl
= (event
->state
& GDK_CONTROL_MASK
) != 0;
1877 bool alt
= (event
->state
& GDK_MOD1_MASK
) != 0;
1878 guint key
= event
->keyval
;
1879 if (ctrl
&& (key
< 128))
1881 else if (!ctrl
&& (key
>= GDK_KP_Multiply
&& key
<= GDK_KP_9
))
1883 // Hack for keys over 256 and below command keys but makes Hungarian work.
1884 // This will have to change for Unicode
1885 else if (key
>= 0xFE00)
1886 key
= KeyTranslate(key
);
1888 bool consumed
= false;
1889 bool added
= KeyDown(key
, shift
, ctrl
, alt
, &consumed
) != 0;
1892 //fprintf(stderr, "SK-key: %d %x %x\n",event->keyval, event->state, consumed);
1893 if (event
->keyval
== 0xffffff && event
->length
> 0) {
1895 if (pdoc
->InsertCString(CurrentPosition(), event
->string
)) {
1896 MovePositionTo(CurrentPosition() + event
->length
);
1901 errorStatus
= SC_STATUS_FAILURE
;
1906 gboolean
ScintillaGTK::KeyPress(GtkWidget
*widget
, GdkEventKey
*event
) {
1907 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1908 return sciThis
->KeyThis(event
);
1911 gboolean
ScintillaGTK::KeyRelease(GtkWidget
*, GdkEventKey
* /*event*/) {
1912 //Platform::DebugPrintf("SC-keyrel: %d %x %3s\n",event->keyval, event->state, event->string);
1916 gboolean
ScintillaGTK::ExposePreeditThis(GtkWidget
*widget
, GdkEventExpose
*ose
) {
1920 PangoAttrList
*attrs
;
1922 gtk_im_context_get_preedit_string(im_context
, &str
, &attrs
, &cursor_pos
);
1923 PangoLayout
*layout
= gtk_widget_create_pango_layout(PWidget(wText
), str
);
1924 pango_layout_set_attributes(layout
, attrs
);
1926 GdkGC
*gc
= gdk_gc_new(widget
->window
);
1927 GdkColor color
[2] = { {0, 0x0000, 0x0000, 0x0000},
1928 {0, 0xffff, 0xffff, 0xffff}
1930 gdk_color_alloc(gdk_colormap_get_system(), color
);
1931 gdk_color_alloc(gdk_colormap_get_system(), color
+ 1);
1933 gdk_gc_set_foreground(gc
, color
+ 1);
1934 gdk_draw_rectangle(widget
->window
, gc
, TRUE
, ose
->area
.x
, ose
->area
.y
,
1935 ose
->area
.width
, ose
->area
.height
);
1937 gdk_gc_set_foreground(gc
, color
);
1938 gdk_gc_set_background(gc
, color
+ 1);
1939 gdk_draw_layout(widget
->window
, gc
, 0, 0, layout
);
1943 pango_attr_list_unref(attrs
);
1944 g_object_unref(layout
);
1946 errorStatus
= SC_STATUS_FAILURE
;
1951 gboolean
ScintillaGTK::ExposePreedit(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
) {
1952 return sciThis
->ExposePreeditThis(widget
, ose
);
1955 void ScintillaGTK::CommitThis(char *utfVal
) {
1957 //~ fprintf(stderr, "Commit '%s'\n", utfVal);
1958 if (IsUnicodeMode()) {
1959 AddCharUTF(utfVal
, strlen(utfVal
));
1961 const char *source
= CharacterSetID();
1963 Converter
conv(source
, "UTF-8", true);
1965 char localeVal
[4] = "\0\0\0";
1967 size_t inLeft
= strlen(utfVal
);
1968 char *pout
= localeVal
;
1969 size_t outLeft
= sizeof(localeVal
);
1970 size_t conversions
= conv
.Convert(&pin
, &inLeft
, &pout
, &outLeft
);
1971 if (conversions
!= ((size_t)(-1))) {
1973 for (int i
= 0; localeVal
[i
]; i
++) {
1974 AddChar(localeVal
[i
]);
1977 fprintf(stderr
, "Conversion failed '%s'\n", utfVal
);
1983 errorStatus
= SC_STATUS_FAILURE
;
1987 void ScintillaGTK::Commit(GtkIMContext
*, char *str
, ScintillaGTK
*sciThis
) {
1988 sciThis
->CommitThis(str
);
1991 void ScintillaGTK::PreeditChangedThis() {
1994 PangoAttrList
*attrs
;
1996 gtk_im_context_get_preedit_string(im_context
, &str
, &attrs
, &cursor_pos
);
1997 if (strlen(str
) > 0) {
1998 PangoLayout
*layout
= gtk_widget_create_pango_layout(PWidget(wText
), str
);
1999 pango_layout_set_attributes(layout
, attrs
);
2002 pango_layout_get_pixel_size(layout
, &w
, &h
);
2003 g_object_unref(layout
);
2006 gdk_window_get_origin((PWidget(wText
))->window
, &x
, &y
);
2008 Point pt
= PointMainCaret();
2014 gtk_window_move(GTK_WINDOW(PWidget(wPreedit
)), x
+ pt
.x
, y
+ pt
.y
);
2015 gtk_window_resize(GTK_WINDOW(PWidget(wPreedit
)), w
, h
);
2016 gtk_widget_show(PWidget(wPreedit
));
2017 gtk_widget_queue_draw_area(PWidget(wPreeditDraw
), 0, 0, w
, h
);
2019 gtk_widget_hide(PWidget(wPreedit
));
2022 pango_attr_list_unref(attrs
);
2024 errorStatus
= SC_STATUS_FAILURE
;
2028 void ScintillaGTK::PreeditChanged(GtkIMContext
*, ScintillaGTK
*sciThis
) {
2029 sciThis
->PreeditChangedThis();
2032 gint
ScintillaGTK::StyleSetText(GtkWidget
*widget
, GtkStyle
*, void*) {
2033 if (widget
->window
!= NULL
)
2034 gdk_window_set_back_pixmap(widget
->window
, NULL
, FALSE
);
2038 gint
ScintillaGTK::RealizeText(GtkWidget
*widget
, void*) {
2039 if (widget
->window
!= NULL
)
2040 gdk_window_set_back_pixmap(widget
->window
, NULL
, FALSE
);
2044 void ScintillaGTK::Destroy(GObject
*object
) {
2046 ScintillaObject
*scio
= reinterpret_cast<ScintillaObject
*>(object
);
2047 // This avoids a double destruction
2050 ScintillaGTK
*sciThis
= reinterpret_cast<ScintillaGTK
*>(scio
->pscin
);
2051 //Platform::DebugPrintf("Destroying %x %x\n", sciThis, object);
2052 sciThis
->Finalise();
2057 // Its dead so nowhere to save the status
2061 static void DrawChild(GtkWidget
*widget
, GdkRectangle
*area
) {
2062 GdkRectangle areaIntersect
;
2064 GTK_WIDGET_DRAWABLE(widget
) &&
2065 gtk_widget_intersect(widget
, area
, &areaIntersect
)) {
2066 gtk_widget_draw(widget
, &areaIntersect
);
2070 void ScintillaGTK::Draw(GtkWidget
*widget
, GdkRectangle
*area
) {
2071 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2073 //Platform::DebugPrintf("Draw %p %0d,%0d %0d,%0d\n", widget, area->x, area->y, area->width, area->height);
2074 PRectangle
rcPaint(area
->x
, area
->y
, area
->x
+ area
->width
, area
->y
+ area
->height
);
2075 sciThis
->SyncPaint(rcPaint
);
2076 if (GTK_WIDGET_DRAWABLE(PWidget(sciThis
->wMain
))) {
2077 DrawChild(PWidget(sciThis
->scrollbarh
), area
);
2078 DrawChild(PWidget(sciThis
->scrollbarv
), area
);
2081 Point pt
= sciThis
->PointMainCaret();
2082 pt
.y
+= sciThis
->vs
.lineHeight
- 2;
2083 if (pt
.x
< 0) pt
.x
= 0;
2084 if (pt
.y
< 0) pt
.y
= 0;
2085 CursorMoved(widget
, pt
.x
, pt
.y
, sciThis
);
2087 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2091 gint
ScintillaGTK::ExposeTextThis(GtkWidget
* /*widget*/, GdkEventExpose
*ose
) {
2093 paintState
= painting
;
2095 rcPaint
.left
= ose
->area
.x
;
2096 rcPaint
.top
= ose
->area
.y
;
2097 rcPaint
.right
= ose
->area
.x
+ ose
->area
.width
;
2098 rcPaint
.bottom
= ose
->area
.y
+ ose
->area
.height
;
2100 PLATFORM_ASSERT(rgnUpdate
== NULL
);
2101 rgnUpdate
= gdk_region_copy(ose
->region
);
2102 PRectangle rcClient
= GetClientRectangle();
2103 paintingAllText
= rcPaint
.Contains(rcClient
);
2104 Surface
*surfaceWindow
= Surface::Allocate();
2105 if (surfaceWindow
) {
2106 surfaceWindow
->Init(PWidget(wText
)->window
, PWidget(wText
));
2107 Paint(surfaceWindow
, rcPaint
);
2108 surfaceWindow
->Release();
2109 delete surfaceWindow
;
2111 if (paintState
== paintAbandoned
) {
2112 // Painting area was insufficient to cover new styling or brace highlight positions
2115 paintState
= notPainting
;
2118 gdk_region_destroy(rgnUpdate
);
2122 errorStatus
= SC_STATUS_FAILURE
;
2128 gint
ScintillaGTK::ExposeText(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
) {
2129 return sciThis
->ExposeTextThis(widget
, ose
);
2132 gint
ScintillaGTK::ExposeMain(GtkWidget
*widget
, GdkEventExpose
*ose
) {
2133 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2134 //Platform::DebugPrintf("Expose Main %0d,%0d %0d,%0d\n",
2135 //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2136 return sciThis
->Expose(widget
, ose
);
2139 gint
ScintillaGTK::Expose(GtkWidget
*, GdkEventExpose
*ose
) {
2141 //fprintf(stderr, "Expose %0d,%0d %0d,%0d\n",
2142 //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2144 // The text is painted in ExposeText
2145 gtk_container_propagate_expose(
2146 GTK_CONTAINER(PWidget(wMain
)), PWidget(scrollbarh
), ose
);
2147 gtk_container_propagate_expose(
2148 GTK_CONTAINER(PWidget(wMain
)), PWidget(scrollbarv
), ose
);
2151 errorStatus
= SC_STATUS_FAILURE
;
2156 void ScintillaGTK::ScrollSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
) {
2158 sciThis
->ScrollTo(static_cast<int>(adj
->value
), false);
2160 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2164 void ScintillaGTK::ScrollHSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
) {
2166 sciThis
->HorizontalScrollTo(static_cast<int>(adj
->value
* 2));
2168 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2172 void ScintillaGTK::SelectionReceived(GtkWidget
*widget
,
2173 GtkSelectionData
*selection_data
, guint
) {
2174 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2175 //Platform::DebugPrintf("Selection received\n");
2176 sciThis
->ReceivedSelection(selection_data
);
2179 void ScintillaGTK::SelectionGet(GtkWidget
*widget
,
2180 GtkSelectionData
*selection_data
, guint info
, guint
) {
2181 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2183 //Platform::DebugPrintf("Selection get\n");
2184 if (selection_data
->selection
== GDK_SELECTION_PRIMARY
) {
2185 if (sciThis
->primary
.s
== NULL
) {
2186 sciThis
->CopySelectionRange(&sciThis
->primary
);
2188 sciThis
->GetSelection(selection_data
, info
, &sciThis
->primary
);
2190 #ifndef USE_GTK_CLIPBOARD
2192 sciThis
->GetSelection(selection_data
, info
, &sciThis
->copyText
);
2196 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2200 gint
ScintillaGTK::SelectionClear(GtkWidget
*widget
, GdkEventSelection
*selection_event
) {
2201 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2202 //Platform::DebugPrintf("Selection clear\n");
2203 sciThis
->UnclaimSelection(selection_event
);
2204 return gtk_selection_clear(widget
, selection_event
);
2207 void ScintillaGTK::DragBegin(GtkWidget
*, GdkDragContext
*) {
2208 //Platform::DebugPrintf("DragBegin\n");
2211 gboolean
ScintillaGTK::DragMotionThis(GdkDragContext
*context
,
2212 gint x
, gint y
, guint dragtime
) {
2215 SetDragPosition(SPositionFromLocation(npt
, false, false, UserVirtualSpace()));
2216 GdkDragAction preferredAction
= context
->suggested_action
;
2217 SelectionPosition pos
= SPositionFromLocation(npt
);
2218 if ((inDragDrop
== ddDragging
) && (PositionInSelection(pos
.Position()))) {
2219 // Avoid dragging selection onto itself as that produces a move
2220 // with no real effect but which creates undo actions.
2221 preferredAction
= static_cast<GdkDragAction
>(0);
2222 } else if (context
->actions
== static_cast<GdkDragAction
>
2223 (GDK_ACTION_COPY
| GDK_ACTION_MOVE
)) {
2224 preferredAction
= GDK_ACTION_MOVE
;
2226 gdk_drag_status(context
, preferredAction
, dragtime
);
2228 errorStatus
= SC_STATUS_FAILURE
;
2233 gboolean
ScintillaGTK::DragMotion(GtkWidget
*widget
, GdkDragContext
*context
,
2234 gint x
, gint y
, guint dragtime
) {
2235 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2236 return sciThis
->DragMotionThis(context
, x
, y
, dragtime
);
2239 void ScintillaGTK::DragLeave(GtkWidget
*widget
, GdkDragContext
* /*context*/, guint
) {
2240 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2242 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2243 //Platform::DebugPrintf("DragLeave %x\n", sciThis);
2245 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2249 void ScintillaGTK::DragEnd(GtkWidget
*widget
, GdkDragContext
* /*context*/) {
2250 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2252 // If drag did not result in drop here or elsewhere
2253 if (!sciThis
->dragWasDropped
)
2254 sciThis
->SetEmptySelection(sciThis
->posDrag
);
2255 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2256 //Platform::DebugPrintf("DragEnd %x %d\n", sciThis, sciThis->dragWasDropped);
2257 sciThis
->inDragDrop
= ddNone
;
2259 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2263 gboolean
ScintillaGTK::Drop(GtkWidget
*widget
, GdkDragContext
* /*context*/,
2264 gint
, gint
, guint
) {
2265 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2267 //Platform::DebugPrintf("Drop %x\n", sciThis);
2268 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2270 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2275 void ScintillaGTK::DragDataReceived(GtkWidget
*widget
, GdkDragContext
* /*context*/,
2276 gint
, gint
, GtkSelectionData
*selection_data
, guint
/*info*/, guint
) {
2277 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2279 sciThis
->ReceivedDrop(selection_data
);
2280 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2282 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2286 void ScintillaGTK::DragDataGet(GtkWidget
*widget
, GdkDragContext
*context
,
2287 GtkSelectionData
*selection_data
, guint info
, guint
) {
2288 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2290 sciThis
->dragWasDropped
= true;
2291 if (!sciThis
->sel
.Empty()) {
2292 sciThis
->GetSelection(selection_data
, info
, &sciThis
->drag
);
2294 if (context
->action
== GDK_ACTION_MOVE
) {
2295 for (size_t r
=0; r
<sciThis
->sel
.Count(); r
++) {
2296 if (sciThis
->posDrop
>= sciThis
->sel
.Range(r
).Start()) {
2297 if (sciThis
->posDrop
> sciThis
->sel
.Range(r
).End()) {
2298 sciThis
->posDrop
.Add(-sciThis
->sel
.Range(r
).Length());
2300 sciThis
->posDrop
.Add(-SelectionRange(sciThis
->posDrop
, sciThis
->sel
.Range(r
).Start()).Length());
2304 sciThis
->ClearSelection();
2306 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2308 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2312 int ScintillaGTK::TimeOut(ScintillaGTK
*sciThis
) {
2317 gboolean
ScintillaGTK::IdleCallback(ScintillaGTK
*sciThis
) {
2318 // Idler will be automatically stopped, if there is nothing
2319 // to do while idle.
2320 bool ret
= sciThis
->Idle();
2322 // FIXME: This will remove the idler from GTK, we don't want to
2323 // remove it as it is removed automatically when this function
2324 // returns false (although, it should be harmless).
2325 sciThis
->SetIdle(false);
2330 gboolean
ScintillaGTK::StyleIdle(ScintillaGTK
*sciThis
) {
2331 sciThis
->IdleStyling();
2332 // Idler will be automatically stopped
2336 void ScintillaGTK::QueueStyling(int upTo
) {
2337 Editor::QueueStyling(upTo
);
2338 if (!styleNeeded
.active
) {
2339 // Only allow one style needed to be queued
2340 styleNeeded
.active
= true;
2341 g_idle_add_full(G_PRIORITY_HIGH_IDLE
,
2342 reinterpret_cast<GSourceFunc
>(StyleIdle
), this, NULL
);
2346 void ScintillaGTK::PopUpCB(ScintillaGTK
*sciThis
, guint action
, GtkWidget
*) {
2348 sciThis
->Command(action
);
2352 gint
ScintillaGTK::PressCT(GtkWidget
*widget
, GdkEventButton
*event
, ScintillaGTK
*sciThis
) {
2354 if (event
->window
!= widget
->window
)
2356 if (event
->type
!= GDK_BUTTON_PRESS
)
2359 pt
.x
= int(event
->x
);
2360 pt
.y
= int(event
->y
);
2361 sciThis
->ct
.MouseClick(pt
);
2362 sciThis
->CallTipClick();
2368 gint
ScintillaGTK::ExposeCT(GtkWidget
*widget
, GdkEventExpose
* /*ose*/, CallTip
*ctip
) {
2370 Surface
*surfaceWindow
= Surface::Allocate();
2371 if (surfaceWindow
) {
2372 surfaceWindow
->Init(widget
->window
, widget
);
2373 surfaceWindow
->SetUnicodeMode(SC_CP_UTF8
== ctip
->codePage
);
2374 surfaceWindow
->SetDBCSMode(ctip
->codePage
);
2375 ctip
->PaintCT(surfaceWindow
);
2376 surfaceWindow
->Release();
2377 delete surfaceWindow
;
2380 // No pointer back to Scintilla to save status
2385 sptr_t
ScintillaGTK::DirectFunction(
2386 ScintillaGTK
*sciThis
, unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
2387 return sciThis
->WndProc(iMessage
, wParam
, lParam
);
2390 sptr_t
scintilla_send_message(ScintillaObject
*sci
, unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
2391 ScintillaGTK
*psci
= reinterpret_cast<ScintillaGTK
*>(sci
->pscin
);
2392 return psci
->WndProc(iMessage
, wParam
, lParam
);
2395 static void scintilla_class_init(ScintillaClass
*klass
);
2396 static void scintilla_init(ScintillaObject
*sci
);
2398 extern void Platform_Initialise();
2399 extern void Platform_Finalise();
2401 GType
scintilla_get_type() {
2402 static GType scintilla_type
= 0;
2405 if (!scintilla_type
) {
2406 scintilla_type
= g_type_from_name("Scintilla");
2407 if (!scintilla_type
) {
2408 static GTypeInfo scintilla_info
= {
2409 (guint16
) sizeof (ScintillaClass
),
2410 NULL
, //(GBaseInitFunc)
2411 NULL
, //(GBaseFinalizeFunc)
2412 (GClassInitFunc
) scintilla_class_init
,
2413 NULL
, //(GClassFinalizeFunc)
2414 NULL
, //gconstpointer data
2415 (guint16
) sizeof (ScintillaObject
),
2417 (GInstanceInitFunc
) scintilla_init
,
2418 NULL
//(GTypeValueTable*)
2421 scintilla_type
= g_type_register_static(
2422 GTK_TYPE_CONTAINER
, "Scintilla", &scintilla_info
, (GTypeFlags
) 0);
2428 return scintilla_type
;
2431 void ScintillaGTK::ClassInit(OBJECT_CLASS
* object_class
, GtkWidgetClass
*widget_class
, GtkContainerClass
*container_class
) {
2432 Platform_Initialise();
2433 atomClipboard
= gdk_atom_intern("CLIPBOARD", FALSE
);
2434 atomUTF8
= gdk_atom_intern("UTF8_STRING", FALSE
);
2435 atomString
= GDK_SELECTION_TYPE_STRING
;
2436 atomUriList
= gdk_atom_intern("text/uri-list", FALSE
);
2437 atomDROPFILES_DND
= gdk_atom_intern("DROPFILES_DND", FALSE
);
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
->finalize
= Destroy
;
2444 widget_class
->size_request
= SizeRequest
;
2445 widget_class
->size_allocate
= SizeAllocate
;
2446 widget_class
->expose_event
= ExposeMain
;
2447 widget_class
->motion_notify_event
= Motion
;
2448 widget_class
->button_press_event
= Press
;
2449 widget_class
->button_release_event
= MouseRelease
;
2450 widget_class
->scroll_event
= ScrollEvent
;
2451 widget_class
->key_press_event
= KeyPress
;
2452 widget_class
->key_release_event
= KeyRelease
;
2453 widget_class
->focus_in_event
= FocusIn
;
2454 widget_class
->focus_out_event
= FocusOut
;
2455 widget_class
->selection_received
= SelectionReceived
;
2456 widget_class
->selection_get
= SelectionGet
;
2457 widget_class
->selection_clear_event
= SelectionClear
;
2459 widget_class
->drag_data_received
= DragDataReceived
;
2460 widget_class
->drag_motion
= DragMotion
;
2461 widget_class
->drag_leave
= DragLeave
;
2462 widget_class
->drag_end
= DragEnd
;
2463 widget_class
->drag_drop
= Drop
;
2464 widget_class
->drag_data_get
= DragDataGet
;
2466 widget_class
->realize
= Realize
;
2467 widget_class
->unrealize
= UnRealize
;
2468 widget_class
->map
= Map
;
2469 widget_class
->unmap
= UnMap
;
2471 container_class
->forall
= MainForAll
;
2474 #define SIG_MARSHAL scintilla_marshal_NONE__INT_POINTER
2475 #define MARSHAL_ARGUMENTS G_TYPE_INT, G_TYPE_POINTER
2477 static void scintilla_class_init(ScintillaClass
*klass
) {
2479 OBJECT_CLASS
*object_class
= (OBJECT_CLASS
*) klass
;
2480 GtkWidgetClass
*widget_class
= (GtkWidgetClass
*) klass
;
2481 GtkContainerClass
*container_class
= (GtkContainerClass
*) klass
;
2483 GSignalFlags sigflags
= GSignalFlags(G_SIGNAL_ACTION
| G_SIGNAL_RUN_LAST
);
2484 scintilla_signals
[COMMAND_SIGNAL
] = g_signal_new(
2486 G_TYPE_FROM_CLASS(object_class
),
2488 G_STRUCT_OFFSET(ScintillaClass
, command
),
2489 NULL
, //(GSignalAccumulator)
2493 2, MARSHAL_ARGUMENTS
);
2495 scintilla_signals
[NOTIFY_SIGNAL
] = g_signal_new(
2497 G_TYPE_FROM_CLASS(object_class
),
2499 G_STRUCT_OFFSET(ScintillaClass
, notify
),
2504 2, MARSHAL_ARGUMENTS
);
2506 klass
->command
= NULL
;
2507 klass
->notify
= NULL
;
2509 ScintillaGTK::ClassInit(object_class
, widget_class
, container_class
);
2514 static void scintilla_init(ScintillaObject
*sci
) {
2516 GTK_WIDGET_SET_FLAGS(sci
, GTK_CAN_FOCUS
);
2517 sci
->pscin
= new ScintillaGTK(sci
);
2522 GtkWidget
* scintilla_new() {
2523 return GTK_WIDGET(g_object_new(scintilla_get_type(), NULL
));
2526 void scintilla_set_id(ScintillaObject
*sci
, uptr_t id
) {
2527 ScintillaGTK
*psci
= reinterpret_cast<ScintillaGTK
*>(sci
->pscin
);
2531 void scintilla_release_resources(void) {
2533 Platform_Finalise();