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.
18 #include <gdk/gdkkeysyms.h>
27 #include "Scintilla.h"
28 #include "ScintillaWidget.h"
33 #include "SplitVector.h"
34 #include "Partitioning.h"
35 #include "RunStyles.h"
36 #include "ContractionState.h"
37 #include "CellBuffer.h"
40 #include "Indicator.h"
42 #include "LineMarker.h"
44 #include "AutoComplete.h"
45 #include "ViewStyle.h"
46 #include "Decoration.h"
47 #include "CharClassify.h"
49 #include "Selection.h"
50 #include "PositionCache.h"
52 #include "ScintillaBase.h"
53 #include "UniConversion.h"
55 #include "scintilla-marshal.h"
60 #include "LexerModule.h"
61 #include "ExternalLexer.h"
64 #include "Converter.h"
66 #if GTK_CHECK_VERSION(2,20,0)
67 #define IS_WIDGET_REALIZED(w) (gtk_widget_get_realized(GTK_WIDGET(w)))
68 #define IS_WIDGET_MAPPED(w) (gtk_widget_get_mapped(GTK_WIDGET(w)))
69 #define IS_WIDGET_VISIBLE(w) (gtk_widget_get_visible(GTK_WIDGET(w)))
71 #define IS_WIDGET_REALIZED(w) (GTK_WIDGET_REALIZED(w))
72 #define IS_WIDGET_MAPPED(w) (GTK_WIDGET_MAPPED(w))
73 #define IS_WIDGET_VISIBLE(w) (GTK_WIDGET_VISIBLE(w))
76 #if GTK_CHECK_VERSION(2,22,0)
80 static GdkWindow
*WindowFromWidget(GtkWidget
*w
) {
81 #if GTK_CHECK_VERSION(3,0,0)
82 return gtk_widget_get_window(w
);
88 static GdkWindow
*PWindow(const Window
&w
) {
89 GtkWidget
*widget
= reinterpret_cast<GtkWidget
*>(w
.GetID());
90 #if GTK_CHECK_VERSION(3,0,0)
91 return gtk_widget_get_window(widget
);
93 return widget
->window
;
98 // Constant conditional expressions are because of GTK+ headers
99 #pragma warning(disable: 4127)
100 // Ignore unreferenced local functions in GTK+ headers
101 #pragma warning(disable: 4505)
104 #if GTK_CHECK_VERSION(2,6,0)
105 #define USE_GTK_CLIPBOARD
108 #define OBJECT_CLASS GObjectClass
111 using namespace Scintilla
;
114 extern char *UTF8FromLatin1(const char *s
, int &len
);
116 class ScintillaGTK
: public ScintillaBase
{
117 _ScintillaObject
*sci
;
121 GtkAdjustment
*adjustmentv
;
122 GtkAdjustment
*adjustmenth
;
126 // Because clipboard access is asynchronous, copyText is created by Copy
127 #ifndef USE_GTK_CLIPBOARD
128 SelectionText copyText
;
131 SelectionText primary
;
133 GdkEventButton evbtn
;
137 int rectangularSelectionModifier
;
139 GtkWidgetClass
*parentClass
;
141 static GdkAtom atomClipboard
;
142 static GdkAtom atomUTF8
;
143 static GdkAtom atomString
;
144 static GdkAtom atomUriList
;
145 static GdkAtom atomDROPFILES_DND
;
149 CLIPFORMAT cfColumnSelect
;
154 GtkIMContext
*im_context
;
156 // Wheel mouse support
157 unsigned int linesPerScroll
;
158 GTimeVal lastWheelMouseTime
;
159 gint lastWheelMouseDirection
;
160 gint wheelMouseIntensity
;
162 #if GTK_CHECK_VERSION(3,0,0)
163 cairo_rectangle_list_t
*rgnUpdate
;
165 GdkRegion
*rgnUpdate
;
168 // Private so ScintillaGTK objects can not be copied
169 ScintillaGTK(const ScintillaGTK
&);
170 ScintillaGTK
&operator=(const ScintillaGTK
&);
173 ScintillaGTK(_ScintillaObject
*sci_
);
174 virtual ~ScintillaGTK();
175 static void ClassInit(OBJECT_CLASS
* object_class
, GtkWidgetClass
*widget_class
, GtkContainerClass
*container_class
);
177 virtual void Initialise();
178 virtual void Finalise();
179 virtual void DisplayCursor(Window::Cursor c
);
180 virtual bool DragThreshold(Point ptStart
, Point ptNow
);
181 virtual void StartDrag();
182 int TargetAsUTF8(char *text
);
183 int EncodedFromUTF8(char *utf8
, char *encoded
);
184 virtual bool ValidCodePage(int codePage
) const;
185 public: // Public for scintilla_send_message
186 virtual sptr_t
WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
188 virtual sptr_t
DefWndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
189 virtual void SetTicking(bool on
);
190 virtual bool SetIdle(bool on
);
191 virtual void SetMouseCapture(bool on
);
192 virtual bool HaveMouseCapture();
193 virtual bool PaintContains(PRectangle rc
);
195 virtual PRectangle
GetClientRectangle();
196 void SyncPaint(PRectangle rc
);
197 virtual void ScrollText(int linesToMove
);
198 virtual void SetVerticalScrollPos();
199 virtual void SetHorizontalScrollPos();
200 virtual bool ModifyScrollBars(int nMax
, int nPage
);
201 void ReconfigureScrollBars();
202 virtual void NotifyChange();
203 virtual void NotifyFocus(bool focus
);
204 virtual void NotifyParent(SCNotification scn
);
205 void NotifyKey(int key
, int modifiers
);
206 void NotifyURIDropped(const char *list
);
207 const char *CharacterSetID() const;
208 virtual CaseFolder
*CaseFolderForEncoding();
209 virtual std::string
CaseMapString(const std::string
&s
, int caseMapping
);
210 virtual int KeyDefault(int key
, int modifiers
);
211 virtual void CopyToClipboard(const SelectionText
&selectedText
);
213 virtual void Paste();
214 virtual void CreateCallTipWindow(PRectangle rc
);
215 virtual void AddToPopUp(const char *label
, int cmd
= 0, bool enabled
= true);
216 bool OwnPrimarySelection();
217 virtual void ClaimSelection();
218 void GetGtkSelectionText(GtkSelectionData
*selectionData
, SelectionText
&selText
);
219 void ReceivedSelection(GtkSelectionData
*selection_data
);
220 void ReceivedDrop(GtkSelectionData
*selection_data
);
221 static void GetSelection(GtkSelectionData
*selection_data
, guint info
, SelectionText
*selected
);
222 #ifdef USE_GTK_CLIPBOARD
223 void StoreOnClipboard(SelectionText
*clipText
);
224 static void ClipboardGetSelection(GtkClipboard
* clip
, GtkSelectionData
*selection_data
, guint info
, void *data
);
225 static void ClipboardClearSelection(GtkClipboard
* clip
, void *data
);
228 void UnclaimSelection(GdkEventSelection
*selection_event
);
229 void Resize(int width
, int height
);
231 // Callback functions
232 void RealizeThis(GtkWidget
*widget
);
233 static void Realize(GtkWidget
*widget
);
234 void UnRealizeThis(GtkWidget
*widget
);
235 static void UnRealize(GtkWidget
*widget
);
237 static void Map(GtkWidget
*widget
);
239 static void UnMap(GtkWidget
*widget
);
240 gint
FocusInThis(GtkWidget
*widget
);
241 static gint
FocusIn(GtkWidget
*widget
, GdkEventFocus
*event
);
242 gint
FocusOutThis(GtkWidget
*widget
);
243 static gint
FocusOut(GtkWidget
*widget
, GdkEventFocus
*event
);
244 static void SizeRequest(GtkWidget
*widget
, GtkRequisition
*requisition
);
245 static void GetPreferredWidth(GtkWidget
*widget
, gint
*minimalWidth
, gint
*naturalWidth
);
246 static void GetPreferredHeight(GtkWidget
*widget
, gint
*minimalHeight
, gint
*naturalHeight
);
247 static void SizeAllocate(GtkWidget
*widget
, GtkAllocation
*allocation
);
248 #if GTK_CHECK_VERSION(3,0,0)
249 gboolean
DrawTextThis(cairo_t
*cr
);
250 static gboolean
DrawText(GtkWidget
*widget
, cairo_t
*cr
, ScintillaGTK
*sciThis
);
251 gboolean
DrawThis(cairo_t
*cr
);
252 static gboolean
DrawMain(GtkWidget
*widget
, cairo_t
*cr
);
254 gboolean
ExposeTextThis(GtkWidget
*widget
, GdkEventExpose
*ose
);
255 static gboolean
ExposeText(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
);
256 gboolean
Expose(GtkWidget
*widget
, GdkEventExpose
*ose
);
257 static gboolean
ExposeMain(GtkWidget
*widget
, GdkEventExpose
*ose
);
259 static void Draw(GtkWidget
*widget
, GdkRectangle
*area
);
260 void ForAll(GtkCallback callback
, gpointer callback_data
);
261 static void MainForAll(GtkContainer
*container
, gboolean include_internals
, GtkCallback callback
, gpointer callback_data
);
263 static void ScrollSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
);
264 static void ScrollHSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
);
265 gint
PressThis(GdkEventButton
*event
);
266 static gint
Press(GtkWidget
*widget
, GdkEventButton
*event
);
267 static gint
MouseRelease(GtkWidget
*widget
, GdkEventButton
*event
);
268 static gint
ScrollEvent(GtkWidget
*widget
, GdkEventScroll
*event
);
269 static gint
Motion(GtkWidget
*widget
, GdkEventMotion
*event
);
270 gboolean
KeyThis(GdkEventKey
*event
);
271 static gboolean
KeyPress(GtkWidget
*widget
, GdkEventKey
*event
);
272 static gboolean
KeyRelease(GtkWidget
*widget
, GdkEventKey
*event
);
273 gboolean
ExposePreeditThis(GtkWidget
*widget
, GdkEventExpose
*ose
);
274 static gboolean
ExposePreedit(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
);
275 void CommitThis(char *str
);
276 static void Commit(GtkIMContext
*context
, char *str
, ScintillaGTK
*sciThis
);
277 void PreeditChangedThis();
278 static void PreeditChanged(GtkIMContext
*context
, ScintillaGTK
*sciThis
);
279 static void StyleSetText(GtkWidget
*widget
, GtkStyle
*previous
, void*);
280 static void RealizeText(GtkWidget
*widget
, void*);
281 static void Destroy(GObject
*object
);
282 static void SelectionReceived(GtkWidget
*widget
, GtkSelectionData
*selection_data
,
284 static void SelectionGet(GtkWidget
*widget
, GtkSelectionData
*selection_data
,
285 guint info
, guint time
);
286 static gint
SelectionClear(GtkWidget
*widget
, GdkEventSelection
*selection_event
);
287 static void DragBegin(GtkWidget
*widget
, GdkDragContext
*context
);
288 gboolean
DragMotionThis(GdkDragContext
*context
, gint x
, gint y
, guint dragtime
);
289 static gboolean
DragMotion(GtkWidget
*widget
, GdkDragContext
*context
,
290 gint x
, gint y
, guint dragtime
);
291 static void DragLeave(GtkWidget
*widget
, GdkDragContext
*context
,
293 static void DragEnd(GtkWidget
*widget
, GdkDragContext
*context
);
294 static gboolean
Drop(GtkWidget
*widget
, GdkDragContext
*context
,
295 gint x
, gint y
, guint time
);
296 static void DragDataReceived(GtkWidget
*widget
, GdkDragContext
*context
,
297 gint x
, gint y
, GtkSelectionData
*selection_data
, guint info
, guint time
);
298 static void DragDataGet(GtkWidget
*widget
, GdkDragContext
*context
,
299 GtkSelectionData
*selection_data
, guint info
, guint time
);
300 static gboolean
TimeOut(ScintillaGTK
*sciThis
);
301 static gboolean
IdleCallback(ScintillaGTK
*sciThis
);
302 static gboolean
StyleIdle(ScintillaGTK
*sciThis
);
303 virtual void QueueStyling(int upTo
);
304 static void PopUpCB(GtkMenuItem
*menuItem
, ScintillaGTK
*sciThis
);
306 #if GTK_CHECK_VERSION(3,0,0)
307 static gboolean
DrawCT(GtkWidget
*widget
, cairo_t
*cr
, CallTip
*ctip
);
309 static gboolean
ExposeCT(GtkWidget
*widget
, GdkEventExpose
*ose
, CallTip
*ct
);
311 static gboolean
PressCT(GtkWidget
*widget
, GdkEventButton
*event
, ScintillaGTK
*sciThis
);
313 static sptr_t
DirectFunction(ScintillaGTK
*sciThis
,
314 unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
323 static gint scintilla_signals
[LAST_SIGNAL
] = { 0 };
328 TARGET_COMPOUND_TEXT
,
333 GdkAtom
ScintillaGTK::atomClipboard
= 0;
334 GdkAtom
ScintillaGTK::atomUTF8
= 0;
335 GdkAtom
ScintillaGTK::atomString
= 0;
336 GdkAtom
ScintillaGTK::atomUriList
= 0;
337 GdkAtom
ScintillaGTK::atomDROPFILES_DND
= 0;
339 static const GtkTargetEntry clipboardCopyTargets
[] = {
340 { (gchar
*) "UTF8_STRING", 0, TARGET_UTF8_STRING
},
341 { (gchar
*) "STRING", 0, TARGET_STRING
},
343 static const gint nClipboardCopyTargets
= sizeof(clipboardCopyTargets
) / sizeof(clipboardCopyTargets
[0]);
345 static const GtkTargetEntry clipboardPasteTargets
[] = {
346 { (gchar
*) "text/uri-list", 0, TARGET_URI
},
347 { (gchar
*) "UTF8_STRING", 0, TARGET_UTF8_STRING
},
348 { (gchar
*) "STRING", 0, TARGET_STRING
},
350 static const gint nClipboardPasteTargets
= sizeof(clipboardPasteTargets
) / sizeof(clipboardPasteTargets
[0]);
352 static GtkWidget
*PWidget(Window
&w
) {
353 return reinterpret_cast<GtkWidget
*>(w
.GetID());
356 static ScintillaGTK
*ScintillaFromWidget(GtkWidget
*widget
) {
357 ScintillaObject
*scio
= reinterpret_cast<ScintillaObject
*>(widget
);
358 return reinterpret_cast<ScintillaGTK
*>(scio
->pscin
);
361 ScintillaGTK::ScintillaGTK(_ScintillaObject
*sci_
) :
362 adjustmentv(0), adjustmenth(0),
363 scrollBarWidth(30), scrollBarHeight(30),
364 capturedMouse(false), dragWasDropped(false),
365 lastKey(0), rectangularSelectionModifier(SCMOD_CTRL
), parentClass(0),
367 lastWheelMouseDirection(0),
368 wheelMouseIntensity(0),
371 wMain
= GTK_WIDGET(sci
);
374 rectangularSelectionModifier
= SCMOD_ALT
;
376 rectangularSelectionModifier
= SCMOD_CTRL
;
380 // There does not seem to be a real standard for indicating that the clipboard
381 // contains a rectangular selection, so copy Developer Studio.
382 cfColumnSelect
= static_cast<CLIPFORMAT
>(
383 ::RegisterClipboardFormat("MSDEVColumnSelect"));
385 // Get intellimouse parameters when running on win32; otherwise use
386 // reasonable default
387 #ifndef SPI_GETWHEELSCROLLLINES
388 #define SPI_GETWHEELSCROLLLINES 104
390 ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &linesPerScroll
, 0);
394 lastWheelMouseTime
.tv_sec
= 0;
395 lastWheelMouseTime
.tv_usec
= 0;
400 ScintillaGTK::~ScintillaGTK() {
401 g_idle_remove_by_data(this);
404 void ScintillaGTK::RealizeThis(GtkWidget
*widget
) {
405 //Platform::DebugPrintf("ScintillaGTK::realize this\n");
406 #if GTK_CHECK_VERSION(2,20,0)
407 gtk_widget_set_realized(widget
, TRUE
);
409 GTK_WIDGET_SET_FLAGS(widget
, GTK_REALIZED
);
412 attrs
.window_type
= GDK_WINDOW_CHILD
;
413 GtkAllocation allocation
;
414 #if GTK_CHECK_VERSION(3,0,0)
415 gtk_widget_get_allocation(widget
, &allocation
);
417 allocation
= widget
->allocation
;
419 attrs
.x
= allocation
.x
;
420 attrs
.y
= allocation
.y
;
421 attrs
.width
= allocation
.width
;
422 attrs
.height
= allocation
.height
;
423 attrs
.wclass
= GDK_INPUT_OUTPUT
;
424 attrs
.visual
= gtk_widget_get_visual(widget
);
425 #if !GTK_CHECK_VERSION(3,0,0)
426 attrs
.colormap
= gtk_widget_get_colormap(widget
);
428 attrs
.event_mask
= gtk_widget_get_events(widget
) | GDK_EXPOSURE_MASK
;
429 GdkCursor
*cursor
= gdk_cursor_new(GDK_XTERM
);
430 attrs
.cursor
= cursor
;
431 #if GTK_CHECK_VERSION(3,0,0)
432 gtk_widget_set_window(widget
, gdk_window_new(gtk_widget_get_parent_window(widget
), &attrs
,
433 GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
| GDK_WA_CURSOR
));
434 gdk_window_set_user_data(gtk_widget_get_window(widget
), widget
);
435 gdk_window_set_background(gtk_widget_get_window(widget
),
436 &(gtk_widget_get_style(widget
)->bg
[GTK_STATE_NORMAL
]));
437 gdk_window_show(gtk_widget_get_window(widget
));
438 gdk_cursor_unref(cursor
);
439 // Deprecated: should chain up to parent class' "realize" implementation
440 gtk_widget_style_attach(widget
);
442 widget
->window
= gdk_window_new(gtk_widget_get_parent_window(widget
), &attrs
,
443 GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
| GDK_WA_COLORMAP
| GDK_WA_CURSOR
);
444 gdk_window_set_user_data(widget
->window
, widget
);
445 gdk_window_set_background(widget
->window
, &widget
->style
->bg
[GTK_STATE_NORMAL
]);
446 gdk_window_show(widget
->window
);
447 gdk_cursor_unref(cursor
);
448 widget
->style
= gtk_style_attach(widget
->style
, widget
->window
);
450 wPreedit
= gtk_window_new(GTK_WINDOW_POPUP
);
451 wPreeditDraw
= gtk_drawing_area_new();
452 GtkWidget
*predrw
= PWidget(wPreeditDraw
); // No code inside the G_OBJECT macro
453 #if !GTK_CHECK_VERSION(3,0,0)
454 g_signal_connect(G_OBJECT(predrw
), "expose_event",
455 G_CALLBACK(ExposePreedit
), this);
457 gtk_container_add(GTK_CONTAINER(PWidget(wPreedit
)), predrw
);
458 gtk_widget_realize(PWidget(wPreedit
));
459 gtk_widget_realize(predrw
);
460 gtk_widget_show(predrw
);
462 im_context
= gtk_im_multicontext_new();
463 g_signal_connect(G_OBJECT(im_context
), "commit",
464 G_CALLBACK(Commit
), this);
465 g_signal_connect(G_OBJECT(im_context
), "preedit_changed",
466 G_CALLBACK(PreeditChanged
), this);
467 gtk_im_context_set_client_window(im_context
, WindowFromWidget(widget
));
468 GtkWidget
*widtxt
= PWidget(wText
); // // No code inside the G_OBJECT macro
469 g_signal_connect_after(G_OBJECT(widtxt
), "style_set",
470 G_CALLBACK(ScintillaGTK::StyleSetText
), NULL
);
471 g_signal_connect_after(G_OBJECT(widtxt
), "realize",
472 G_CALLBACK(ScintillaGTK::RealizeText
), NULL
);
473 gtk_widget_realize(widtxt
);
474 gtk_widget_realize(PWidget(scrollbarv
));
475 gtk_widget_realize(PWidget(scrollbarh
));
477 cursor
= gdk_cursor_new(GDK_XTERM
);
478 gdk_window_set_cursor(PWindow(wText
), cursor
);
479 gdk_cursor_unref(cursor
);
481 cursor
= gdk_cursor_new(GDK_LEFT_PTR
);
482 gdk_window_set_cursor(PWindow(scrollbarv
), cursor
);
483 gdk_cursor_unref(cursor
);
485 cursor
= gdk_cursor_new(GDK_LEFT_PTR
);
486 gdk_window_set_cursor(PWindow(scrollbarh
), cursor
);
487 gdk_cursor_unref(cursor
);
489 gtk_selection_add_targets(widget
, GDK_SELECTION_PRIMARY
,
490 clipboardCopyTargets
, nClipboardCopyTargets
);
491 #ifndef USE_GTK_CLIPBOARD
492 gtk_selection_add_targets(widget
, atomClipboard
,
493 clipboardPasteTargets
, nClipboardPasteTargets
);
497 void ScintillaGTK::Realize(GtkWidget
*widget
) {
498 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
499 sciThis
->RealizeThis(widget
);
502 void ScintillaGTK::UnRealizeThis(GtkWidget
*widget
) {
504 gtk_selection_clear_targets(widget
, GDK_SELECTION_PRIMARY
);
505 #ifndef USE_GTK_CLIPBOARD
506 gtk_selection_clear_targets(widget
, atomClipboard
);
509 if (IS_WIDGET_MAPPED(widget
)) {
510 gtk_widget_unmap(widget
);
512 #if GTK_CHECK_VERSION(2,20,0)
513 gtk_widget_set_realized(widget
, FALSE
);
515 GTK_WIDGET_UNSET_FLAGS(widget
, GTK_REALIZED
);
517 gtk_widget_unrealize(PWidget(wText
));
518 gtk_widget_unrealize(PWidget(scrollbarv
));
519 gtk_widget_unrealize(PWidget(scrollbarh
));
520 gtk_widget_unrealize(PWidget(wPreedit
));
521 gtk_widget_unrealize(PWidget(wPreeditDraw
));
522 g_object_unref(im_context
);
524 if (GTK_WIDGET_CLASS(parentClass
)->unrealize
)
525 GTK_WIDGET_CLASS(parentClass
)->unrealize(widget
);
529 errorStatus
= SC_STATUS_FAILURE
;
533 void ScintillaGTK::UnRealize(GtkWidget
*widget
) {
534 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
535 sciThis
->UnRealizeThis(widget
);
538 static void MapWidget(GtkWidget
*widget
) {
540 IS_WIDGET_VISIBLE(widget
) &&
541 !IS_WIDGET_MAPPED(widget
)) {
542 gtk_widget_map(widget
);
546 void ScintillaGTK::MapThis() {
548 //Platform::DebugPrintf("ScintillaGTK::map this\n");
549 #if GTK_CHECK_VERSION(2,20,0)
550 gtk_widget_set_mapped(PWidget(wMain
), TRUE
);
552 GTK_WIDGET_SET_FLAGS(PWidget(wMain
), GTK_MAPPED
);
554 MapWidget(PWidget(wText
));
555 MapWidget(PWidget(scrollbarh
));
556 MapWidget(PWidget(scrollbarv
));
557 wMain
.SetCursor(Window::cursorArrow
);
558 scrollbarv
.SetCursor(Window::cursorArrow
);
559 scrollbarh
.SetCursor(Window::cursorArrow
);
561 gdk_window_show(PWindow(wMain
));
563 errorStatus
= SC_STATUS_FAILURE
;
567 void ScintillaGTK::Map(GtkWidget
*widget
) {
568 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
572 void ScintillaGTK::UnMapThis() {
574 //Platform::DebugPrintf("ScintillaGTK::unmap this\n");
575 #if GTK_CHECK_VERSION(2,20,0)
576 gtk_widget_set_mapped(PWidget(wMain
), FALSE
);
578 GTK_WIDGET_UNSET_FLAGS(PWidget(wMain
), GTK_MAPPED
);
581 gdk_window_hide(PWindow(wMain
));
582 gtk_widget_unmap(PWidget(wText
));
583 gtk_widget_unmap(PWidget(scrollbarh
));
584 gtk_widget_unmap(PWidget(scrollbarv
));
586 errorStatus
= SC_STATUS_FAILURE
;
590 void ScintillaGTK::UnMap(GtkWidget
*widget
) {
591 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
592 sciThis
->UnMapThis();
595 void ScintillaGTK::ForAll(GtkCallback callback
, gpointer callback_data
) {
597 (*callback
) (PWidget(wText
), callback_data
);
598 (*callback
) (PWidget(scrollbarv
), callback_data
);
599 (*callback
) (PWidget(scrollbarh
), callback_data
);
601 errorStatus
= SC_STATUS_FAILURE
;
605 void ScintillaGTK::MainForAll(GtkContainer
*container
, gboolean include_internals
, GtkCallback callback
, gpointer callback_data
) {
606 ScintillaGTK
*sciThis
= ScintillaFromWidget((GtkWidget
*)container
);
608 if (callback
!= NULL
&& include_internals
) {
609 sciThis
->ForAll(callback
, callback_data
);
613 gint
ScintillaGTK::FocusInThis(GtkWidget
*widget
) {
616 if (im_context
!= NULL
) {
620 gtk_im_context_get_preedit_string(im_context
, &str
, NULL
, &cursor_pos
);
621 if (PWidget(wPreedit
) != NULL
) {
622 if (strlen(str
) > 0) {
623 gtk_widget_show(PWidget(wPreedit
));
625 gtk_widget_hide(PWidget(wPreedit
));
629 gtk_im_context_focus_in(im_context
);
633 errorStatus
= SC_STATUS_FAILURE
;
638 gint
ScintillaGTK::FocusIn(GtkWidget
*widget
, GdkEventFocus
* /*event*/) {
639 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
640 return sciThis
->FocusInThis(widget
);
643 gint
ScintillaGTK::FocusOutThis(GtkWidget
*widget
) {
645 SetFocusState(false);
647 if (PWidget(wPreedit
) != NULL
)
648 gtk_widget_hide(PWidget(wPreedit
));
649 if (im_context
!= NULL
)
650 gtk_im_context_focus_out(im_context
);
653 errorStatus
= SC_STATUS_FAILURE
;
658 gint
ScintillaGTK::FocusOut(GtkWidget
*widget
, GdkEventFocus
* /*event*/) {
659 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
660 return sciThis
->FocusOutThis(widget
);
663 void ScintillaGTK::SizeRequest(GtkWidget
*widget
, GtkRequisition
*requisition
) {
664 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
665 requisition
->width
= 1;
666 requisition
->height
= 1;
667 GtkRequisition child_requisition
;
668 #if GTK_CHECK_VERSION(3,0,0)
669 gtk_widget_get_preferred_size(PWidget(sciThis
->scrollbarh
), NULL
, &child_requisition
);
670 gtk_widget_get_preferred_size(PWidget(sciThis
->scrollbarv
), NULL
, &child_requisition
);
672 gtk_widget_size_request(PWidget(sciThis
->scrollbarh
), &child_requisition
);
673 gtk_widget_size_request(PWidget(sciThis
->scrollbarv
), &child_requisition
);
677 void ScintillaGTK::GetPreferredWidth(GtkWidget
*widget
, gint
*minimalWidth
, gint
*naturalWidth
) {
678 GtkRequisition requisition
;
679 SizeRequest(widget
, &requisition
);
680 *minimalWidth
= *naturalWidth
= requisition
.width
;
683 void ScintillaGTK::GetPreferredHeight(GtkWidget
*widget
, gint
*minimalHeight
, gint
*naturalHeight
) {
684 GtkRequisition requisition
;
685 SizeRequest(widget
, &requisition
);
686 *minimalHeight
= *naturalHeight
= requisition
.height
;
689 void ScintillaGTK::SizeAllocate(GtkWidget
*widget
, GtkAllocation
*allocation
) {
690 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
692 #if GTK_CHECK_VERSION(2,20,0)
693 gtk_widget_set_allocation(widget
, allocation
);
695 widget
->allocation
= *allocation
;
697 if (IS_WIDGET_REALIZED(widget
))
698 gdk_window_move_resize(WindowFromWidget(widget
),
704 sciThis
->Resize(allocation
->width
, allocation
->height
);
707 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
711 void ScintillaGTK::Initialise() {
712 //Platform::DebugPrintf("ScintillaGTK::Initialise\n");
713 parentClass
= reinterpret_cast<GtkWidgetClass
*>(
714 g_type_class_ref(gtk_container_get_type()));
716 #if GTK_CHECK_VERSION(2,20,0)
717 gtk_widget_set_can_focus(PWidget(wMain
), TRUE
);
718 gtk_widget_set_sensitive(PWidget(wMain
), TRUE
);
720 GTK_WIDGET_SET_FLAGS(PWidget(wMain
), GTK_CAN_FOCUS
);
721 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(PWidget(wMain
)), GTK_SENSITIVE
);
723 gtk_widget_set_events(PWidget(wMain
),
727 | GDK_KEY_RELEASE_MASK
728 | GDK_FOCUS_CHANGE_MASK
729 | GDK_LEAVE_NOTIFY_MASK
730 | GDK_BUTTON_PRESS_MASK
731 | GDK_BUTTON_RELEASE_MASK
732 | GDK_POINTER_MOTION_MASK
733 | GDK_POINTER_MOTION_HINT_MASK
);
735 wText
= gtk_drawing_area_new();
736 gtk_widget_set_parent(PWidget(wText
), PWidget(wMain
));
737 GtkWidget
*widtxt
= PWidget(wText
); // No code inside the G_OBJECT macro
738 gtk_widget_show(widtxt
);
739 #if GTK_CHECK_VERSION(3,0,0)
740 g_signal_connect(G_OBJECT(widtxt
), "draw",
741 G_CALLBACK(ScintillaGTK::DrawText
), this);
743 g_signal_connect(G_OBJECT(widtxt
), "expose_event",
744 G_CALLBACK(ScintillaGTK::ExposeText
), this);
746 gtk_widget_set_events(widtxt
, GDK_EXPOSURE_MASK
);
747 // Avoid background drawing flash
748 gtk_widget_set_double_buffered(widtxt
, FALSE
);
749 gtk_widget_set_size_request(widtxt
, 100, 100);
750 adjustmentv
= GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 201.0, 1.0, 20.0, 20.0));
751 scrollbarv
= gtk_vscrollbar_new(GTK_ADJUSTMENT(adjustmentv
));
752 #if GTK_CHECK_VERSION(2,20,0)
753 gtk_widget_set_can_focus(PWidget(scrollbarv
), FALSE
);
755 GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarv
), GTK_CAN_FOCUS
);
757 g_signal_connect(G_OBJECT(adjustmentv
), "value_changed",
758 G_CALLBACK(ScrollSignal
), this);
759 gtk_widget_set_parent(PWidget(scrollbarv
), PWidget(wMain
));
760 gtk_widget_show(PWidget(scrollbarv
));
762 adjustmenth
= GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 101.0, 1.0, 20.0, 20.0));
763 scrollbarh
= gtk_hscrollbar_new(GTK_ADJUSTMENT(adjustmenth
));
764 #if GTK_CHECK_VERSION(2,20,0)
765 gtk_widget_set_can_focus(PWidget(scrollbarh
), FALSE
);
767 GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarh
), GTK_CAN_FOCUS
);
769 g_signal_connect(G_OBJECT(adjustmenth
), "value_changed",
770 G_CALLBACK(ScrollHSignal
), this);
771 gtk_widget_set_parent(PWidget(scrollbarh
), PWidget(wMain
));
772 gtk_widget_show(PWidget(scrollbarh
));
774 gtk_widget_grab_focus(PWidget(wMain
));
776 gtk_drag_dest_set(GTK_WIDGET(PWidget(wMain
)),
777 GTK_DEST_DEFAULT_ALL
, clipboardPasteTargets
, nClipboardPasteTargets
,
778 static_cast<GdkDragAction
>(GDK_ACTION_COPY
| GDK_ACTION_MOVE
));
780 // Set caret period based on GTK settings
781 gboolean blinkOn
= false;
782 if (g_object_class_find_property(G_OBJECT_GET_CLASS(
783 G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink")) {
784 g_object_get(G_OBJECT(
785 gtk_settings_get_default()), "gtk-cursor-blink", &blinkOn
, NULL
);
788 g_object_class_find_property(G_OBJECT_GET_CLASS(
789 G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink-time")) {
791 g_object_get(G_OBJECT(
792 gtk_settings_get_default()), "gtk-cursor-blink-time", &value
, NULL
);
793 caret
.period
= gint(value
/ 1.75);
801 void ScintillaGTK::Finalise() {
803 ScintillaBase::Finalise();
806 void ScintillaGTK::DisplayCursor(Window::Cursor c
) {
807 if (cursorMode
== SC_CURSORNORMAL
)
810 wText
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
813 bool ScintillaGTK::DragThreshold(Point ptStart
, Point ptNow
) {
814 return gtk_drag_check_threshold(GTK_WIDGET(PWidget(wMain
)),
815 ptStart
.x
, ptStart
.y
, ptNow
.x
, ptNow
.y
);
818 void ScintillaGTK::StartDrag() {
819 dragWasDropped
= false;
820 inDragDrop
= ddDragging
;
821 GtkTargetList
*tl
= gtk_target_list_new(clipboardCopyTargets
, nClipboardCopyTargets
);
822 gtk_drag_begin(GTK_WIDGET(PWidget(wMain
)),
824 static_cast<GdkDragAction
>(GDK_ACTION_COPY
| GDK_ACTION_MOVE
),
826 reinterpret_cast<GdkEvent
*>(&evbtn
));
829 static char *ConvertText(int *lenResult
, char *s
, size_t len
, const char *charSetDest
,
830 const char *charSetSource
, bool transliterations
, bool silent
=false) {
831 // s is not const because of different versions of iconv disagreeing about const
834 Converter
conv(charSetDest
, charSetSource
, transliterations
);
836 destForm
= new char[len
*3+1];
839 char *pout
= destForm
;
840 size_t outLeft
= len
*3+1;
841 size_t conversions
= conv
.Convert(&pin
, &inLeft
, &pout
, &outLeft
);
842 if (conversions
== ((size_t)(-1))) {
844 fprintf(stderr
, "iconv %s->%s failed for %s\n",
845 charSetSource
, charSetDest
, static_cast<char *>(s
));
849 //fprintf(stderr, "iconv OK %s %d\n", destForm, pout - destForm);
851 *lenResult
= pout
- destForm
;
854 fprintf(stderr
, "Can not iconv %s %s\n", charSetDest
, charSetSource
);
857 destForm
= new char[1];
864 // Returns the target converted to UTF8.
865 // Return the length in bytes.
866 int ScintillaGTK::TargetAsUTF8(char *text
) {
867 int targetLength
= targetEnd
- targetStart
;
868 if (IsUnicodeMode()) {
870 pdoc
->GetCharRange(text
, targetStart
, targetLength
);
874 const char *charSetBuffer
= CharacterSetID();
875 if (*charSetBuffer
) {
876 //~ fprintf(stderr, "AsUTF8 %s %d %0d-%0d\n", charSetBuffer, targetLength, targetStart, targetEnd);
877 char *s
= new char[targetLength
];
879 pdoc
->GetCharRange(s
, targetStart
, targetLength
);
880 //~ fprintf(stderr, " \"%s\"\n", s);
882 char *tmputf
= ConvertText(&targetLength
, s
, targetLength
, "UTF-8", charSetBuffer
, false);
883 memcpy(text
, tmputf
, targetLength
);
885 //~ fprintf(stderr, " \"%s\"\n", text);
891 pdoc
->GetCharRange(text
, targetStart
, targetLength
);
895 //~ fprintf(stderr, "Length = %d bytes\n", targetLength);
899 // Translates a nul terminated UTF8 string into the document encoding.
900 // Return the length of the result in bytes.
901 int ScintillaGTK::EncodedFromUTF8(char *utf8
, char *encoded
) {
902 int inputLength
= (lengthForEncode
>= 0) ? lengthForEncode
: strlen(utf8
);
903 if (IsUnicodeMode()) {
905 memcpy(encoded
, utf8
, inputLength
);
910 const char *charSetBuffer
= CharacterSetID();
911 if (*charSetBuffer
) {
913 char *tmpEncoded
= ConvertText(&outLength
, utf8
, inputLength
, charSetBuffer
, "UTF-8", true);
916 memcpy(encoded
, tmpEncoded
, outLength
);
923 memcpy(encoded
, utf8
, inputLength
);
932 bool ScintillaGTK::ValidCodePage(int codePage
) const {
934 || codePage
== SC_CP_UTF8
942 sptr_t
ScintillaGTK::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
947 gtk_widget_grab_focus(PWidget(wMain
));
950 case SCI_GETDIRECTFUNCTION
:
951 return reinterpret_cast<sptr_t
>(DirectFunction
);
953 case SCI_GETDIRECTPOINTER
:
954 return reinterpret_cast<sptr_t
>(this);
957 case SCI_LOADLEXERLIBRARY
:
958 LexerManager::GetInstance()->Load(reinterpret_cast<const char*>(lParam
));
961 case SCI_TARGETASUTF8
:
962 return TargetAsUTF8(reinterpret_cast<char*>(lParam
));
964 case SCI_ENCODEDFROMUTF8
:
965 return EncodedFromUTF8(reinterpret_cast<char*>(wParam
),
966 reinterpret_cast<char*>(lParam
));
968 case SCI_SETRECTANGULARSELECTIONMODIFIER
:
969 rectangularSelectionModifier
= wParam
;
972 case SCI_GETRECTANGULARSELECTIONMODIFIER
:
973 return rectangularSelectionModifier
;
976 return ScintillaBase::WndProc(iMessage
, wParam
, lParam
);
978 } catch (std::bad_alloc
&) {
979 errorStatus
= SC_STATUS_BADALLOC
;
981 errorStatus
= SC_STATUS_FAILURE
;
986 sptr_t
ScintillaGTK::DefWndProc(unsigned int, uptr_t
, sptr_t
) {
990 void ScintillaGTK::SetTicking(bool on
) {
991 if (timer
.ticking
!= on
) {
994 timer
.tickerID
= reinterpret_cast<TickerID
>(g_timeout_add(timer
.tickSize
,
995 reinterpret_cast<GSourceFunc
>(TimeOut
), this));
997 g_source_remove(GPOINTER_TO_UINT(timer
.tickerID
));
1000 timer
.ticksToWait
= caret
.period
;
1003 bool ScintillaGTK::SetIdle(bool on
) {
1005 // Start idler, if it's not running.
1008 idler
.idlerID
= reinterpret_cast<IdlerID
>(
1009 g_idle_add_full(G_PRIORITY_DEFAULT_IDLE
,
1010 reinterpret_cast<GSourceFunc
>(IdleCallback
), this, NULL
));
1013 // Stop idler, if it's running
1015 idler
.state
= false;
1016 g_source_remove(GPOINTER_TO_UINT(idler
.idlerID
));
1022 void ScintillaGTK::SetMouseCapture(bool on
) {
1023 if (mouseDownCaptures
) {
1025 gtk_grab_add(GTK_WIDGET(PWidget(wMain
)));
1027 gtk_grab_remove(GTK_WIDGET(PWidget(wMain
)));
1033 bool ScintillaGTK::HaveMouseCapture() {
1034 return capturedMouse
;
1037 #if GTK_CHECK_VERSION(3,0,0)
1039 // Is crcTest completely in crcContainer?
1040 static bool CRectContains(const cairo_rectangle_t
&crcContainer
, const cairo_rectangle_t
&crcTest
) {
1042 (crcTest
.x
>= crcContainer
.x
) && ((crcTest
.x
+ crcTest
.width
) <= (crcContainer
.x
+ crcContainer
.width
)) &&
1043 (crcTest
.y
>= crcContainer
.y
) && ((crcTest
.y
+ crcTest
.height
) <= (crcContainer
.y
+ crcContainer
.height
));
1046 // Is crcTest completely in crcListContainer?
1047 // May incorrectly return false if complex shape
1048 static bool CRectListContains(const cairo_rectangle_list_t
*crcListContainer
, const cairo_rectangle_t
&crcTest
) {
1049 for (int r
=0; r
<crcListContainer
->num_rectangles
; r
++) {
1050 if (CRectContains(crcListContainer
->rectangles
[r
], crcTest
))
1058 bool ScintillaGTK::PaintContains(PRectangle rc
) {
1059 // This allows optimization when a rectangle is completely in the update region.
1060 // It is OK to return false when too difficult to determine as that just performs extra drawing
1061 bool contains
= true;
1062 if (paintState
== painting
) {
1063 if (!rcPaint
.Contains(rc
)) {
1065 } else if (rgnUpdate
) {
1066 #if GTK_CHECK_VERSION(3,0,0)
1067 cairo_rectangle_t grc
= {rc
.left
, rc
.top
,
1068 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
};
1069 contains
= CRectListContains(rgnUpdate
, grc
);
1071 GdkRectangle grc
= {rc
.left
, rc
.top
,
1072 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
};
1073 if (gdk_region_rect_in(rgnUpdate
, &grc
) != GDK_OVERLAP_RECTANGLE_IN
) {
1082 // Redraw all of text area. This paint will not be abandoned.
1083 void ScintillaGTK::FullPaint() {
1084 wText
.InvalidateAll();
1087 PRectangle
ScintillaGTK::GetClientRectangle() {
1088 PRectangle rc
= wMain
.GetClientPosition();
1089 if (verticalScrollBarVisible
)
1090 rc
.right
-= scrollBarWidth
;
1091 if (horizontalScrollBarVisible
&& (wrapState
== eWrapNone
))
1092 rc
.bottom
-= scrollBarHeight
;
1094 rc
.right
-= rc
.left
;
1095 rc
.bottom
-= rc
.top
;
1101 // Synchronously paint a rectangle of the window.
1102 void ScintillaGTK::SyncPaint(PRectangle rc
) {
1103 paintState
= painting
;
1105 PRectangle rcClient
= GetClientRectangle();
1106 paintingAllText
= rcPaint
.Contains(rcClient
);
1107 if (PWindow(wText
)) {
1108 Surface
*sw
= Surface::Allocate();
1110 #if GTK_CHECK_VERSION(3,0,0)
1111 cairo_t
*cr
= gdk_cairo_create(PWindow(wText
));
1112 sw
->Init(cr
, PWidget(wText
));
1114 sw
->Init(PWindow(wText
), PWidget(wText
));
1119 #if GTK_CHECK_VERSION(3,0,0)
1124 if (paintState
== paintAbandoned
) {
1125 // Painting area was insufficient to cover new styling or brace highlight positions
1128 paintState
= notPainting
;
1131 void ScintillaGTK::ScrollText(int linesToMove
) {
1132 int diff
= vs
.lineHeight
* -linesToMove
;
1133 //Platform::DebugPrintf("ScintillaGTK::ScrollText %d %d %0d,%0d %0d,%0d\n", linesToMove, diff,
1134 // rc.left, rc.top, rc.right, rc.bottom);
1135 GtkWidget
*wi
= PWidget(wText
);
1137 gdk_window_scroll(WindowFromWidget(wi
), 0, -diff
);
1138 gdk_window_process_updates(WindowFromWidget(wi
), FALSE
);
1141 void ScintillaGTK::SetVerticalScrollPos() {
1143 gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmentv
), topLine
);
1146 void ScintillaGTK::SetHorizontalScrollPos() {
1148 gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmenth
), xOffset
/ 2);
1151 bool ScintillaGTK::ModifyScrollBars(int nMax
, int nPage
) {
1152 bool modified
= false;
1153 int pageScroll
= LinesToScroll();
1155 #if GTK_CHECK_VERSION(3,0,0)
1156 if (gtk_adjustment_get_upper(adjustmentv
) != (nMax
+ 1) ||
1157 gtk_adjustment_get_page_size(adjustmentv
) != nPage
||
1158 gtk_adjustment_get_page_increment(adjustmentv
) != pageScroll
) {
1159 gtk_adjustment_set_upper(adjustmentv
, nMax
+ 1);
1160 gtk_adjustment_set_page_size(adjustmentv
, nPage
);
1161 gtk_adjustment_set_page_increment(adjustmentv
, pageScroll
);
1162 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv
));
1166 if (GTK_ADJUSTMENT(adjustmentv
)->upper
!= (nMax
+ 1) ||
1167 GTK_ADJUSTMENT(adjustmentv
)->page_size
!= nPage
||
1168 GTK_ADJUSTMENT(adjustmentv
)->page_increment
!= pageScroll
) {
1169 GTK_ADJUSTMENT(adjustmentv
)->upper
= nMax
+ 1;
1170 GTK_ADJUSTMENT(adjustmentv
)->page_size
= nPage
;
1171 GTK_ADJUSTMENT(adjustmentv
)->page_increment
= pageScroll
;
1172 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv
));
1177 PRectangle rcText
= GetTextRectangle();
1178 int horizEndPreferred
= scrollWidth
;
1179 if (horizEndPreferred
< 0)
1180 horizEndPreferred
= 0;
1181 unsigned int pageWidth
= rcText
.Width();
1182 unsigned int pageIncrement
= pageWidth
/ 3;
1183 unsigned int charWidth
= vs
.styles
[STYLE_DEFAULT
].aveCharWidth
;
1184 #if GTK_CHECK_VERSION(3,0,0)
1185 if (gtk_adjustment_get_upper(adjustmenth
) != horizEndPreferred
||
1186 gtk_adjustment_get_page_size(adjustmenth
) != pageWidth
||
1187 gtk_adjustment_get_page_increment(adjustmenth
) != pageIncrement
||
1188 gtk_adjustment_get_step_increment(adjustmenth
) != charWidth
) {
1189 gtk_adjustment_set_upper(adjustmenth
, horizEndPreferred
);
1190 gtk_adjustment_set_page_size(adjustmenth
, pageWidth
);
1191 gtk_adjustment_set_page_increment(adjustmenth
, pageIncrement
);
1192 gtk_adjustment_set_step_increment(adjustmenth
, charWidth
);
1193 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth
));
1197 if (GTK_ADJUSTMENT(adjustmenth
)->upper
!= horizEndPreferred
||
1198 GTK_ADJUSTMENT(adjustmenth
)->page_size
!= pageWidth
||
1199 GTK_ADJUSTMENT(adjustmenth
)->page_increment
!= pageIncrement
||
1200 GTK_ADJUSTMENT(adjustmenth
)->step_increment
!= charWidth
) {
1201 GTK_ADJUSTMENT(adjustmenth
)->upper
= horizEndPreferred
;
1202 GTK_ADJUSTMENT(adjustmenth
)->step_increment
= charWidth
;
1203 GTK_ADJUSTMENT(adjustmenth
)->page_size
= pageWidth
;
1204 GTK_ADJUSTMENT(adjustmenth
)->page_increment
= pageIncrement
;
1205 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth
));
1212 void ScintillaGTK::ReconfigureScrollBars() {
1213 PRectangle rc
= wMain
.GetClientPosition();
1214 Resize(rc
.Width(), rc
.Height());
1217 void ScintillaGTK::NotifyChange() {
1218 g_signal_emit(G_OBJECT(sci
), scintilla_signals
[COMMAND_SIGNAL
], 0,
1219 Platform::LongFromTwoShorts(GetCtrlID(), SCEN_CHANGE
), PWidget(wMain
));
1222 void ScintillaGTK::NotifyFocus(bool focus
) {
1223 g_signal_emit(G_OBJECT(sci
), scintilla_signals
[COMMAND_SIGNAL
], 0,
1224 Platform::LongFromTwoShorts
1225 (GetCtrlID(), focus
? SCEN_SETFOCUS
: SCEN_KILLFOCUS
), PWidget(wMain
));
1228 void ScintillaGTK::NotifyParent(SCNotification scn
) {
1229 scn
.nmhdr
.hwndFrom
= PWidget(wMain
);
1230 scn
.nmhdr
.idFrom
= GetCtrlID();
1231 g_signal_emit(G_OBJECT(sci
), scintilla_signals
[NOTIFY_SIGNAL
], 0,
1235 void ScintillaGTK::NotifyKey(int key
, int modifiers
) {
1236 SCNotification scn
= {0};
1237 scn
.nmhdr
.code
= SCN_KEY
;
1239 scn
.modifiers
= modifiers
;
1244 void ScintillaGTK::NotifyURIDropped(const char *list
) {
1245 SCNotification scn
= {0};
1246 scn
.nmhdr
.code
= SCN_URIDROPPED
;
1252 const char *CharacterSetID(int characterSet
);
1254 const char *ScintillaGTK::CharacterSetID() const {
1255 return ::CharacterSetID(vs
.styles
[STYLE_DEFAULT
].characterSet
);
1258 class CaseFolderUTF8
: public CaseFolderTable
{
1263 virtual size_t Fold(char *folded
, size_t sizeFolded
, const char *mixed
, size_t lenMixed
) {
1264 if ((lenMixed
== 1) && (sizeFolded
> 0)) {
1265 folded
[0] = mapping
[static_cast<unsigned char>(mixed
[0])];
1268 gchar
*mapped
= g_utf8_casefold(mixed
, lenMixed
);
1269 size_t lenMapped
= strlen(mapped
);
1270 if (lenMapped
< sizeFolded
) {
1271 memcpy(folded
, mapped
, lenMapped
);
1281 class CaseFolderDBCS
: public CaseFolderTable
{
1282 const char *charSet
;
1284 CaseFolderDBCS(const char *charSet_
) : charSet(charSet_
) {
1287 virtual size_t Fold(char *folded
, size_t sizeFolded
, const char *mixed
, size_t lenMixed
) {
1288 if ((lenMixed
== 1) && (sizeFolded
> 0)) {
1289 folded
[0] = mapping
[static_cast<unsigned char>(mixed
[0])];
1291 } else if (*charSet
) {
1292 int convertedLength
= lenMixed
;
1293 char *sUTF8
= ConvertText(&convertedLength
, const_cast<char *>(mixed
), lenMixed
,
1294 "UTF-8", charSet
, false);
1296 gchar
*mapped
= g_utf8_casefold(sUTF8
, strlen(sUTF8
));
1297 size_t lenMapped
= strlen(mapped
);
1298 if (lenMapped
< sizeFolded
) {
1299 memcpy(folded
, mapped
, lenMapped
);
1309 // Something failed so return a single NUL byte
1315 CaseFolder
*ScintillaGTK::CaseFolderForEncoding() {
1316 if (pdoc
->dbcsCodePage
== SC_CP_UTF8
) {
1317 return new CaseFolderUTF8();
1319 const char *charSetBuffer
= CharacterSetID();
1320 if (charSetBuffer
) {
1321 if (pdoc
->dbcsCodePage
== 0) {
1322 CaseFolderTable
*pcf
= new CaseFolderTable();
1323 pcf
->StandardASCII();
1324 // Only for single byte encodings
1325 for (int i
=0x80; i
<0x100; i
++) {
1326 char sCharacter
[2] = "A";
1328 int convertedLength
= 1;
1329 const char *sUTF8
= ConvertText(&convertedLength
, sCharacter
, 1,
1330 "UTF-8", charSetBuffer
, false);
1332 gchar
*mapped
= g_utf8_casefold(sUTF8
, strlen(sUTF8
));
1334 int mappedLength
= strlen(mapped
);
1335 const char *mappedBack
= ConvertText(&mappedLength
, mapped
,
1336 mappedLength
, charSetBuffer
, "UTF-8", false, true);
1337 if (mappedBack
&& (strlen(mappedBack
) == 1) && (mappedBack
[0] != sCharacter
[0])) {
1338 pcf
->SetTranslation(sCharacter
[0], mappedBack
[0]);
1340 delete []mappedBack
;
1348 return new CaseFolderDBCS(charSetBuffer
);
1355 std::string
ScintillaGTK::CaseMapString(const std::string
&s
, int caseMapping
) {
1357 return std::string();
1359 if (caseMapping
== cmSame
)
1362 const char *needsFree1
= 0; // Must be freed with delete []
1363 const char *charSetBuffer
= CharacterSetID();
1364 const char *sUTF8
= s
.c_str();
1365 int rangeBytes
= s
.size();
1367 int convertedLength
= rangeBytes
;
1368 // Change text to UTF-8
1369 if (!IsUnicodeMode()) {
1371 if (*charSetBuffer
) {
1372 sUTF8
= ConvertText(&convertedLength
, const_cast<char *>(s
.c_str()), rangeBytes
,
1373 "UTF-8", charSetBuffer
, false);
1377 gchar
*mapped
; // Must be freed with g_free
1378 if (caseMapping
== cmUpper
) {
1379 mapped
= g_utf8_strup(sUTF8
, convertedLength
);
1381 mapped
= g_utf8_strdown(sUTF8
, convertedLength
);
1383 int mappedLength
= strlen(mapped
);
1384 char *mappedBack
= mapped
;
1386 char *needsFree2
= 0; // Must be freed with delete []
1387 if (!IsUnicodeMode()) {
1388 if (*charSetBuffer
) {
1389 mappedBack
= ConvertText(&mappedLength
, mapped
, mappedLength
, charSetBuffer
, "UTF-8", false);
1390 needsFree2
= mappedBack
;
1394 std::string
ret(mappedBack
, mappedLength
);
1396 delete []needsFree1
;
1397 delete []needsFree2
;
1401 int ScintillaGTK::KeyDefault(int key
, int modifiers
) {
1402 if (!(modifiers
& SCI_CTRL
) && !(modifiers
& SCI_ALT
)) {
1404 NotifyKey(key
, modifiers
);
1407 // Pass up to container in case it is an accelerator
1408 NotifyKey(key
, modifiers
);
1412 // Pass up to container in case it is an accelerator
1413 NotifyKey(key
, modifiers
);
1416 //Platform::DebugPrintf("SK-key: %d %x %x\n",key, modifiers);
1419 void ScintillaGTK::CopyToClipboard(const SelectionText
&selectedText
) {
1420 #ifndef USE_GTK_CLIPBOARD
1421 copyText
.Copy(selectedText
);
1422 gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain
)),
1426 SelectionText
*clipText
= new SelectionText();
1427 clipText
->Copy(selectedText
);
1428 StoreOnClipboard(clipText
);
1432 void ScintillaGTK::Copy() {
1434 #ifndef USE_GTK_CLIPBOARD
1435 CopySelectionRange(©Text
);
1436 gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain
)),
1440 SelectionText
*clipText
= new SelectionText();
1441 CopySelectionRange(clipText
);
1442 StoreOnClipboard(clipText
);
1445 if (sel
.IsRectangular()) {
1446 ::OpenClipboard(NULL
);
1447 ::SetClipboardData(cfColumnSelect
, 0);
1454 void ScintillaGTK::Paste() {
1455 atomSought
= atomUTF8
;
1456 gtk_selection_convert(GTK_WIDGET(PWidget(wMain
)),
1457 atomClipboard
, atomSought
, GDK_CURRENT_TIME
);
1460 void ScintillaGTK::CreateCallTipWindow(PRectangle rc
) {
1461 if (!ct
.wCallTip
.Created()) {
1462 ct
.wCallTip
= gtk_window_new(GTK_WINDOW_POPUP
);
1463 ct
.wDraw
= gtk_drawing_area_new();
1464 GtkWidget
*widcdrw
= PWidget(ct
.wDraw
); // // No code inside the G_OBJECT macro
1465 gtk_container_add(GTK_CONTAINER(PWidget(ct
.wCallTip
)), widcdrw
);
1466 #if GTK_CHECK_VERSION(3,0,0)
1467 g_signal_connect(G_OBJECT(widcdrw
), "draw",
1468 G_CALLBACK(ScintillaGTK::DrawCT
), &ct
);
1470 g_signal_connect(G_OBJECT(widcdrw
), "expose_event",
1471 G_CALLBACK(ScintillaGTK::ExposeCT
), &ct
);
1473 g_signal_connect(G_OBJECT(widcdrw
), "button_press_event",
1474 G_CALLBACK(ScintillaGTK::PressCT
), static_cast<void *>(this));
1475 gtk_widget_set_events(widcdrw
,
1476 GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
);
1478 gtk_widget_set_size_request(PWidget(ct
.wDraw
), rc
.Width(), rc
.Height());
1480 if (PWindow(ct
.wCallTip
)) {
1481 gdk_window_resize(PWindow(ct
.wCallTip
), rc
.Width(), rc
.Height());
1485 void ScintillaGTK::AddToPopUp(const char *label
, int cmd
, bool enabled
) {
1486 GtkWidget
*menuItem
;
1488 menuItem
= gtk_menu_item_new_with_label(label
);
1490 menuItem
= gtk_separator_menu_item_new();
1491 gtk_menu_shell_append(GTK_MENU_SHELL(popup
.GetID()), menuItem
);
1492 g_object_set_data(G_OBJECT(menuItem
), "CmdNum", reinterpret_cast<void *>(cmd
));
1493 g_signal_connect(G_OBJECT(menuItem
),"activate", G_CALLBACK(PopUpCB
), this);
1497 gtk_widget_set_sensitive(menuItem
, enabled
);
1501 bool ScintillaGTK::OwnPrimarySelection() {
1502 return ((gdk_selection_owner_get(GDK_SELECTION_PRIMARY
)
1503 == PWindow(wMain
)) &&
1504 (PWindow(wMain
) != NULL
));
1507 void ScintillaGTK::ClaimSelection() {
1508 // X Windows has a 'primary selection' as well as the clipboard.
1509 // Whenever the user selects some text, we become the primary selection
1510 if (!sel
.Empty() && IS_WIDGET_REALIZED(GTK_WIDGET(PWidget(wMain
)))) {
1511 primarySelection
= true;
1512 gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain
)),
1513 GDK_SELECTION_PRIMARY
, GDK_CURRENT_TIME
);
1515 } else if (OwnPrimarySelection()) {
1516 primarySelection
= true;
1517 if (primary
.s
== NULL
)
1518 gtk_selection_owner_set(NULL
, GDK_SELECTION_PRIMARY
, GDK_CURRENT_TIME
);
1520 primarySelection
= false;
1525 #if GTK_CHECK_VERSION(3,0,0)
1526 static const guchar
*DataOfGSD(GtkSelectionData
*sd
) { return gtk_selection_data_get_data(sd
); }
1527 static gint
LengthOfGSD(GtkSelectionData
*sd
) { return gtk_selection_data_get_length(sd
); }
1528 static GdkAtom
TypeOfGSD(GtkSelectionData
*sd
) { return gtk_selection_data_get_data_type(sd
); }
1529 static GdkAtom
SelectionOfGSD(GtkSelectionData
*sd
) { return gtk_selection_data_get_selection(sd
); }
1531 static const guchar
*DataOfGSD(GtkSelectionData
*sd
) { return sd
->data
; }
1532 static gint
LengthOfGSD(GtkSelectionData
*sd
) { return sd
->length
; }
1533 static GdkAtom
TypeOfGSD(GtkSelectionData
*sd
) { return sd
->type
; }
1534 static GdkAtom
SelectionOfGSD(GtkSelectionData
*sd
) { return sd
->selection
; }
1537 // Detect rectangular text, convert line ends to current mode, convert from or to UTF-8
1538 void ScintillaGTK::GetGtkSelectionText(GtkSelectionData
*selectionData
, SelectionText
&selText
) {
1539 const char *data
= reinterpret_cast<const char *>(DataOfGSD(selectionData
));
1540 int len
= LengthOfGSD(selectionData
);
1541 GdkAtom selectionTypeData
= TypeOfGSD(selectionData
);
1543 // Return empty string if selection is not a string
1544 if ((selectionTypeData
!= GDK_TARGET_STRING
) && (selectionTypeData
!= atomUTF8
)) {
1545 char *empty
= new char[1];
1547 selText
.Set(empty
, 0, SC_CP_UTF8
, 0, false, false);
1551 // Check for "\n\0" ending to string indicating that selection is rectangular
1554 isRectangular
= ::IsClipboardFormatAvailable(cfColumnSelect
) != 0;
1556 isRectangular
= ((len
> 2) && (data
[len
- 1] == 0 && data
[len
- 2] == '\n'));
1558 len
--; // Forget the extra '\0'
1562 if (selectionTypeData
== GDK_TARGET_STRING
) {
1563 dest
= Document::TransformLineEnds(&len
, data
, len
, pdoc
->eolMode
);
1564 if (IsUnicodeMode()) {
1565 // Unknown encoding so assume in Latin1
1566 char *destPrevious
= dest
;
1567 dest
= UTF8FromLatin1(dest
, len
);
1568 selText
.Set(dest
, len
, SC_CP_UTF8
, 0, selText
.rectangular
, false);
1569 delete []destPrevious
;
1571 // Assume buffer is in same encoding as selection
1572 selText
.Set(dest
, len
, pdoc
->dbcsCodePage
,
1573 vs
.styles
[STYLE_DEFAULT
].characterSet
, isRectangular
, false);
1576 dest
= Document::TransformLineEnds(&len
, data
, len
, pdoc
->eolMode
);
1577 selText
.Set(dest
, len
, SC_CP_UTF8
, 0, isRectangular
, false);
1578 const char *charSetBuffer
= CharacterSetID();
1579 if (!IsUnicodeMode() && *charSetBuffer
) {
1580 // Convert to locale
1581 dest
= ConvertText(&len
, selText
.s
, selText
.len
, charSetBuffer
, "UTF-8", true);
1582 selText
.Set(dest
, len
, pdoc
->dbcsCodePage
,
1583 vs
.styles
[STYLE_DEFAULT
].characterSet
, selText
.rectangular
, false);
1588 void ScintillaGTK::ReceivedSelection(GtkSelectionData
*selection_data
) {
1590 if ((SelectionOfGSD(selection_data
) == atomClipboard
) ||
1591 (SelectionOfGSD(selection_data
) == GDK_SELECTION_PRIMARY
)) {
1592 if ((atomSought
== atomUTF8
) && (LengthOfGSD(selection_data
) <= 0)) {
1593 atomSought
= atomString
;
1594 gtk_selection_convert(GTK_WIDGET(PWidget(wMain
)),
1595 SelectionOfGSD(selection_data
), atomSought
, GDK_CURRENT_TIME
);
1596 } else if ((LengthOfGSD(selection_data
) > 0) &&
1597 ((TypeOfGSD(selection_data
) == GDK_TARGET_STRING
) || (TypeOfGSD(selection_data
) == atomUTF8
))) {
1598 SelectionText selText
;
1599 GetGtkSelectionText(selection_data
, selText
);
1602 if (SelectionOfGSD(selection_data
) != GDK_SELECTION_PRIMARY
) {
1603 ClearSelection(multiPasteMode
== SC_MULTIPASTE_EACH
);
1605 SelectionPosition selStart
= sel
.IsRectangular() ?
1606 sel
.Rectangular().Start() :
1607 sel
.Range(sel
.Main()).Start();
1609 if (selText
.rectangular
) {
1610 PasteRectangular(selStart
, selText
.s
, selText
.len
);
1612 InsertPaste(selStart
, selText
.s
, selText
.len
);
1614 EnsureCaretVisible();
1617 // else fprintf(stderr, "Target non string %d %d\n", (int)(selection_data->type),
1618 // (int)(atomUTF8));
1621 errorStatus
= SC_STATUS_FAILURE
;
1625 void ScintillaGTK::ReceivedDrop(GtkSelectionData
*selection_data
) {
1626 dragWasDropped
= true;
1627 if (TypeOfGSD(selection_data
) == atomUriList
|| TypeOfGSD(selection_data
) == atomDROPFILES_DND
) {
1628 char *ptr
= new char[LengthOfGSD(selection_data
) + 1];
1629 ptr
[LengthOfGSD(selection_data
)] = '\0';
1630 memcpy(ptr
, DataOfGSD(selection_data
), LengthOfGSD(selection_data
));
1631 NotifyURIDropped(ptr
);
1633 } else if ((TypeOfGSD(selection_data
) == GDK_TARGET_STRING
) || (TypeOfGSD(selection_data
) == atomUTF8
)) {
1634 if (TypeOfGSD(selection_data
) > 0) {
1635 SelectionText selText
;
1636 GetGtkSelectionText(selection_data
, selText
);
1637 DropAt(posDrop
, selText
.s
, false, selText
.rectangular
);
1639 } else if (LengthOfGSD(selection_data
) > 0) {
1640 //~ fprintf(stderr, "ReceivedDrop other %p\n", static_cast<void *>(selection_data->type));
1647 void ScintillaGTK::GetSelection(GtkSelectionData
*selection_data
, guint info
, SelectionText
*text
) {
1649 // GDK on Win32 expands any \n into \r\n, so make a copy of
1650 // the clip text now with newlines converted to \n. Use { } to hide symbols
1652 SelectionText
*newline_normalized
= NULL
;
1655 char *tmpstr
= Document::TransformLineEnds(&tmpstr_len
, text
->s
, text
->len
, SC_EOL_LF
);
1656 newline_normalized
= new SelectionText();
1657 newline_normalized
->Set(tmpstr
, tmpstr_len
, SC_CP_UTF8
, 0, text
->rectangular
, false);
1658 text
= newline_normalized
;
1662 // Convert text to utf8 if it isn't already
1663 SelectionText
*converted
= 0;
1664 if ((text
->codePage
!= SC_CP_UTF8
) && (info
== TARGET_UTF8_STRING
)) {
1665 const char *charSet
= ::CharacterSetID(text
->characterSet
);
1668 char* tmputf
= ConvertText(&new_len
, text
->s
, text
->len
, "UTF-8", charSet
, false);
1669 converted
= new SelectionText();
1670 converted
->Set(tmputf
, new_len
, SC_CP_UTF8
, 0, text
->rectangular
, false);
1675 // Here is a somewhat evil kludge.
1676 // As I can not work out how to store data on the clipboard in multiple formats
1677 // and need some way to mark the clipping as being stream or rectangular,
1678 // the terminating \0 is included in the length for rectangular clippings.
1679 // All other tested aplications behave benignly by ignoring the \0.
1680 // The #if is here because on Windows cfColumnSelect clip entry is used
1681 // instead as standard indicator of rectangularness (so no need to kludge)
1682 const char *textData
= text
->s
? text
->s
: "";
1683 int len
= strlen(textData
);
1684 #if PLAT_GTK_WIN32 == 0
1685 if (text
->rectangular
)
1689 if (info
== TARGET_UTF8_STRING
) {
1690 gtk_selection_data_set_text(selection_data
, textData
, len
);
1692 gtk_selection_data_set(selection_data
,
1693 static_cast<GdkAtom
>(GDK_SELECTION_TYPE_STRING
),
1694 8, reinterpret_cast<const unsigned char *>(textData
), len
);
1699 delete newline_normalized
;
1703 #ifdef USE_GTK_CLIPBOARD
1704 void ScintillaGTK::StoreOnClipboard(SelectionText
*clipText
) {
1705 GtkClipboard
*clipBoard
=
1706 gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain
)), atomClipboard
);
1707 if (clipBoard
== NULL
) // Occurs if widget isn't in a toplevel
1710 if (gtk_clipboard_set_with_data(clipBoard
, clipboardCopyTargets
, nClipboardCopyTargets
,
1711 ClipboardGetSelection
, ClipboardClearSelection
, clipText
)) {
1712 gtk_clipboard_set_can_store(clipBoard
, clipboardCopyTargets
, nClipboardCopyTargets
);
1716 void ScintillaGTK::ClipboardGetSelection(GtkClipboard
*, GtkSelectionData
*selection_data
, guint info
, void *data
) {
1717 GetSelection(selection_data
, info
, static_cast<SelectionText
*>(data
));
1720 void ScintillaGTK::ClipboardClearSelection(GtkClipboard
*, void *data
) {
1721 SelectionText
*obj
= static_cast<SelectionText
*>(data
);
1726 void ScintillaGTK::UnclaimSelection(GdkEventSelection
*selection_event
) {
1728 //Platform::DebugPrintf("UnclaimSelection\n");
1729 if (selection_event
->selection
== GDK_SELECTION_PRIMARY
) {
1730 //Platform::DebugPrintf("UnclaimPrimarySelection\n");
1731 if (!OwnPrimarySelection()) {
1733 primarySelection
= false;
1738 errorStatus
= SC_STATUS_FAILURE
;
1742 void ScintillaGTK::Resize(int width
, int height
) {
1743 //Platform::DebugPrintf("Resize %d %d\n", width, height);
1744 //printf("Resize %d %d\n", width, height);
1746 // Not always needed, but some themes can have different sizes of scrollbars
1747 #if GTK_CHECK_VERSION(3,0,0)
1748 GtkRequisition requisition
;
1749 gtk_widget_get_requisition(PWidget(scrollbarv
), &requisition
);
1750 scrollBarWidth
= requisition
.width
;
1751 gtk_widget_get_requisition(PWidget(scrollbarh
), &requisition
);
1752 scrollBarHeight
= requisition
.height
;
1754 scrollBarWidth
= GTK_WIDGET(PWidget(scrollbarv
))->requisition
.width
;
1755 scrollBarHeight
= GTK_WIDGET(PWidget(scrollbarh
))->requisition
.height
;
1758 // These allocations should never produce negative sizes as they would wrap around to huge
1759 // unsigned numbers inside GTK+ causing warnings.
1760 bool showSBHorizontal
= horizontalScrollBarVisible
&& (wrapState
== eWrapNone
);
1761 int horizontalScrollBarHeight
= scrollBarHeight
;
1762 if (!showSBHorizontal
)
1763 horizontalScrollBarHeight
= 0;
1765 GtkAllocation alloc
;
1766 if (showSBHorizontal
) {
1767 gtk_widget_show(GTK_WIDGET(PWidget(scrollbarh
)));
1769 alloc
.y
= height
- scrollBarHeight
;
1770 alloc
.width
= Platform::Maximum(1, width
- scrollBarWidth
);
1771 alloc
.height
= horizontalScrollBarHeight
;
1772 gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarh
)), &alloc
);
1774 gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarh
)));
1777 if (verticalScrollBarVisible
) {
1778 gtk_widget_show(GTK_WIDGET(PWidget(scrollbarv
)));
1779 alloc
.x
= width
- scrollBarWidth
;
1781 alloc
.width
= scrollBarWidth
;
1782 alloc
.height
= Platform::Maximum(1, height
- scrollBarHeight
);
1783 if (!showSBHorizontal
)
1784 alloc
.height
+= scrollBarWidth
-1;
1785 gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarv
)), &alloc
);
1787 gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarv
)));
1789 if (IS_WIDGET_MAPPED(PWidget(wMain
))) {
1795 alloc
.width
= Platform::Maximum(1, width
- scrollBarWidth
);
1796 alloc
.height
= Platform::Maximum(1, height
- scrollBarHeight
);
1797 if (!showSBHorizontal
)
1798 alloc
.height
+= scrollBarHeight
;
1799 if (!verticalScrollBarVisible
)
1800 alloc
.width
+= scrollBarWidth
;
1801 gtk_widget_size_allocate(GTK_WIDGET(PWidget(wText
)), &alloc
);
1804 static void SetAdjustmentValue(GtkAdjustment
*object
, int value
) {
1805 GtkAdjustment
*adjustment
= GTK_ADJUSTMENT(object
);
1806 #if GTK_CHECK_VERSION(3,0,0)
1807 int maxValue
= static_cast<int>(
1808 gtk_adjustment_get_upper(adjustment
) - gtk_adjustment_get_page_size(adjustment
));
1810 int maxValue
= static_cast<int>(
1811 adjustment
->upper
- adjustment
->page_size
);
1814 if (value
> maxValue
)
1818 gtk_adjustment_set_value(adjustment
, value
);
1821 static int modifierTranslated(int sciModifier
) {
1822 switch (sciModifier
) {
1824 return GDK_SHIFT_MASK
;
1826 return GDK_CONTROL_MASK
;
1828 return GDK_MOD1_MASK
;
1830 return GDK_MOD4_MASK
;
1836 gint
ScintillaGTK::PressThis(GdkEventButton
*event
) {
1838 //Platform::DebugPrintf("Press %x time=%d state = %x button = %x\n",this,event->time, event->state, event->button);
1839 // Do not use GTK+ double click events as Scintilla has its own double click detection
1840 if (event
->type
!= GDK_BUTTON_PRESS
)
1845 pt
.x
= int(event
->x
);
1846 pt
.y
= int(event
->y
);
1847 PRectangle rcClient
= GetClientRectangle();
1848 //Platform::DebugPrintf("Press %0d,%0d in %0d,%0d %0d,%0d\n",
1849 // pt.x, pt.y, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1850 if ((pt
.x
> rcClient
.right
) || (pt
.y
> rcClient
.bottom
)) {
1851 Platform::DebugPrintf("Bad location\n");
1855 bool ctrl
= (event
->state
& GDK_CONTROL_MASK
) != 0;
1857 gtk_widget_grab_focus(PWidget(wMain
));
1858 if (event
->button
== 1) {
1859 // On X, instead of sending literal modifiers use the user specified
1860 // modifier, defaulting to control instead of alt.
1861 // This is because most X window managers grab alt + click for moving
1862 ButtonDown(pt
, event
->time
,
1863 (event
->state
& GDK_SHIFT_MASK
) != 0,
1864 (event
->state
& GDK_CONTROL_MASK
) != 0,
1865 (event
->state
& modifierTranslated(rectangularSelectionModifier
)) != 0);
1866 } else if (event
->button
== 2) {
1867 // Grab the primary selection if it exists
1868 SelectionPosition pos
= SPositionFromLocation(pt
, false, false, UserVirtualSpace());
1869 if (OwnPrimarySelection() && primary
.s
== NULL
)
1870 CopySelectionRange(&primary
);
1873 SetSelection(pos
, pos
);
1874 atomSought
= atomUTF8
;
1875 gtk_selection_convert(GTK_WIDGET(PWidget(wMain
)), GDK_SELECTION_PRIMARY
,
1876 atomSought
, event
->time
);
1877 } else if (event
->button
== 3) {
1878 if (!PointInSelection(pt
))
1879 SetEmptySelection(PositionFromLocation(pt
));
1880 if (displayPopupMenu
) {
1882 // Convert to screen
1885 gdk_window_get_origin(PWindow(wMain
), &ox
, &oy
);
1886 ContextMenu(Point(pt
.x
+ ox
, pt
.y
+ oy
));
1890 } else if (event
->button
== 4) {
1891 // Wheel scrolling up (only GTK 1.x does it this way)
1893 SetAdjustmentValue(adjustmenth
, (xOffset
/ 2) - 6);
1895 SetAdjustmentValue(adjustmentv
, topLine
- 3);
1896 } else if (event
->button
== 5) {
1897 // Wheel scrolling down (only GTK 1.x does it this way)
1899 SetAdjustmentValue(adjustmenth
, (xOffset
/ 2) + 6);
1901 SetAdjustmentValue(adjustmentv
, topLine
+ 3);
1904 errorStatus
= SC_STATUS_FAILURE
;
1909 gint
ScintillaGTK::Press(GtkWidget
*widget
, GdkEventButton
*event
) {
1910 if (event
->window
!= WindowFromWidget(widget
))
1912 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1913 return sciThis
->PressThis(event
);
1916 gint
ScintillaGTK::MouseRelease(GtkWidget
*widget
, GdkEventButton
*event
) {
1917 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1919 //Platform::DebugPrintf("Release %x %d %d\n",sciThis,event->time,event->state);
1920 if (!sciThis
->HaveMouseCapture())
1922 if (event
->button
== 1) {
1924 pt
.x
= int(event
->x
);
1925 pt
.y
= int(event
->y
);
1926 //Platform::DebugPrintf("Up %x %x %d %d %d\n",
1927 // sciThis,event->window,event->time, pt.x, pt.y);
1928 if (event
->window
!= PWindow(sciThis
->wMain
))
1929 // If mouse released on scroll bar then the position is relative to the
1930 // scrollbar, not the drawing window so just repeat the most recent point.
1931 pt
= sciThis
->ptMouseLast
;
1932 sciThis
->ButtonUp(pt
, event
->time
, (event
->state
& 4) != 0);
1935 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
1940 // win32gtk and GTK >= 2 use SCROLL_* events instead of passing the
1941 // button4/5/6/7 events to the GTK app
1942 gint
ScintillaGTK::ScrollEvent(GtkWidget
*widget
,
1943 GdkEventScroll
*event
) {
1944 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1947 if (widget
== NULL
|| event
== NULL
)
1950 // Compute amount and direction to scroll (even tho on win32 there is
1951 // intensity of scrolling info in the native message, gtk doesn't
1952 // support this so we simulate similarly adaptive scrolling)
1953 // Note that this is disabled on OS X (Darwin) where the X11 server already has
1954 // and adaptive scrolling algorithm that fights with this one
1956 #if defined(__MWERKS__) || defined(__APPLE_CPP__) || defined(__APPLE_CC__)
1957 cLineScroll
= sciThis
->linesPerScroll
;
1958 if (cLineScroll
== 0)
1960 sciThis
->wheelMouseIntensity
= cLineScroll
;
1962 int timeDelta
= 1000000;
1964 g_get_current_time(&curTime
);
1965 if (curTime
.tv_sec
== sciThis
->lastWheelMouseTime
.tv_sec
)
1966 timeDelta
= curTime
.tv_usec
- sciThis
->lastWheelMouseTime
.tv_usec
;
1967 else if (curTime
.tv_sec
== sciThis
->lastWheelMouseTime
.tv_sec
+ 1)
1968 timeDelta
= 1000000 + (curTime
.tv_usec
- sciThis
->lastWheelMouseTime
.tv_usec
);
1969 if ((event
->direction
== sciThis
->lastWheelMouseDirection
) && (timeDelta
< 250000)) {
1970 if (sciThis
->wheelMouseIntensity
< 12)
1971 sciThis
->wheelMouseIntensity
++;
1972 cLineScroll
= sciThis
->wheelMouseIntensity
;
1974 cLineScroll
= sciThis
->linesPerScroll
;
1975 if (cLineScroll
== 0)
1977 sciThis
->wheelMouseIntensity
= cLineScroll
;
1980 if (event
->direction
== GDK_SCROLL_UP
|| event
->direction
== GDK_SCROLL_LEFT
) {
1983 g_get_current_time(&sciThis
->lastWheelMouseTime
);
1984 sciThis
->lastWheelMouseDirection
= event
->direction
;
1986 // Note: Unpatched versions of win32gtk don't set the 'state' value so
1987 // only regular scrolling is supported there. Also, unpatched win32gtk
1988 // issues spurious button 2 mouse events during wheeling, which can cause
1989 // problems (a patch for both was submitted by archaeopteryx.com on 13Jun2001)
1991 // Data zoom not supported
1992 if (event
->state
& GDK_SHIFT_MASK
) {
1996 // Horizontal scrolling
1997 if (event
->direction
== GDK_SCROLL_LEFT
|| event
->direction
== GDK_SCROLL_RIGHT
) {
1998 sciThis
->HorizontalScrollTo(sciThis
->xOffset
+ cLineScroll
);
2000 // Text font size zoom
2001 } else if (event
->state
& GDK_CONTROL_MASK
) {
2002 if (cLineScroll
< 0) {
2003 sciThis
->KeyCommand(SCI_ZOOMIN
);
2005 sciThis
->KeyCommand(SCI_ZOOMOUT
);
2008 // Regular scrolling
2010 sciThis
->ScrollTo(sciThis
->topLine
+ cLineScroll
);
2014 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2019 gint
ScintillaGTK::Motion(GtkWidget
*widget
, GdkEventMotion
*event
) {
2020 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2022 //Platform::DebugPrintf("Motion %x %d\n",sciThis,event->time);
2023 if (event
->window
!= WindowFromWidget(widget
))
2027 GdkModifierType state
;
2028 if (event
->is_hint
) {
2029 gdk_window_get_pointer(event
->window
, &x
, &y
, &state
);
2031 x
= static_cast<int>(event
->x
);
2032 y
= static_cast<int>(event
->y
);
2033 state
= static_cast<GdkModifierType
>(event
->state
);
2035 //Platform::DebugPrintf("Move %x %x %d %c %d %d\n",
2036 // sciThis,event->window,event->time,event->is_hint? 'h' :'.', x, y);
2038 sciThis
->ButtonMove(pt
);
2040 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2045 // Map the keypad keys to their equivalent functions
2046 static int KeyTranslate(int keyIn
) {
2048 #if GTK_CHECK_VERSION(3,0,0)
2049 case GDK_KEY_ISO_Left_Tab
:
2051 case GDK_KEY_KP_Down
:
2055 case GDK_KEY_KP_Left
:
2057 case GDK_KEY_KP_Right
:
2059 case GDK_KEY_KP_Home
:
2061 case GDK_KEY_KP_End
:
2063 case GDK_KEY_KP_Page_Up
:
2065 case GDK_KEY_KP_Page_Down
:
2067 case GDK_KEY_KP_Delete
:
2069 case GDK_KEY_KP_Insert
:
2071 case GDK_KEY_KP_Enter
:
2086 case GDK_KEY_Page_Up
:
2088 case GDK_KEY_Page_Down
:
2090 case GDK_KEY_Delete
:
2092 case GDK_KEY_Insert
:
2094 case GDK_KEY_Escape
:
2096 case GDK_KEY_BackSpace
:
2100 case GDK_KEY_Return
:
2102 case GDK_KEY_KP_Add
:
2104 case GDK_KEY_KP_Subtract
:
2105 return SCK_SUBTRACT
;
2106 case GDK_KEY_KP_Divide
:
2108 case GDK_KEY_Super_L
:
2110 case GDK_KEY_Super_R
:
2117 case GDK_ISO_Left_Tab
:
2131 case GDK_KP_Page_Up
:
2133 case GDK_KP_Page_Down
:
2172 case GDK_KP_Subtract
:
2173 return SCK_SUBTRACT
;
2188 gboolean
ScintillaGTK::KeyThis(GdkEventKey
*event
) {
2190 //fprintf(stderr, "SC-key: %d %x [%s]\n",
2191 // event->keyval, event->state, (event->length > 0) ? event->string : "empty");
2192 if (gtk_im_context_filter_keypress(im_context
, event
)) {
2195 if (!event
->keyval
) {
2199 bool shift
= (event
->state
& GDK_SHIFT_MASK
) != 0;
2200 bool ctrl
= (event
->state
& GDK_CONTROL_MASK
) != 0;
2201 bool alt
= (event
->state
& GDK_MOD1_MASK
) != 0;
2202 guint key
= event
->keyval
;
2203 if (ctrl
&& (key
< 128))
2205 #if GTK_CHECK_VERSION(3,0,0)
2206 else if (!ctrl
&& (key
>= GDK_KEY_KP_Multiply
&& key
<= GDK_KEY_KP_9
))
2208 else if (!ctrl
&& (key
>= GDK_KP_Multiply
&& key
<= GDK_KP_9
))
2211 // Hack for keys over 256 and below command keys but makes Hungarian work.
2212 // This will have to change for Unicode
2213 else if (key
>= 0xFE00)
2214 key
= KeyTranslate(key
);
2216 bool consumed
= false;
2217 bool added
= KeyDown(key
, shift
, ctrl
, alt
, &consumed
) != 0;
2220 //fprintf(stderr, "SK-key: %d %x %x\n",event->keyval, event->state, consumed);
2221 if (event
->keyval
== 0xffffff && event
->length
> 0) {
2223 if (pdoc
->InsertCString(CurrentPosition(), event
->string
)) {
2224 MovePositionTo(CurrentPosition() + event
->length
);
2229 errorStatus
= SC_STATUS_FAILURE
;
2234 gboolean
ScintillaGTK::KeyPress(GtkWidget
*widget
, GdkEventKey
*event
) {
2235 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2236 return sciThis
->KeyThis(event
);
2239 gboolean
ScintillaGTK::KeyRelease(GtkWidget
*, GdkEventKey
* /*event*/) {
2240 //Platform::DebugPrintf("SC-keyrel: %d %x %3s\n",event->keyval, event->state, event->string);
2244 gboolean
ScintillaGTK::ExposePreeditThis(GtkWidget
*widget
, GdkEventExpose
*ose
) {
2248 PangoAttrList
*attrs
;
2250 gtk_im_context_get_preedit_string(im_context
, &str
, &attrs
, &cursor_pos
);
2251 PangoLayout
*layout
= gtk_widget_create_pango_layout(PWidget(wText
), str
);
2252 pango_layout_set_attributes(layout
, attrs
);
2255 GdkGC
*gc
= gdk_gc_new(widget
->window
);
2256 GdkColor color
[2] = { {0, 0x0000, 0x0000, 0x0000},
2257 {0, 0xffff, 0xffff, 0xffff}
2259 gdk_colormap_alloc_color(gdk_colormap_get_system(), color
, FALSE
, TRUE
);
2260 gdk_colormap_alloc_color(gdk_colormap_get_system(), color
+ 1, FALSE
, TRUE
);
2262 gdk_gc_set_foreground(gc
, color
+ 1);
2263 gdk_draw_rectangle(widget
->window
, gc
, TRUE
, ose
->area
.x
, ose
->area
.y
,
2264 ose
->area
.width
, ose
->area
.height
);
2266 gdk_gc_set_foreground(gc
, color
);
2267 gdk_gc_set_background(gc
, color
+ 1);
2268 gdk_draw_layout(widget
->window
, gc
, 0, 0, layout
);
2272 pango_attr_list_unref(attrs
);
2273 g_object_unref(layout
);
2275 errorStatus
= SC_STATUS_FAILURE
;
2280 gboolean
ScintillaGTK::ExposePreedit(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
) {
2281 return sciThis
->ExposePreeditThis(widget
, ose
);
2284 void ScintillaGTK::CommitThis(char *utfVal
) {
2286 //~ fprintf(stderr, "Commit '%s'\n", utfVal);
2287 if (IsUnicodeMode()) {
2288 AddCharUTF(utfVal
, strlen(utfVal
));
2290 const char *source
= CharacterSetID();
2292 Converter
conv(source
, "UTF-8", true);
2294 char localeVal
[4] = "\0\0\0";
2296 size_t inLeft
= strlen(utfVal
);
2297 char *pout
= localeVal
;
2298 size_t outLeft
= sizeof(localeVal
);
2299 size_t conversions
= conv
.Convert(&pin
, &inLeft
, &pout
, &outLeft
);
2300 if (conversions
!= ((size_t)(-1))) {
2302 for (int i
= 0; localeVal
[i
]; i
++) {
2303 AddChar(localeVal
[i
]);
2306 fprintf(stderr
, "Conversion failed '%s'\n", utfVal
);
2312 errorStatus
= SC_STATUS_FAILURE
;
2316 void ScintillaGTK::Commit(GtkIMContext
*, char *str
, ScintillaGTK
*sciThis
) {
2317 sciThis
->CommitThis(str
);
2320 void ScintillaGTK::PreeditChangedThis() {
2323 PangoAttrList
*attrs
;
2325 gtk_im_context_get_preedit_string(im_context
, &str
, &attrs
, &cursor_pos
);
2326 if (strlen(str
) > 0) {
2327 PangoLayout
*layout
= gtk_widget_create_pango_layout(PWidget(wText
), str
);
2328 pango_layout_set_attributes(layout
, attrs
);
2331 pango_layout_get_pixel_size(layout
, &w
, &h
);
2332 g_object_unref(layout
);
2335 gdk_window_get_origin(PWindow(wText
), &x
, &y
);
2337 Point pt
= PointMainCaret();
2343 gtk_window_move(GTK_WINDOW(PWidget(wPreedit
)), x
+ pt
.x
, y
+ pt
.y
);
2344 gtk_window_resize(GTK_WINDOW(PWidget(wPreedit
)), w
, h
);
2345 gtk_widget_show(PWidget(wPreedit
));
2346 gtk_widget_queue_draw_area(PWidget(wPreeditDraw
), 0, 0, w
, h
);
2348 gtk_widget_hide(PWidget(wPreedit
));
2351 pango_attr_list_unref(attrs
);
2353 errorStatus
= SC_STATUS_FAILURE
;
2357 void ScintillaGTK::PreeditChanged(GtkIMContext
*, ScintillaGTK
*sciThis
) {
2358 sciThis
->PreeditChangedThis();
2361 void ScintillaGTK::StyleSetText(GtkWidget
*widget
, GtkStyle
*, void*) {
2362 RealizeText(widget
, NULL
);
2365 void ScintillaGTK::RealizeText(GtkWidget
*widget
, void*) {
2366 // Set NULL background to avoid automatic clearing so Scintilla responsible for all drawing
2367 if (WindowFromWidget(widget
)) {
2368 #if GTK_CHECK_VERSION(3,0,0)
2369 gdk_window_set_background_pattern(WindowFromWidget(widget
), NULL
);
2371 gdk_window_set_back_pixmap(WindowFromWidget(widget
), NULL
, FALSE
);
2376 void ScintillaGTK::Destroy(GObject
*object
) {
2378 ScintillaObject
*scio
= reinterpret_cast<ScintillaObject
*>(object
);
2379 // This avoids a double destruction
2382 ScintillaGTK
*sciThis
= reinterpret_cast<ScintillaGTK
*>(scio
->pscin
);
2383 //Platform::DebugPrintf("Destroying %x %x\n", sciThis, object);
2384 sciThis
->Finalise();
2389 // Its dead so nowhere to save the status
2393 #if GTK_CHECK_VERSION(3,0,0)
2395 gboolean
ScintillaGTK::DrawTextThis(cairo_t
*cr
) {
2397 paintState
= painting
;
2399 rcPaint
= GetClientRectangle();
2401 PLATFORM_ASSERT(rgnUpdate
== NULL
);
2402 rgnUpdate
= cairo_copy_clip_rectangle_list(cr
);
2403 if (rgnUpdate
&& rgnUpdate
->status
!= CAIRO_STATUS_SUCCESS
) {
2404 // If not successful then ignore
2405 fprintf(stderr
, "DrawTextThis failed to copy update region %d [%d]\n", rgnUpdate
->status
, rgnUpdate
->num_rectangles
);
2406 cairo_rectangle_list_destroy(rgnUpdate
);
2410 double x1
, y1
, x2
, y2
;
2411 cairo_clip_extents(cr
, &x1
, &y1
, &x2
, &y2
);
2415 rcPaint
.bottom
= y2
;
2416 PRectangle rcClient
= GetClientRectangle();
2417 paintingAllText
= rcPaint
.Contains(rcClient
);
2418 Surface
*surfaceWindow
= Surface::Allocate();
2419 if (surfaceWindow
) {
2420 surfaceWindow
->Init(cr
, PWidget(wText
));
2421 Paint(surfaceWindow
, rcPaint
);
2422 surfaceWindow
->Release();
2423 delete surfaceWindow
;
2425 if (paintState
== paintAbandoned
) {
2426 // Painting area was insufficient to cover new styling or brace highlight positions
2429 paintState
= notPainting
;
2432 cairo_rectangle_list_destroy(rgnUpdate
);
2435 paintState
= notPainting
;
2437 errorStatus
= SC_STATUS_FAILURE
;
2443 gboolean
ScintillaGTK::DrawText(GtkWidget
*, cairo_t
*cr
, ScintillaGTK
*sciThis
) {
2444 return sciThis
->DrawTextThis(cr
);
2447 gboolean
ScintillaGTK::DrawThis(cairo_t
*cr
) {
2449 gtk_container_propagate_draw(
2450 GTK_CONTAINER(PWidget(wMain
)), PWidget(scrollbarh
), cr
);
2451 gtk_container_propagate_draw(
2452 GTK_CONTAINER(PWidget(wMain
)), PWidget(scrollbarv
), cr
);
2454 errorStatus
= SC_STATUS_FAILURE
;
2459 gboolean
ScintillaGTK::DrawMain(GtkWidget
*widget
, cairo_t
*cr
) {
2460 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2461 return sciThis
->DrawThis(cr
);
2466 gboolean
ScintillaGTK::ExposeTextThis(GtkWidget
* /*widget*/, GdkEventExpose
*ose
) {
2468 paintState
= painting
;
2470 rcPaint
.left
= ose
->area
.x
;
2471 rcPaint
.top
= ose
->area
.y
;
2472 rcPaint
.right
= ose
->area
.x
+ ose
->area
.width
;
2473 rcPaint
.bottom
= ose
->area
.y
+ ose
->area
.height
;
2475 PLATFORM_ASSERT(rgnUpdate
== NULL
);
2476 rgnUpdate
= gdk_region_copy(ose
->region
);
2477 PRectangle rcClient
= GetClientRectangle();
2478 paintingAllText
= rcPaint
.Contains(rcClient
);
2479 Surface
*surfaceWindow
= Surface::Allocate();
2480 if (surfaceWindow
) {
2481 surfaceWindow
->Init(PWindow(wText
), PWidget(wText
));
2482 Paint(surfaceWindow
, rcPaint
);
2483 surfaceWindow
->Release();
2484 delete surfaceWindow
;
2486 if (paintState
== paintAbandoned
) {
2487 // Painting area was insufficient to cover new styling or brace highlight positions
2490 paintState
= notPainting
;
2493 gdk_region_destroy(rgnUpdate
);
2497 errorStatus
= SC_STATUS_FAILURE
;
2503 gboolean
ScintillaGTK::ExposeText(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
) {
2504 return sciThis
->ExposeTextThis(widget
, ose
);
2507 gboolean
ScintillaGTK::ExposeMain(GtkWidget
*widget
, GdkEventExpose
*ose
) {
2508 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2509 //Platform::DebugPrintf("Expose Main %0d,%0d %0d,%0d\n",
2510 //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2511 return sciThis
->Expose(widget
, ose
);
2514 gboolean
ScintillaGTK::Expose(GtkWidget
*, GdkEventExpose
*ose
) {
2516 //fprintf(stderr, "Expose %0d,%0d %0d,%0d\n",
2517 //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2519 // The text is painted in ExposeText
2520 gtk_container_propagate_expose(
2521 GTK_CONTAINER(PWidget(wMain
)), PWidget(scrollbarh
), ose
);
2522 gtk_container_propagate_expose(
2523 GTK_CONTAINER(PWidget(wMain
)), PWidget(scrollbarv
), ose
);
2526 errorStatus
= SC_STATUS_FAILURE
;
2533 void ScintillaGTK::ScrollSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
) {
2535 #if GTK_CHECK_VERSION(3,0,0)
2536 sciThis
->ScrollTo(static_cast<int>(gtk_adjustment_get_value(adj
)), false);
2538 sciThis
->ScrollTo(static_cast<int>(adj
->value
), false);
2541 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2545 void ScintillaGTK::ScrollHSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
) {
2547 #if GTK_CHECK_VERSION(3,0,0)
2548 sciThis
->HorizontalScrollTo(static_cast<int>(gtk_adjustment_get_value(adj
) * 2));
2550 sciThis
->HorizontalScrollTo(static_cast<int>(adj
->value
* 2));
2553 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2557 void ScintillaGTK::SelectionReceived(GtkWidget
*widget
,
2558 GtkSelectionData
*selection_data
, guint
) {
2559 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2560 //Platform::DebugPrintf("Selection received\n");
2561 sciThis
->ReceivedSelection(selection_data
);
2564 void ScintillaGTK::SelectionGet(GtkWidget
*widget
,
2565 GtkSelectionData
*selection_data
, guint info
, guint
) {
2566 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2568 //Platform::DebugPrintf("Selection get\n");
2569 if (SelectionOfGSD(selection_data
) == GDK_SELECTION_PRIMARY
) {
2570 if (sciThis
->primary
.s
== NULL
) {
2571 sciThis
->CopySelectionRange(&sciThis
->primary
);
2573 sciThis
->GetSelection(selection_data
, info
, &sciThis
->primary
);
2575 #ifndef USE_GTK_CLIPBOARD
2577 sciThis
->GetSelection(selection_data
, info
, &sciThis
->copyText
);
2581 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2585 gint
ScintillaGTK::SelectionClear(GtkWidget
*widget
, GdkEventSelection
*selection_event
) {
2586 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2587 //Platform::DebugPrintf("Selection clear\n");
2588 sciThis
->UnclaimSelection(selection_event
);
2589 if (GTK_WIDGET_CLASS(sciThis
->parentClass
)->selection_clear_event
) {
2590 return GTK_WIDGET_CLASS(sciThis
->parentClass
)->selection_clear_event(widget
, selection_event
);
2595 void ScintillaGTK::DragBegin(GtkWidget
*, GdkDragContext
*) {
2596 //Platform::DebugPrintf("DragBegin\n");
2599 gboolean
ScintillaGTK::DragMotionThis(GdkDragContext
*context
,
2600 gint x
, gint y
, guint dragtime
) {
2603 SetDragPosition(SPositionFromLocation(npt
, false, false, UserVirtualSpace()));
2604 #if GTK_CHECK_VERSION(3,0,0)
2605 GdkDragAction preferredAction
= gdk_drag_context_get_suggested_action(context
);
2606 GdkDragAction actions
= gdk_drag_context_get_actions(context
);
2608 GdkDragAction preferredAction
= context
->suggested_action
;
2609 GdkDragAction actions
= context
->actions
;
2611 SelectionPosition pos
= SPositionFromLocation(npt
);
2612 if ((inDragDrop
== ddDragging
) && (PositionInSelection(pos
.Position()))) {
2613 // Avoid dragging selection onto itself as that produces a move
2614 // with no real effect but which creates undo actions.
2615 preferredAction
= static_cast<GdkDragAction
>(0);
2616 } else if (actions
== static_cast<GdkDragAction
>
2617 (GDK_ACTION_COPY
| GDK_ACTION_MOVE
)) {
2618 preferredAction
= GDK_ACTION_MOVE
;
2620 gdk_drag_status(context
, preferredAction
, dragtime
);
2622 errorStatus
= SC_STATUS_FAILURE
;
2627 gboolean
ScintillaGTK::DragMotion(GtkWidget
*widget
, GdkDragContext
*context
,
2628 gint x
, gint y
, guint dragtime
) {
2629 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2630 return sciThis
->DragMotionThis(context
, x
, y
, dragtime
);
2633 void ScintillaGTK::DragLeave(GtkWidget
*widget
, GdkDragContext
* /*context*/, guint
) {
2634 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2636 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2637 //Platform::DebugPrintf("DragLeave %x\n", sciThis);
2639 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2643 void ScintillaGTK::DragEnd(GtkWidget
*widget
, GdkDragContext
* /*context*/) {
2644 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2646 // If drag did not result in drop here or elsewhere
2647 if (!sciThis
->dragWasDropped
)
2648 sciThis
->SetEmptySelection(sciThis
->posDrag
);
2649 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2650 //Platform::DebugPrintf("DragEnd %x %d\n", sciThis, sciThis->dragWasDropped);
2651 sciThis
->inDragDrop
= ddNone
;
2653 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2657 gboolean
ScintillaGTK::Drop(GtkWidget
*widget
, GdkDragContext
* /*context*/,
2658 gint
, gint
, guint
) {
2659 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2661 //Platform::DebugPrintf("Drop %x\n", sciThis);
2662 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2664 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2669 void ScintillaGTK::DragDataReceived(GtkWidget
*widget
, GdkDragContext
* /*context*/,
2670 gint
, gint
, GtkSelectionData
*selection_data
, guint
/*info*/, guint
) {
2671 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2673 sciThis
->ReceivedDrop(selection_data
);
2674 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2676 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2680 void ScintillaGTK::DragDataGet(GtkWidget
*widget
, GdkDragContext
*context
,
2681 GtkSelectionData
*selection_data
, guint info
, guint
) {
2682 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2684 sciThis
->dragWasDropped
= true;
2685 if (!sciThis
->sel
.Empty()) {
2686 sciThis
->GetSelection(selection_data
, info
, &sciThis
->drag
);
2688 #if GTK_CHECK_VERSION(3,0,0)
2689 GdkDragAction action
= gdk_drag_context_get_selected_action(context
);
2691 GdkDragAction action
= context
->action
;
2693 if (action
== GDK_ACTION_MOVE
) {
2694 for (size_t r
=0; r
<sciThis
->sel
.Count(); r
++) {
2695 if (sciThis
->posDrop
>= sciThis
->sel
.Range(r
).Start()) {
2696 if (sciThis
->posDrop
> sciThis
->sel
.Range(r
).End()) {
2697 sciThis
->posDrop
.Add(-sciThis
->sel
.Range(r
).Length());
2699 sciThis
->posDrop
.Add(-SelectionRange(sciThis
->posDrop
, sciThis
->sel
.Range(r
).Start()).Length());
2703 sciThis
->ClearSelection();
2705 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2707 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2711 int ScintillaGTK::TimeOut(ScintillaGTK
*sciThis
) {
2716 gboolean
ScintillaGTK::IdleCallback(ScintillaGTK
*sciThis
) {
2717 // Idler will be automatically stopped, if there is nothing
2718 // to do while idle.
2719 gdk_threads_enter();
2720 bool ret
= sciThis
->Idle();
2722 // FIXME: This will remove the idler from GTK, we don't want to
2723 // remove it as it is removed automatically when this function
2724 // returns false (although, it should be harmless).
2725 sciThis
->SetIdle(false);
2727 gdk_threads_leave();
2731 gboolean
ScintillaGTK::StyleIdle(ScintillaGTK
*sciThis
) {
2732 gdk_threads_enter();
2733 sciThis
->IdleStyling();
2734 gdk_threads_leave();
2735 // Idler will be automatically stopped
2739 void ScintillaGTK::QueueStyling(int upTo
) {
2740 Editor::QueueStyling(upTo
);
2741 if (!styleNeeded
.active
) {
2742 // Only allow one style needed to be queued
2743 styleNeeded
.active
= true;
2744 g_idle_add_full(G_PRIORITY_HIGH_IDLE
,
2745 reinterpret_cast<GSourceFunc
>(StyleIdle
), this, NULL
);
2749 void ScintillaGTK::PopUpCB(GtkMenuItem
*menuItem
, ScintillaGTK
*sciThis
) {
2750 guint action
= (sptr_t
)(g_object_get_data(G_OBJECT(menuItem
), "CmdNum"));
2752 sciThis
->Command(action
);
2756 gboolean
ScintillaGTK::PressCT(GtkWidget
*widget
, GdkEventButton
*event
, ScintillaGTK
*sciThis
) {
2758 if (event
->window
!= WindowFromWidget(widget
))
2760 if (event
->type
!= GDK_BUTTON_PRESS
)
2763 pt
.x
= int(event
->x
);
2764 pt
.y
= int(event
->y
);
2765 sciThis
->ct
.MouseClick(pt
);
2766 sciThis
->CallTipClick();
2772 #if GTK_CHECK_VERSION(3,0,0)
2774 gboolean
ScintillaGTK::DrawCT(GtkWidget
*widget
, cairo_t
*cr
, CallTip
*ctip
) {
2776 Surface
*surfaceWindow
= Surface::Allocate();
2777 if (surfaceWindow
) {
2778 surfaceWindow
->Init(cr
, widget
);
2779 surfaceWindow
->SetUnicodeMode(SC_CP_UTF8
== ctip
->codePage
);
2780 surfaceWindow
->SetDBCSMode(ctip
->codePage
);
2781 ctip
->PaintCT(surfaceWindow
);
2782 surfaceWindow
->Release();
2783 delete surfaceWindow
;
2786 // No pointer back to Scintilla to save status
2793 gboolean
ScintillaGTK::ExposeCT(GtkWidget
*widget
, GdkEventExpose
* /*ose*/, CallTip
*ctip
) {
2795 Surface
*surfaceWindow
= Surface::Allocate();
2796 if (surfaceWindow
) {
2797 surfaceWindow
->Init(WindowFromWidget(widget
), widget
);
2798 surfaceWindow
->SetUnicodeMode(SC_CP_UTF8
== ctip
->codePage
);
2799 surfaceWindow
->SetDBCSMode(ctip
->codePage
);
2800 ctip
->PaintCT(surfaceWindow
);
2801 surfaceWindow
->Release();
2802 delete surfaceWindow
;
2805 // No pointer back to Scintilla to save status
2812 sptr_t
ScintillaGTK::DirectFunction(
2813 ScintillaGTK
*sciThis
, unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
2814 return sciThis
->WndProc(iMessage
, wParam
, lParam
);
2817 sptr_t
scintilla_send_message(ScintillaObject
*sci
, unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
2818 ScintillaGTK
*psci
= reinterpret_cast<ScintillaGTK
*>(sci
->pscin
);
2819 return psci
->WndProc(iMessage
, wParam
, lParam
);
2822 static void scintilla_class_init(ScintillaClass
*klass
);
2823 static void scintilla_init(ScintillaObject
*sci
);
2825 extern void Platform_Initialise();
2826 extern void Platform_Finalise();
2828 GType
scintilla_get_type() {
2829 static GType scintilla_type
= 0;
2832 if (!scintilla_type
) {
2833 scintilla_type
= g_type_from_name("Scintilla");
2834 if (!scintilla_type
) {
2835 static GTypeInfo scintilla_info
= {
2836 (guint16
) sizeof (ScintillaClass
),
2837 NULL
, //(GBaseInitFunc)
2838 NULL
, //(GBaseFinalizeFunc)
2839 (GClassInitFunc
) scintilla_class_init
,
2840 NULL
, //(GClassFinalizeFunc)
2841 NULL
, //gconstpointer data
2842 (guint16
) sizeof (ScintillaObject
),
2844 (GInstanceInitFunc
) scintilla_init
,
2845 NULL
//(GTypeValueTable*)
2848 scintilla_type
= g_type_register_static(
2849 GTK_TYPE_CONTAINER
, "Scintilla", &scintilla_info
, (GTypeFlags
) 0);
2855 return scintilla_type
;
2858 void ScintillaGTK::ClassInit(OBJECT_CLASS
* object_class
, GtkWidgetClass
*widget_class
, GtkContainerClass
*container_class
) {
2859 Platform_Initialise();
2861 Scintilla_LinkLexers();
2863 atomClipboard
= gdk_atom_intern("CLIPBOARD", FALSE
);
2864 atomUTF8
= gdk_atom_intern("UTF8_STRING", FALSE
);
2865 atomString
= GDK_SELECTION_TYPE_STRING
;
2866 atomUriList
= gdk_atom_intern("text/uri-list", FALSE
);
2867 atomDROPFILES_DND
= gdk_atom_intern("DROPFILES_DND", FALSE
);
2869 // Define default signal handlers for the class: Could move more
2870 // of the signal handlers here (those that currently attached to wDraw
2871 // in Initialise() may require coordinate translation?)
2873 object_class
->finalize
= Destroy
;
2874 #if GTK_CHECK_VERSION(3,0,0)
2875 widget_class
->get_preferred_width
= GetPreferredWidth
;
2876 widget_class
->get_preferred_height
= GetPreferredHeight
;
2878 widget_class
->size_request
= SizeRequest
;
2880 widget_class
->size_allocate
= SizeAllocate
;
2881 #if GTK_CHECK_VERSION(3,0,0)
2882 widget_class
->draw
= DrawMain
;
2884 widget_class
->expose_event
= ExposeMain
;
2886 widget_class
->motion_notify_event
= Motion
;
2887 widget_class
->button_press_event
= Press
;
2888 widget_class
->button_release_event
= MouseRelease
;
2889 widget_class
->scroll_event
= ScrollEvent
;
2890 widget_class
->key_press_event
= KeyPress
;
2891 widget_class
->key_release_event
= KeyRelease
;
2892 widget_class
->focus_in_event
= FocusIn
;
2893 widget_class
->focus_out_event
= FocusOut
;
2894 widget_class
->selection_received
= SelectionReceived
;
2895 widget_class
->selection_get
= SelectionGet
;
2896 widget_class
->selection_clear_event
= SelectionClear
;
2898 widget_class
->drag_data_received
= DragDataReceived
;
2899 widget_class
->drag_motion
= DragMotion
;
2900 widget_class
->drag_leave
= DragLeave
;
2901 widget_class
->drag_end
= DragEnd
;
2902 widget_class
->drag_drop
= Drop
;
2903 widget_class
->drag_data_get
= DragDataGet
;
2905 widget_class
->realize
= Realize
;
2906 widget_class
->unrealize
= UnRealize
;
2907 widget_class
->map
= Map
;
2908 widget_class
->unmap
= UnMap
;
2910 container_class
->forall
= MainForAll
;
2913 #define SIG_MARSHAL scintilla_marshal_NONE__INT_POINTER
2914 #define MARSHAL_ARGUMENTS G_TYPE_INT, G_TYPE_POINTER
2916 static void scintilla_class_init(ScintillaClass
*klass
) {
2918 OBJECT_CLASS
*object_class
= (OBJECT_CLASS
*) klass
;
2919 GtkWidgetClass
*widget_class
= (GtkWidgetClass
*) klass
;
2920 GtkContainerClass
*container_class
= (GtkContainerClass
*) klass
;
2922 GSignalFlags sigflags
= GSignalFlags(G_SIGNAL_ACTION
| G_SIGNAL_RUN_LAST
);
2923 scintilla_signals
[COMMAND_SIGNAL
] = g_signal_new(
2925 G_TYPE_FROM_CLASS(object_class
),
2927 G_STRUCT_OFFSET(ScintillaClass
, command
),
2928 NULL
, //(GSignalAccumulator)
2932 2, MARSHAL_ARGUMENTS
);
2934 scintilla_signals
[NOTIFY_SIGNAL
] = g_signal_new(
2936 G_TYPE_FROM_CLASS(object_class
),
2938 G_STRUCT_OFFSET(ScintillaClass
, notify
),
2943 2, MARSHAL_ARGUMENTS
);
2945 klass
->command
= NULL
;
2946 klass
->notify
= NULL
;
2948 ScintillaGTK::ClassInit(object_class
, widget_class
, container_class
);
2953 static void scintilla_init(ScintillaObject
*sci
) {
2955 #if GTK_CHECK_VERSION(2,20,0)
2956 gtk_widget_set_can_focus(GTK_WIDGET(sci
), TRUE
);
2958 GTK_WIDGET_SET_FLAGS(sci
, GTK_CAN_FOCUS
);
2960 sci
->pscin
= new ScintillaGTK(sci
);
2965 GtkWidget
* scintilla_new() {
2966 return GTK_WIDGET(g_object_new(scintilla_get_type(), NULL
));
2969 void scintilla_set_id(ScintillaObject
*sci
, uptr_t id
) {
2970 ScintillaGTK
*psci
= reinterpret_cast<ScintillaGTK
*>(sci
->pscin
);
2974 void scintilla_release_resources(void) {
2976 Platform_Finalise();