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.
20 #include <gdk/gdkkeysyms.h>
29 #include "Scintilla.h"
30 #include "ScintillaWidget.h"
34 #include "StringCopy.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"
50 #include "CaseFolder.h"
52 #include "Selection.h"
53 #include "PositionCache.h"
55 #include "ScintillaBase.h"
56 #include "UniConversion.h"
57 #include "CaseConvert.h"
59 #include "scintilla-marshal.h"
64 #include "LexerModule.h"
65 #include "ExternalLexer.h"
68 #include "Converter.h"
70 #if defined(__clang__)
71 // Clang 3.0 incorrectly displays sentinel warnings. Fixed by clang 3.1.
72 #pragma GCC diagnostic ignored "-Wsentinel"
75 #if GTK_CHECK_VERSION(2,20,0)
76 #define IS_WIDGET_REALIZED(w) (gtk_widget_get_realized(GTK_WIDGET(w)))
77 #define IS_WIDGET_MAPPED(w) (gtk_widget_get_mapped(GTK_WIDGET(w)))
78 #define IS_WIDGET_VISIBLE(w) (gtk_widget_get_visible(GTK_WIDGET(w)))
80 #define IS_WIDGET_REALIZED(w) (GTK_WIDGET_REALIZED(w))
81 #define IS_WIDGET_MAPPED(w) (GTK_WIDGET_MAPPED(w))
82 #define IS_WIDGET_VISIBLE(w) (GTK_WIDGET_VISIBLE(w))
85 static GdkWindow
*WindowFromWidget(GtkWidget
*w
) {
86 #if GTK_CHECK_VERSION(3,0,0)
87 return gtk_widget_get_window(w
);
94 // Constant conditional expressions are because of GTK+ headers
95 #pragma warning(disable: 4127)
96 // Ignore unreferenced local functions in GTK+ headers
97 #pragma warning(disable: 4505)
100 #define OBJECT_CLASS GObjectClass
103 using namespace Scintilla
;
106 static GdkWindow
*PWindow(const Window
&w
) {
107 GtkWidget
*widget
= reinterpret_cast<GtkWidget
*>(w
.GetID());
108 #if GTK_CHECK_VERSION(3,0,0)
109 return gtk_widget_get_window(widget
);
111 return widget
->window
;
115 extern std::string
UTF8FromLatin1(const char *s
, int len
);
117 class ScintillaGTK
: public ScintillaBase
{
118 _ScintillaObject
*sci
;
122 GtkAdjustment
*adjustmentv
;
123 GtkAdjustment
*adjustmenth
;
124 int verticalScrollBarWidth
;
125 int horizontalScrollBarHeight
;
127 SelectionText primary
;
129 GdkEventButton
*evbtn
;
133 int rectangularSelectionModifier
;
135 GtkWidgetClass
*parentClass
;
137 static GdkAtom atomClipboard
;
138 static GdkAtom atomUTF8
;
139 static GdkAtom atomString
;
140 static GdkAtom atomUriList
;
141 static GdkAtom atomDROPFILES_DND
;
145 CLIPFORMAT cfColumnSelect
;
150 GtkIMContext
*im_context
;
152 // Wheel mouse support
153 unsigned int linesPerScroll
;
154 GTimeVal lastWheelMouseTime
;
155 gint lastWheelMouseDirection
;
156 gint wheelMouseIntensity
;
158 #if GTK_CHECK_VERSION(3,0,0)
159 cairo_rectangle_list_t
*rgnUpdate
;
161 GdkRegion
*rgnUpdate
;
163 bool repaintFullWindow
;
165 // Private so ScintillaGTK objects can not be copied
166 ScintillaGTK(const ScintillaGTK
&);
167 ScintillaGTK
&operator=(const ScintillaGTK
&);
170 explicit ScintillaGTK(_ScintillaObject
*sci_
);
171 virtual ~ScintillaGTK();
172 static void ClassInit(OBJECT_CLASS
* object_class
, GtkWidgetClass
*widget_class
, GtkContainerClass
*container_class
);
174 virtual void Initialise();
175 virtual void Finalise();
176 virtual bool AbandonPaint();
177 virtual void DisplayCursor(Window::Cursor c
);
178 virtual bool DragThreshold(Point ptStart
, Point ptNow
);
179 virtual void StartDrag();
180 int TargetAsUTF8(char *text
);
181 int EncodedFromUTF8(char *utf8
, char *encoded
) const;
182 virtual bool ValidCodePage(int codePage
) const;
183 public: // Public for scintilla_send_message
184 virtual sptr_t
WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
186 virtual sptr_t
DefWndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
187 virtual void SetTicking(bool on
);
188 virtual bool SetIdle(bool on
);
189 virtual void SetMouseCapture(bool on
);
190 virtual bool HaveMouseCapture();
191 virtual bool PaintContains(PRectangle rc
);
193 virtual PRectangle
GetClientRectangle();
194 virtual void ScrollText(int linesToMove
);
195 virtual void SetVerticalScrollPos();
196 virtual void SetHorizontalScrollPos();
197 virtual bool ModifyScrollBars(int nMax
, int nPage
);
198 void ReconfigureScrollBars();
199 virtual void NotifyChange();
200 virtual void NotifyFocus(bool focus
);
201 virtual void NotifyParent(SCNotification scn
);
202 void NotifyKey(int key
, int modifiers
);
203 void NotifyURIDropped(const char *list
);
204 const char *CharacterSetID() const;
205 virtual CaseFolder
*CaseFolderForEncoding();
206 virtual std::string
CaseMapString(const std::string
&s
, int caseMapping
);
207 virtual int KeyDefault(int key
, int modifiers
);
208 virtual void CopyToClipboard(const SelectionText
&selectedText
);
210 virtual void Paste();
211 virtual void CreateCallTipWindow(PRectangle rc
);
212 virtual void AddToPopUp(const char *label
, int cmd
= 0, bool enabled
= true);
213 bool OwnPrimarySelection();
214 virtual void ClaimSelection();
215 void GetGtkSelectionText(GtkSelectionData
*selectionData
, SelectionText
&selText
);
216 void ReceivedSelection(GtkSelectionData
*selection_data
);
217 void ReceivedDrop(GtkSelectionData
*selection_data
);
218 static void GetSelection(GtkSelectionData
*selection_data
, guint info
, SelectionText
*selected
);
219 void StoreOnClipboard(SelectionText
*clipText
);
220 static void ClipboardGetSelection(GtkClipboard
* clip
, GtkSelectionData
*selection_data
, guint info
, void *data
);
221 static void ClipboardClearSelection(GtkClipboard
* clip
, void *data
);
223 void UnclaimSelection(GdkEventSelection
*selection_event
);
224 void Resize(int width
, int height
);
226 // Callback functions
227 void RealizeThis(GtkWidget
*widget
);
228 static void Realize(GtkWidget
*widget
);
229 void UnRealizeThis(GtkWidget
*widget
);
230 static void UnRealize(GtkWidget
*widget
);
232 static void Map(GtkWidget
*widget
);
234 static void UnMap(GtkWidget
*widget
);
235 gint
FocusInThis(GtkWidget
*widget
);
236 static gint
FocusIn(GtkWidget
*widget
, GdkEventFocus
*event
);
237 gint
FocusOutThis(GtkWidget
*widget
);
238 static gint
FocusOut(GtkWidget
*widget
, GdkEventFocus
*event
);
239 static void SizeRequest(GtkWidget
*widget
, GtkRequisition
*requisition
);
240 #if GTK_CHECK_VERSION(3,0,0)
241 static void GetPreferredWidth(GtkWidget
*widget
, gint
*minimalWidth
, gint
*naturalWidth
);
242 static void GetPreferredHeight(GtkWidget
*widget
, gint
*minimalHeight
, gint
*naturalHeight
);
244 static void SizeAllocate(GtkWidget
*widget
, GtkAllocation
*allocation
);
245 #if GTK_CHECK_VERSION(3,0,0)
246 gboolean
DrawTextThis(cairo_t
*cr
);
247 static gboolean
DrawText(GtkWidget
*widget
, cairo_t
*cr
, ScintillaGTK
*sciThis
);
248 gboolean
DrawThis(cairo_t
*cr
);
249 static gboolean
DrawMain(GtkWidget
*widget
, cairo_t
*cr
);
251 gboolean
ExposeTextThis(GtkWidget
*widget
, GdkEventExpose
*ose
);
252 static gboolean
ExposeText(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
);
253 gboolean
Expose(GtkWidget
*widget
, GdkEventExpose
*ose
);
254 static gboolean
ExposeMain(GtkWidget
*widget
, GdkEventExpose
*ose
);
256 static void Draw(GtkWidget
*widget
, GdkRectangle
*area
);
257 void ForAll(GtkCallback callback
, gpointer callback_data
);
258 static void MainForAll(GtkContainer
*container
, gboolean include_internals
, GtkCallback callback
, gpointer callback_data
);
260 static void ScrollSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
);
261 static void ScrollHSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
);
262 gint
PressThis(GdkEventButton
*event
);
263 static gint
Press(GtkWidget
*widget
, GdkEventButton
*event
);
264 static gint
MouseRelease(GtkWidget
*widget
, GdkEventButton
*event
);
265 static gint
ScrollEvent(GtkWidget
*widget
, GdkEventScroll
*event
);
266 static gint
Motion(GtkWidget
*widget
, GdkEventMotion
*event
);
267 gboolean
KeyThis(GdkEventKey
*event
);
268 static gboolean
KeyPress(GtkWidget
*widget
, GdkEventKey
*event
);
269 static gboolean
KeyRelease(GtkWidget
*widget
, GdkEventKey
*event
);
270 #if GTK_CHECK_VERSION(3,0,0)
271 gboolean
DrawPreeditThis(GtkWidget
*widget
, cairo_t
*cr
);
272 static gboolean
DrawPreedit(GtkWidget
*widget
, cairo_t
*cr
, ScintillaGTK
*sciThis
);
274 gboolean
ExposePreeditThis(GtkWidget
*widget
, GdkEventExpose
*ose
);
275 static gboolean
ExposePreedit(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
);
277 void CommitThis(char *str
);
278 static void Commit(GtkIMContext
*context
, char *str
, ScintillaGTK
*sciThis
);
279 void PreeditChangedThis();
280 static void PreeditChanged(GtkIMContext
*context
, ScintillaGTK
*sciThis
);
281 static void StyleSetText(GtkWidget
*widget
, GtkStyle
*previous
, void*);
282 static void RealizeText(GtkWidget
*widget
, void*);
283 static void Destroy(GObject
*object
);
284 static void SelectionReceived(GtkWidget
*widget
, GtkSelectionData
*selection_data
,
286 static void SelectionGet(GtkWidget
*widget
, GtkSelectionData
*selection_data
,
287 guint info
, guint time
);
288 static gint
SelectionClear(GtkWidget
*widget
, GdkEventSelection
*selection_event
);
289 gboolean
DragMotionThis(GdkDragContext
*context
, gint x
, gint y
, guint dragtime
);
290 static gboolean
DragMotion(GtkWidget
*widget
, GdkDragContext
*context
,
291 gint x
, gint y
, guint dragtime
);
292 static void DragLeave(GtkWidget
*widget
, GdkDragContext
*context
,
294 static void DragEnd(GtkWidget
*widget
, GdkDragContext
*context
);
295 static gboolean
Drop(GtkWidget
*widget
, GdkDragContext
*context
,
296 gint x
, gint y
, guint time
);
297 static void DragDataReceived(GtkWidget
*widget
, GdkDragContext
*context
,
298 gint x
, gint y
, GtkSelectionData
*selection_data
, guint info
, guint time
);
299 static void DragDataGet(GtkWidget
*widget
, GdkDragContext
*context
,
300 GtkSelectionData
*selection_data
, guint info
, guint time
);
301 static gboolean
TimeOut(ScintillaGTK
*sciThis
);
302 static gboolean
IdleCallback(ScintillaGTK
*sciThis
);
303 static gboolean
StyleIdle(ScintillaGTK
*sciThis
);
304 virtual void QueueIdleWork(WorkNeeded::workItems items
, int upTo
);
305 static void PopUpCB(GtkMenuItem
*menuItem
, ScintillaGTK
*sciThis
);
307 #if GTK_CHECK_VERSION(3,0,0)
308 static gboolean
DrawCT(GtkWidget
*widget
, cairo_t
*cr
, CallTip
*ctip
);
310 static gboolean
ExposeCT(GtkWidget
*widget
, GdkEventExpose
*ose
, CallTip
*ct
);
312 static gboolean
PressCT(GtkWidget
*widget
, GdkEventButton
*event
, ScintillaGTK
*sciThis
);
314 static sptr_t
DirectFunction(sptr_t ptr
,
315 unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
324 static gint scintilla_signals
[LAST_SIGNAL
] = { 0 };
329 TARGET_COMPOUND_TEXT
,
334 GdkAtom
ScintillaGTK::atomClipboard
= 0;
335 GdkAtom
ScintillaGTK::atomUTF8
= 0;
336 GdkAtom
ScintillaGTK::atomString
= 0;
337 GdkAtom
ScintillaGTK::atomUriList
= 0;
338 GdkAtom
ScintillaGTK::atomDROPFILES_DND
= 0;
340 static const GtkTargetEntry clipboardCopyTargets
[] = {
341 { (gchar
*) "UTF8_STRING", 0, TARGET_UTF8_STRING
},
342 { (gchar
*) "STRING", 0, TARGET_STRING
},
344 static const gint nClipboardCopyTargets
= ELEMENTS(clipboardCopyTargets
);
346 static const GtkTargetEntry clipboardPasteTargets
[] = {
347 { (gchar
*) "text/uri-list", 0, TARGET_URI
},
348 { (gchar
*) "UTF8_STRING", 0, TARGET_UTF8_STRING
},
349 { (gchar
*) "STRING", 0, TARGET_STRING
},
351 static const gint nClipboardPasteTargets
= ELEMENTS(clipboardPasteTargets
);
353 static GtkWidget
*PWidget(Window
&w
) {
354 return reinterpret_cast<GtkWidget
*>(w
.GetID());
357 static ScintillaGTK
*ScintillaFromWidget(GtkWidget
*widget
) {
358 ScintillaObject
*scio
= reinterpret_cast<ScintillaObject
*>(widget
);
359 return reinterpret_cast<ScintillaGTK
*>(scio
->pscin
);
362 ScintillaGTK::ScintillaGTK(_ScintillaObject
*sci_
) :
363 adjustmentv(0), adjustmenth(0),
364 verticalScrollBarWidth(30), horizontalScrollBarHeight(30),
365 evbtn(0), capturedMouse(false), dragWasDropped(false),
366 lastKey(0), rectangularSelectionModifier(SCMOD_CTRL
), parentClass(0),
368 lastWheelMouseDirection(0),
369 wheelMouseIntensity(0),
371 repaintFullWindow(false) {
373 wMain
= GTK_WIDGET(sci
);
376 rectangularSelectionModifier
= SCMOD_ALT
;
378 rectangularSelectionModifier
= SCMOD_CTRL
;
382 // There does not seem to be a real standard for indicating that the clipboard
383 // contains a rectangular selection, so copy Developer Studio.
384 cfColumnSelect
= static_cast<CLIPFORMAT
>(
385 ::RegisterClipboardFormat("MSDEVColumnSelect"));
387 // Get intellimouse parameters when running on win32; otherwise use
388 // reasonable default
389 #ifndef SPI_GETWHEELSCROLLLINES
390 #define SPI_GETWHEELSCROLLLINES 104
392 ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &linesPerScroll
, 0);
396 lastWheelMouseTime
.tv_sec
= 0;
397 lastWheelMouseTime
.tv_usec
= 0;
402 ScintillaGTK::~ScintillaGTK() {
403 g_idle_remove_by_data(this);
405 gdk_event_free(reinterpret_cast<GdkEvent
*>(evbtn
));
410 static void UnRefCursor(GdkCursor
*cursor
) {
411 #if GTK_CHECK_VERSION(3,0,0)
412 g_object_unref(cursor
);
414 gdk_cursor_unref(cursor
);
418 void ScintillaGTK::RealizeThis(GtkWidget
*widget
) {
419 //Platform::DebugPrintf("ScintillaGTK::realize this\n");
420 #if GTK_CHECK_VERSION(2,20,0)
421 gtk_widget_set_realized(widget
, TRUE
);
423 GTK_WIDGET_SET_FLAGS(widget
, GTK_REALIZED
);
426 attrs
.window_type
= GDK_WINDOW_CHILD
;
427 GtkAllocation allocation
;
428 #if GTK_CHECK_VERSION(3,0,0)
429 gtk_widget_get_allocation(widget
, &allocation
);
431 allocation
= widget
->allocation
;
433 attrs
.x
= allocation
.x
;
434 attrs
.y
= allocation
.y
;
435 attrs
.width
= allocation
.width
;
436 attrs
.height
= allocation
.height
;
437 attrs
.wclass
= GDK_INPUT_OUTPUT
;
438 attrs
.visual
= gtk_widget_get_visual(widget
);
439 #if !GTK_CHECK_VERSION(3,0,0)
440 attrs
.colormap
= gtk_widget_get_colormap(widget
);
442 attrs
.event_mask
= gtk_widget_get_events(widget
) | GDK_EXPOSURE_MASK
;
443 GdkCursor
*cursor
= gdk_cursor_new(GDK_XTERM
);
444 attrs
.cursor
= cursor
;
445 #if GTK_CHECK_VERSION(3,0,0)
446 gtk_widget_set_window(widget
, gdk_window_new(gtk_widget_get_parent_window(widget
), &attrs
,
447 GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
| GDK_WA_CURSOR
));
448 gdk_window_set_user_data(gtk_widget_get_window(widget
), widget
);
449 GtkStyleContext
*styleContext
= gtk_widget_get_style_context(widget
);
451 GdkRGBA colourBackWidget
;
452 gtk_style_context_get_background_color(styleContext
, GTK_STATE_FLAG_NORMAL
, &colourBackWidget
);
453 gdk_window_set_background_rgba(gtk_widget_get_window(widget
), &colourBackWidget
);
455 gdk_window_show(gtk_widget_get_window(widget
));
458 widget
->window
= gdk_window_new(gtk_widget_get_parent_window(widget
), &attrs
,
459 GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
| GDK_WA_COLORMAP
| GDK_WA_CURSOR
);
460 gdk_window_set_user_data(widget
->window
, widget
);
461 widget
->style
= gtk_style_attach(widget
->style
, widget
->window
);
462 gdk_window_set_background(widget
->window
, &widget
->style
->bg
[GTK_STATE_NORMAL
]);
463 gdk_window_show(widget
->window
);
466 wPreedit
= gtk_window_new(GTK_WINDOW_POPUP
);
467 wPreeditDraw
= gtk_drawing_area_new();
468 GtkWidget
*predrw
= PWidget(wPreeditDraw
); // No code inside the G_OBJECT macro
469 #if GTK_CHECK_VERSION(3,0,0)
470 g_signal_connect(G_OBJECT(predrw
), "draw",
471 G_CALLBACK(DrawPreedit
), this);
473 g_signal_connect(G_OBJECT(predrw
), "expose_event",
474 G_CALLBACK(ExposePreedit
), this);
476 gtk_container_add(GTK_CONTAINER(PWidget(wPreedit
)), predrw
);
477 gtk_widget_realize(PWidget(wPreedit
));
478 gtk_widget_realize(predrw
);
479 gtk_widget_show(predrw
);
481 im_context
= gtk_im_multicontext_new();
482 g_signal_connect(G_OBJECT(im_context
), "commit",
483 G_CALLBACK(Commit
), this);
484 g_signal_connect(G_OBJECT(im_context
), "preedit_changed",
485 G_CALLBACK(PreeditChanged
), this);
486 gtk_im_context_set_client_window(im_context
, WindowFromWidget(widget
));
487 GtkWidget
*widtxt
= PWidget(wText
); // // No code inside the G_OBJECT macro
488 g_signal_connect_after(G_OBJECT(widtxt
), "style_set",
489 G_CALLBACK(ScintillaGTK::StyleSetText
), NULL
);
490 g_signal_connect_after(G_OBJECT(widtxt
), "realize",
491 G_CALLBACK(ScintillaGTK::RealizeText
), NULL
);
492 gtk_widget_realize(widtxt
);
493 gtk_widget_realize(PWidget(scrollbarv
));
494 gtk_widget_realize(PWidget(scrollbarh
));
496 cursor
= gdk_cursor_new(GDK_XTERM
);
497 gdk_window_set_cursor(PWindow(wText
), cursor
);
500 cursor
= gdk_cursor_new(GDK_LEFT_PTR
);
501 gdk_window_set_cursor(PWindow(scrollbarv
), cursor
);
504 cursor
= gdk_cursor_new(GDK_LEFT_PTR
);
505 gdk_window_set_cursor(PWindow(scrollbarh
), cursor
);
508 gtk_selection_add_targets(widget
, GDK_SELECTION_PRIMARY
,
509 clipboardCopyTargets
, nClipboardCopyTargets
);
512 void ScintillaGTK::Realize(GtkWidget
*widget
) {
513 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
514 sciThis
->RealizeThis(widget
);
517 void ScintillaGTK::UnRealizeThis(GtkWidget
*widget
) {
519 gtk_selection_clear_targets(widget
, GDK_SELECTION_PRIMARY
);
521 if (IS_WIDGET_MAPPED(widget
)) {
522 gtk_widget_unmap(widget
);
524 #if GTK_CHECK_VERSION(2,20,0)
525 gtk_widget_set_realized(widget
, FALSE
);
527 GTK_WIDGET_UNSET_FLAGS(widget
, GTK_REALIZED
);
529 gtk_widget_unrealize(PWidget(wText
));
530 gtk_widget_unrealize(PWidget(scrollbarv
));
531 gtk_widget_unrealize(PWidget(scrollbarh
));
532 gtk_widget_unrealize(PWidget(wPreedit
));
533 gtk_widget_unrealize(PWidget(wPreeditDraw
));
534 g_object_unref(im_context
);
536 if (GTK_WIDGET_CLASS(parentClass
)->unrealize
)
537 GTK_WIDGET_CLASS(parentClass
)->unrealize(widget
);
541 errorStatus
= SC_STATUS_FAILURE
;
545 void ScintillaGTK::UnRealize(GtkWidget
*widget
) {
546 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
547 sciThis
->UnRealizeThis(widget
);
550 static void MapWidget(GtkWidget
*widget
) {
552 IS_WIDGET_VISIBLE(widget
) &&
553 !IS_WIDGET_MAPPED(widget
)) {
554 gtk_widget_map(widget
);
558 void ScintillaGTK::MapThis() {
560 //Platform::DebugPrintf("ScintillaGTK::map this\n");
561 #if GTK_CHECK_VERSION(2,20,0)
562 gtk_widget_set_mapped(PWidget(wMain
), TRUE
);
564 GTK_WIDGET_SET_FLAGS(PWidget(wMain
), GTK_MAPPED
);
566 MapWidget(PWidget(wText
));
567 MapWidget(PWidget(scrollbarh
));
568 MapWidget(PWidget(scrollbarv
));
569 wMain
.SetCursor(Window::cursorArrow
);
570 scrollbarv
.SetCursor(Window::cursorArrow
);
571 scrollbarh
.SetCursor(Window::cursorArrow
);
573 gdk_window_show(PWindow(wMain
));
575 errorStatus
= SC_STATUS_FAILURE
;
579 void ScintillaGTK::Map(GtkWidget
*widget
) {
580 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
584 void ScintillaGTK::UnMapThis() {
586 //Platform::DebugPrintf("ScintillaGTK::unmap this\n");
587 #if GTK_CHECK_VERSION(2,20,0)
588 gtk_widget_set_mapped(PWidget(wMain
), FALSE
);
590 GTK_WIDGET_UNSET_FLAGS(PWidget(wMain
), GTK_MAPPED
);
593 gdk_window_hide(PWindow(wMain
));
594 gtk_widget_unmap(PWidget(wText
));
595 gtk_widget_unmap(PWidget(scrollbarh
));
596 gtk_widget_unmap(PWidget(scrollbarv
));
598 errorStatus
= SC_STATUS_FAILURE
;
602 void ScintillaGTK::UnMap(GtkWidget
*widget
) {
603 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
604 sciThis
->UnMapThis();
607 void ScintillaGTK::ForAll(GtkCallback callback
, gpointer callback_data
) {
609 (*callback
) (PWidget(wText
), callback_data
);
610 (*callback
) (PWidget(scrollbarv
), callback_data
);
611 (*callback
) (PWidget(scrollbarh
), callback_data
);
613 errorStatus
= SC_STATUS_FAILURE
;
617 void ScintillaGTK::MainForAll(GtkContainer
*container
, gboolean include_internals
, GtkCallback callback
, gpointer callback_data
) {
618 ScintillaGTK
*sciThis
= ScintillaFromWidget((GtkWidget
*)container
);
620 if (callback
!= NULL
&& include_internals
) {
621 sciThis
->ForAll(callback
, callback_data
);
625 gint
ScintillaGTK::FocusInThis(GtkWidget
*widget
) {
628 if (im_context
!= NULL
) {
632 gtk_im_context_get_preedit_string(im_context
, &str
, NULL
, &cursor_pos
);
633 if (PWidget(wPreedit
) != NULL
) {
634 if (strlen(str
) > 0) {
635 gtk_widget_show(PWidget(wPreedit
));
637 gtk_widget_hide(PWidget(wPreedit
));
641 gtk_im_context_focus_in(im_context
);
645 errorStatus
= SC_STATUS_FAILURE
;
650 gint
ScintillaGTK::FocusIn(GtkWidget
*widget
, GdkEventFocus
* /*event*/) {
651 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
652 return sciThis
->FocusInThis(widget
);
655 gint
ScintillaGTK::FocusOutThis(GtkWidget
*widget
) {
657 SetFocusState(false);
659 if (PWidget(wPreedit
) != NULL
)
660 gtk_widget_hide(PWidget(wPreedit
));
661 if (im_context
!= NULL
)
662 gtk_im_context_focus_out(im_context
);
665 errorStatus
= SC_STATUS_FAILURE
;
670 gint
ScintillaGTK::FocusOut(GtkWidget
*widget
, GdkEventFocus
* /*event*/) {
671 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
672 return sciThis
->FocusOutThis(widget
);
675 void ScintillaGTK::SizeRequest(GtkWidget
*widget
, GtkRequisition
*requisition
) {
676 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
677 requisition
->width
= 1;
678 requisition
->height
= 1;
679 GtkRequisition child_requisition
;
680 #if GTK_CHECK_VERSION(3,0,0)
681 gtk_widget_get_preferred_size(PWidget(sciThis
->scrollbarh
), NULL
, &child_requisition
);
682 gtk_widget_get_preferred_size(PWidget(sciThis
->scrollbarv
), NULL
, &child_requisition
);
684 gtk_widget_size_request(PWidget(sciThis
->scrollbarh
), &child_requisition
);
685 gtk_widget_size_request(PWidget(sciThis
->scrollbarv
), &child_requisition
);
689 #if GTK_CHECK_VERSION(3,0,0)
691 void ScintillaGTK::GetPreferredWidth(GtkWidget
*widget
, gint
*minimalWidth
, gint
*naturalWidth
) {
692 GtkRequisition requisition
;
693 SizeRequest(widget
, &requisition
);
694 *minimalWidth
= *naturalWidth
= requisition
.width
;
697 void ScintillaGTK::GetPreferredHeight(GtkWidget
*widget
, gint
*minimalHeight
, gint
*naturalHeight
) {
698 GtkRequisition requisition
;
699 SizeRequest(widget
, &requisition
);
700 *minimalHeight
= *naturalHeight
= requisition
.height
;
705 void ScintillaGTK::SizeAllocate(GtkWidget
*widget
, GtkAllocation
*allocation
) {
706 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
708 #if GTK_CHECK_VERSION(2,20,0)
709 gtk_widget_set_allocation(widget
, allocation
);
711 widget
->allocation
= *allocation
;
713 if (IS_WIDGET_REALIZED(widget
))
714 gdk_window_move_resize(WindowFromWidget(widget
),
720 sciThis
->Resize(allocation
->width
, allocation
->height
);
723 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
727 void ScintillaGTK::Initialise() {
728 //Platform::DebugPrintf("ScintillaGTK::Initialise\n");
729 parentClass
= reinterpret_cast<GtkWidgetClass
*>(
730 g_type_class_ref(gtk_container_get_type()));
732 #if GTK_CHECK_VERSION(2,20,0)
733 gtk_widget_set_can_focus(PWidget(wMain
), TRUE
);
734 gtk_widget_set_sensitive(PWidget(wMain
), TRUE
);
736 GTK_WIDGET_SET_FLAGS(PWidget(wMain
), GTK_CAN_FOCUS
);
737 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(PWidget(wMain
)), GTK_SENSITIVE
);
739 gtk_widget_set_events(PWidget(wMain
),
744 | GDK_KEY_RELEASE_MASK
745 | GDK_FOCUS_CHANGE_MASK
746 | GDK_LEAVE_NOTIFY_MASK
747 | GDK_BUTTON_PRESS_MASK
748 | GDK_BUTTON_RELEASE_MASK
749 | GDK_POINTER_MOTION_MASK
750 | GDK_POINTER_MOTION_HINT_MASK
);
752 wText
= gtk_drawing_area_new();
753 gtk_widget_set_parent(PWidget(wText
), PWidget(wMain
));
754 GtkWidget
*widtxt
= PWidget(wText
); // No code inside the G_OBJECT macro
755 gtk_widget_show(widtxt
);
756 #if GTK_CHECK_VERSION(3,0,0)
757 g_signal_connect(G_OBJECT(widtxt
), "draw",
758 G_CALLBACK(ScintillaGTK::DrawText
), this);
760 g_signal_connect(G_OBJECT(widtxt
), "expose_event",
761 G_CALLBACK(ScintillaGTK::ExposeText
), this);
763 #if GTK_CHECK_VERSION(3,0,0)
764 // we need a runtime check because we don't want double buffering when
765 // running on >= 3.9.2
766 if (gtk_check_version(3,9,2) != NULL
/* on < 3.9.2 */)
769 // Avoid background drawing flash/missing redraws
770 gtk_widget_set_double_buffered(widtxt
, FALSE
);
772 gtk_widget_set_events(widtxt
, GDK_EXPOSURE_MASK
);
773 gtk_widget_set_size_request(widtxt
, 100, 100);
774 adjustmentv
= GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 201.0, 1.0, 20.0, 20.0));
775 #if GTK_CHECK_VERSION(3,0,0)
776 scrollbarv
= gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL
, GTK_ADJUSTMENT(adjustmentv
));
778 scrollbarv
= gtk_vscrollbar_new(GTK_ADJUSTMENT(adjustmentv
));
780 #if GTK_CHECK_VERSION(2,20,0)
781 gtk_widget_set_can_focus(PWidget(scrollbarv
), FALSE
);
783 GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarv
), GTK_CAN_FOCUS
);
785 g_signal_connect(G_OBJECT(adjustmentv
), "value_changed",
786 G_CALLBACK(ScrollSignal
), this);
787 gtk_widget_set_parent(PWidget(scrollbarv
), PWidget(wMain
));
788 gtk_widget_show(PWidget(scrollbarv
));
790 adjustmenth
= GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 101.0, 1.0, 20.0, 20.0));
791 #if GTK_CHECK_VERSION(3,0,0)
792 scrollbarh
= gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL
, GTK_ADJUSTMENT(adjustmenth
));
794 scrollbarh
= gtk_hscrollbar_new(GTK_ADJUSTMENT(adjustmenth
));
796 #if GTK_CHECK_VERSION(2,20,0)
797 gtk_widget_set_can_focus(PWidget(scrollbarh
), FALSE
);
799 GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarh
), GTK_CAN_FOCUS
);
801 g_signal_connect(G_OBJECT(adjustmenth
), "value_changed",
802 G_CALLBACK(ScrollHSignal
), this);
803 gtk_widget_set_parent(PWidget(scrollbarh
), PWidget(wMain
));
804 gtk_widget_show(PWidget(scrollbarh
));
806 gtk_widget_grab_focus(PWidget(wMain
));
808 gtk_drag_dest_set(GTK_WIDGET(PWidget(wMain
)),
809 GTK_DEST_DEFAULT_ALL
, clipboardPasteTargets
, nClipboardPasteTargets
,
810 static_cast<GdkDragAction
>(GDK_ACTION_COPY
| GDK_ACTION_MOVE
));
812 // Set caret period based on GTK settings
813 gboolean blinkOn
= false;
814 if (g_object_class_find_property(G_OBJECT_GET_CLASS(
815 G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink")) {
816 g_object_get(G_OBJECT(
817 gtk_settings_get_default()), "gtk-cursor-blink", &blinkOn
, NULL
);
820 g_object_class_find_property(G_OBJECT_GET_CLASS(
821 G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink-time")) {
823 g_object_get(G_OBJECT(
824 gtk_settings_get_default()), "gtk-cursor-blink-time", &value
, NULL
);
825 caret
.period
= gint(value
/ 1.75);
833 void ScintillaGTK::Finalise() {
835 ScintillaBase::Finalise();
838 bool ScintillaGTK::AbandonPaint() {
839 if ((paintState
== painting
) && !paintingAllText
) {
840 repaintFullWindow
= true;
845 void ScintillaGTK::DisplayCursor(Window::Cursor c
) {
846 if (cursorMode
== SC_CURSORNORMAL
)
849 wText
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
852 bool ScintillaGTK::DragThreshold(Point ptStart
, Point ptNow
) {
853 return gtk_drag_check_threshold(GTK_WIDGET(PWidget(wMain
)),
854 ptStart
.x
, ptStart
.y
, ptNow
.x
, ptNow
.y
);
857 void ScintillaGTK::StartDrag() {
858 PLATFORM_ASSERT(evbtn
!= 0);
859 dragWasDropped
= false;
860 inDragDrop
= ddDragging
;
861 GtkTargetList
*tl
= gtk_target_list_new(clipboardCopyTargets
, nClipboardCopyTargets
);
862 #if GTK_CHECK_VERSION(3,10,0)
863 gtk_drag_begin_with_coordinates(GTK_WIDGET(PWidget(wMain
)),
865 static_cast<GdkDragAction
>(GDK_ACTION_COPY
| GDK_ACTION_MOVE
),
867 reinterpret_cast<GdkEvent
*>(evbtn
),
870 gtk_drag_begin(GTK_WIDGET(PWidget(wMain
)),
872 static_cast<GdkDragAction
>(GDK_ACTION_COPY
| GDK_ACTION_MOVE
),
874 reinterpret_cast<GdkEvent
*>(evbtn
));
878 static std::string
ConvertText(const char *s
, size_t len
, const char *charSetDest
,
879 const char *charSetSource
, bool transliterations
, bool silent
=false) {
880 // s is not const because of different versions of iconv disagreeing about const
881 std::string destForm
;
882 Converter
conv(charSetDest
, charSetSource
, transliterations
);
884 size_t outLeft
= len
*3+1;
885 destForm
= std::string(outLeft
, '\0');
886 // g_iconv does not actually write to its input argument so safe to cast away const
887 char *pin
= const_cast<char *>(s
);
889 char *putf
= &destForm
[0];
891 size_t conversions
= conv
.Convert(&pin
, &inLeft
, &pout
, &outLeft
);
892 if (conversions
== ((size_t)(-1))) {
895 fprintf(stderr
, "iconv %s->%s failed for %0x '%s'\n",
896 charSetSource
, charSetDest
, (unsigned char)(*s
), s
);
898 fprintf(stderr
, "iconv %s->%s failed for %s\n",
899 charSetSource
, charSetDest
, s
);
901 destForm
= std::string();
903 destForm
.resize(pout
- putf
);
906 fprintf(stderr
, "Can not iconv %s %s\n", charSetDest
, charSetSource
);
911 // Returns the target converted to UTF8.
912 // Return the length in bytes.
913 int ScintillaGTK::TargetAsUTF8(char *text
) {
914 int targetLength
= targetEnd
- targetStart
;
915 if (IsUnicodeMode()) {
917 pdoc
->GetCharRange(text
, targetStart
, targetLength
);
921 const char *charSetBuffer
= CharacterSetID();
922 if (*charSetBuffer
) {
923 std::string s
= RangeText(targetStart
, targetEnd
);
924 std::string tmputf
= ConvertText(&s
[0], targetLength
, "UTF-8", charSetBuffer
, false);
926 memcpy(text
, tmputf
.c_str(), tmputf
.length());
928 return tmputf
.length();
931 pdoc
->GetCharRange(text
, targetStart
, targetLength
);
938 // Translates a nul terminated UTF8 string into the document encoding.
939 // Return the length of the result in bytes.
940 int ScintillaGTK::EncodedFromUTF8(char *utf8
, char *encoded
) const {
941 int inputLength
= (lengthForEncode
>= 0) ? lengthForEncode
: strlen(utf8
);
942 if (IsUnicodeMode()) {
944 memcpy(encoded
, utf8
, inputLength
);
949 const char *charSetBuffer
= CharacterSetID();
950 if (*charSetBuffer
) {
951 std::string tmpEncoded
= ConvertText(utf8
, inputLength
, charSetBuffer
, "UTF-8", true);
953 memcpy(encoded
, tmpEncoded
.c_str(), tmpEncoded
.length());
955 return tmpEncoded
.length();
958 memcpy(encoded
, utf8
, inputLength
);
967 bool ScintillaGTK::ValidCodePage(int codePage
) const {
969 || codePage
== SC_CP_UTF8
977 sptr_t
ScintillaGTK::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
982 gtk_widget_grab_focus(PWidget(wMain
));
985 case SCI_GETDIRECTFUNCTION
:
986 return reinterpret_cast<sptr_t
>(DirectFunction
);
988 case SCI_GETDIRECTPOINTER
:
989 return reinterpret_cast<sptr_t
>(this);
992 case SCI_LOADLEXERLIBRARY
:
993 LexerManager::GetInstance()->Load(reinterpret_cast<const char*>(lParam
));
996 case SCI_TARGETASUTF8
:
997 return TargetAsUTF8(reinterpret_cast<char*>(lParam
));
999 case SCI_ENCODEDFROMUTF8
:
1000 return EncodedFromUTF8(reinterpret_cast<char*>(wParam
),
1001 reinterpret_cast<char*>(lParam
));
1003 case SCI_SETRECTANGULARSELECTIONMODIFIER
:
1004 rectangularSelectionModifier
= wParam
;
1007 case SCI_GETRECTANGULARSELECTIONMODIFIER
:
1008 return rectangularSelectionModifier
;
1011 return ScintillaBase::WndProc(iMessage
, wParam
, lParam
);
1013 } catch (std::bad_alloc
&) {
1014 errorStatus
= SC_STATUS_BADALLOC
;
1016 errorStatus
= SC_STATUS_FAILURE
;
1021 sptr_t
ScintillaGTK::DefWndProc(unsigned int, uptr_t
, sptr_t
) {
1025 void ScintillaGTK::SetTicking(bool on
) {
1026 if (timer
.ticking
!= on
) {
1028 if (timer
.ticking
) {
1029 timer
.tickerID
= reinterpret_cast<TickerID
>(g_timeout_add(timer
.tickSize
,
1030 reinterpret_cast<GSourceFunc
>(TimeOut
), this));
1032 g_source_remove(GPOINTER_TO_UINT(timer
.tickerID
));
1035 timer
.ticksToWait
= caret
.period
;
1038 bool ScintillaGTK::SetIdle(bool on
) {
1040 // Start idler, if it's not running.
1043 idler
.idlerID
= reinterpret_cast<IdlerID
>(
1044 g_idle_add_full(G_PRIORITY_DEFAULT_IDLE
,
1045 reinterpret_cast<GSourceFunc
>(IdleCallback
), this, NULL
));
1048 // Stop idler, if it's running
1050 idler
.state
= false;
1051 g_source_remove(GPOINTER_TO_UINT(idler
.idlerID
));
1057 void ScintillaGTK::SetMouseCapture(bool on
) {
1058 if (mouseDownCaptures
) {
1060 gtk_grab_add(GTK_WIDGET(PWidget(wMain
)));
1062 gtk_grab_remove(GTK_WIDGET(PWidget(wMain
)));
1068 bool ScintillaGTK::HaveMouseCapture() {
1069 return capturedMouse
;
1072 #if GTK_CHECK_VERSION(3,0,0)
1074 // Is crcTest completely in crcContainer?
1075 static bool CRectContains(const cairo_rectangle_t
&crcContainer
, const cairo_rectangle_t
&crcTest
) {
1077 (crcTest
.x
>= crcContainer
.x
) && ((crcTest
.x
+ crcTest
.width
) <= (crcContainer
.x
+ crcContainer
.width
)) &&
1078 (crcTest
.y
>= crcContainer
.y
) && ((crcTest
.y
+ crcTest
.height
) <= (crcContainer
.y
+ crcContainer
.height
));
1081 // Is crcTest completely in crcListContainer?
1082 // May incorrectly return false if complex shape
1083 static bool CRectListContains(const cairo_rectangle_list_t
*crcListContainer
, const cairo_rectangle_t
&crcTest
) {
1084 for (int r
=0; r
<crcListContainer
->num_rectangles
; r
++) {
1085 if (CRectContains(crcListContainer
->rectangles
[r
], crcTest
))
1093 bool ScintillaGTK::PaintContains(PRectangle rc
) {
1094 // This allows optimization when a rectangle is completely in the update region.
1095 // It is OK to return false when too difficult to determine as that just performs extra drawing
1096 bool contains
= true;
1097 if (paintState
== painting
) {
1098 if (!rcPaint
.Contains(rc
)) {
1100 } else if (rgnUpdate
) {
1101 #if GTK_CHECK_VERSION(3,0,0)
1102 cairo_rectangle_t grc
= {rc
.left
, rc
.top
,
1103 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
};
1104 contains
= CRectListContains(rgnUpdate
, grc
);
1106 GdkRectangle grc
= {static_cast<gint
>(rc
.left
), static_cast<gint
>(rc
.top
),
1107 static_cast<gint
>(rc
.right
- rc
.left
), static_cast<gint
>(rc
.bottom
- rc
.top
)};
1108 if (gdk_region_rect_in(rgnUpdate
, &grc
) != GDK_OVERLAP_RECTANGLE_IN
) {
1117 // Redraw all of text area. This paint will not be abandoned.
1118 void ScintillaGTK::FullPaint() {
1119 wText
.InvalidateAll();
1122 PRectangle
ScintillaGTK::GetClientRectangle() {
1123 PRectangle rc
= wMain
.GetClientPosition();
1124 if (verticalScrollBarVisible
)
1125 rc
.right
-= verticalScrollBarWidth
;
1126 if (horizontalScrollBarVisible
&& !Wrapping())
1127 rc
.bottom
-= horizontalScrollBarHeight
;
1129 rc
.right
-= rc
.left
;
1130 rc
.bottom
-= rc
.top
;
1136 void ScintillaGTK::ScrollText(int linesToMove
) {
1137 int diff
= vs
.lineHeight
* -linesToMove
;
1138 //Platform::DebugPrintf("ScintillaGTK::ScrollText %d %d %0d,%0d %0d,%0d\n", linesToMove, diff,
1139 // rc.left, rc.top, rc.right, rc.bottom);
1140 GtkWidget
*wi
= PWidget(wText
);
1143 if (IS_WIDGET_REALIZED(wi
)) {
1144 gdk_window_scroll(WindowFromWidget(wi
), 0, -diff
);
1145 gdk_window_process_updates(WindowFromWidget(wi
), FALSE
);
1149 void ScintillaGTK::SetVerticalScrollPos() {
1151 gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmentv
), topLine
);
1154 void ScintillaGTK::SetHorizontalScrollPos() {
1156 gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmenth
), xOffset
);
1159 bool ScintillaGTK::ModifyScrollBars(int nMax
, int nPage
) {
1160 bool modified
= false;
1161 int pageScroll
= LinesToScroll();
1163 #if GTK_CHECK_VERSION(3,0,0)
1164 if (gtk_adjustment_get_upper(adjustmentv
) != (nMax
+ 1) ||
1165 gtk_adjustment_get_page_size(adjustmentv
) != nPage
||
1166 gtk_adjustment_get_page_increment(adjustmentv
) != pageScroll
) {
1167 gtk_adjustment_set_upper(adjustmentv
, nMax
+ 1);
1168 gtk_adjustment_set_page_size(adjustmentv
, nPage
);
1169 gtk_adjustment_set_page_increment(adjustmentv
, pageScroll
);
1170 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv
));
1174 if (GTK_ADJUSTMENT(adjustmentv
)->upper
!= (nMax
+ 1) ||
1175 GTK_ADJUSTMENT(adjustmentv
)->page_size
!= nPage
||
1176 GTK_ADJUSTMENT(adjustmentv
)->page_increment
!= pageScroll
) {
1177 GTK_ADJUSTMENT(adjustmentv
)->upper
= nMax
+ 1;
1178 GTK_ADJUSTMENT(adjustmentv
)->page_size
= nPage
;
1179 GTK_ADJUSTMENT(adjustmentv
)->page_increment
= pageScroll
;
1180 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv
));
1185 PRectangle rcText
= GetTextRectangle();
1186 int horizEndPreferred
= scrollWidth
;
1187 if (horizEndPreferred
< 0)
1188 horizEndPreferred
= 0;
1189 unsigned int pageWidth
= rcText
.Width();
1190 unsigned int pageIncrement
= pageWidth
/ 3;
1191 unsigned int charWidth
= vs
.styles
[STYLE_DEFAULT
].aveCharWidth
;
1192 #if GTK_CHECK_VERSION(3,0,0)
1193 if (gtk_adjustment_get_upper(adjustmenth
) != horizEndPreferred
||
1194 gtk_adjustment_get_page_size(adjustmenth
) != pageWidth
||
1195 gtk_adjustment_get_page_increment(adjustmenth
) != pageIncrement
||
1196 gtk_adjustment_get_step_increment(adjustmenth
) != charWidth
) {
1197 gtk_adjustment_set_upper(adjustmenth
, horizEndPreferred
);
1198 gtk_adjustment_set_page_size(adjustmenth
, pageWidth
);
1199 gtk_adjustment_set_page_increment(adjustmenth
, pageIncrement
);
1200 gtk_adjustment_set_step_increment(adjustmenth
, charWidth
);
1201 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth
));
1205 if (GTK_ADJUSTMENT(adjustmenth
)->upper
!= horizEndPreferred
||
1206 GTK_ADJUSTMENT(adjustmenth
)->page_size
!= pageWidth
||
1207 GTK_ADJUSTMENT(adjustmenth
)->page_increment
!= pageIncrement
||
1208 GTK_ADJUSTMENT(adjustmenth
)->step_increment
!= charWidth
) {
1209 GTK_ADJUSTMENT(adjustmenth
)->upper
= horizEndPreferred
;
1210 GTK_ADJUSTMENT(adjustmenth
)->step_increment
= charWidth
;
1211 GTK_ADJUSTMENT(adjustmenth
)->page_size
= pageWidth
;
1212 GTK_ADJUSTMENT(adjustmenth
)->page_increment
= pageIncrement
;
1213 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth
));
1217 if (modified
&& (paintState
== painting
)) {
1218 repaintFullWindow
= true;
1224 void ScintillaGTK::ReconfigureScrollBars() {
1225 PRectangle rc
= wMain
.GetClientPosition();
1226 Resize(rc
.Width(), rc
.Height());
1229 void ScintillaGTK::NotifyChange() {
1230 g_signal_emit(G_OBJECT(sci
), scintilla_signals
[COMMAND_SIGNAL
], 0,
1231 Platform::LongFromTwoShorts(GetCtrlID(), SCEN_CHANGE
), PWidget(wMain
));
1234 void ScintillaGTK::NotifyFocus(bool focus
) {
1235 g_signal_emit(G_OBJECT(sci
), scintilla_signals
[COMMAND_SIGNAL
], 0,
1236 Platform::LongFromTwoShorts
1237 (GetCtrlID(), focus
? SCEN_SETFOCUS
: SCEN_KILLFOCUS
), PWidget(wMain
));
1238 Editor::NotifyFocus(focus
);
1241 void ScintillaGTK::NotifyParent(SCNotification scn
) {
1242 scn
.nmhdr
.hwndFrom
= PWidget(wMain
);
1243 scn
.nmhdr
.idFrom
= GetCtrlID();
1244 g_signal_emit(G_OBJECT(sci
), scintilla_signals
[NOTIFY_SIGNAL
], 0,
1248 void ScintillaGTK::NotifyKey(int key
, int modifiers
) {
1249 SCNotification scn
= {};
1250 scn
.nmhdr
.code
= SCN_KEY
;
1252 scn
.modifiers
= modifiers
;
1257 void ScintillaGTK::NotifyURIDropped(const char *list
) {
1258 SCNotification scn
= {};
1259 scn
.nmhdr
.code
= SCN_URIDROPPED
;
1265 const char *CharacterSetID(int characterSet
);
1267 const char *ScintillaGTK::CharacterSetID() const {
1268 return ::CharacterSetID(vs
.styles
[STYLE_DEFAULT
].characterSet
);
1271 class CaseFolderDBCS
: public CaseFolderTable
{
1272 const char *charSet
;
1274 explicit CaseFolderDBCS(const char *charSet_
) : charSet(charSet_
) {
1277 virtual size_t Fold(char *folded
, size_t sizeFolded
, const char *mixed
, size_t lenMixed
) {
1278 if ((lenMixed
== 1) && (sizeFolded
> 0)) {
1279 folded
[0] = mapping
[static_cast<unsigned char>(mixed
[0])];
1281 } else if (*charSet
) {
1282 std::string sUTF8
= ConvertText(mixed
, lenMixed
,
1283 "UTF-8", charSet
, false);
1284 if (!sUTF8
.empty()) {
1285 gchar
*mapped
= g_utf8_casefold(sUTF8
.c_str(), sUTF8
.length());
1286 size_t lenMapped
= strlen(mapped
);
1287 if (lenMapped
< sizeFolded
) {
1288 memcpy(folded
, mapped
, lenMapped
);
1297 // Something failed so return a single NUL byte
1303 CaseFolder
*ScintillaGTK::CaseFolderForEncoding() {
1304 if (pdoc
->dbcsCodePage
== SC_CP_UTF8
) {
1305 return new CaseFolderUnicode();
1307 const char *charSetBuffer
= CharacterSetID();
1308 if (charSetBuffer
) {
1309 if (pdoc
->dbcsCodePage
== 0) {
1310 CaseFolderTable
*pcf
= new CaseFolderTable();
1311 pcf
->StandardASCII();
1312 // Only for single byte encodings
1313 for (int i
=0x80; i
<0x100; i
++) {
1314 char sCharacter
[2] = "A";
1316 // Silent as some bytes have no assigned character
1317 std::string sUTF8
= ConvertText(sCharacter
, 1,
1318 "UTF-8", charSetBuffer
, false, true);
1319 if (!sUTF8
.empty()) {
1320 gchar
*mapped
= g_utf8_casefold(sUTF8
.c_str(), sUTF8
.length());
1322 std::string mappedBack
= ConvertText(mapped
, strlen(mapped
),
1323 charSetBuffer
, "UTF-8", false, true);
1324 if ((mappedBack
.length() == 1) && (mappedBack
[0] != sCharacter
[0])) {
1325 pcf
->SetTranslation(sCharacter
[0], mappedBack
[0]);
1333 return new CaseFolderDBCS(charSetBuffer
);
1343 gchar
*mapped
; // Must be freed with g_free
1344 CaseMapper(const std::string
&sUTF8
, bool toUpperCase
) {
1346 mapped
= g_utf8_strup(sUTF8
.c_str(), sUTF8
.length());
1348 mapped
= g_utf8_strdown(sUTF8
.c_str(), sUTF8
.length());
1358 std::string
ScintillaGTK::CaseMapString(const std::string
&s
, int caseMapping
) {
1359 if ((s
.size() == 0) || (caseMapping
== cmSame
))
1362 if (IsUnicodeMode()) {
1363 std::string
retMapped(s
.length() * maxExpansionCaseConversion
, 0);
1364 size_t lenMapped
= CaseConvertString(&retMapped
[0], retMapped
.length(), s
.c_str(), s
.length(),
1365 (caseMapping
== cmUpper
) ? CaseConversionUpper
: CaseConversionLower
);
1366 retMapped
.resize(lenMapped
);
1370 const char *charSetBuffer
= CharacterSetID();
1372 if (!*charSetBuffer
) {
1373 CaseMapper
mapper(s
, caseMapping
== cmUpper
);
1374 return std::string(mapper
.mapped
, strlen(mapper
.mapped
));
1376 // Change text to UTF-8
1377 std::string sUTF8
= ConvertText(s
.c_str(), s
.length(),
1378 "UTF-8", charSetBuffer
, false);
1379 CaseMapper
mapper(sUTF8
, caseMapping
== cmUpper
);
1380 return ConvertText(mapper
.mapped
, strlen(mapper
.mapped
), charSetBuffer
, "UTF-8", false);
1384 int ScintillaGTK::KeyDefault(int key
, int modifiers
) {
1385 // Pass up to container in case it is an accelerator
1386 NotifyKey(key
, modifiers
);
1390 void ScintillaGTK::CopyToClipboard(const SelectionText
&selectedText
) {
1391 SelectionText
*clipText
= new SelectionText();
1392 clipText
->Copy(selectedText
);
1393 StoreOnClipboard(clipText
);
1396 void ScintillaGTK::Copy() {
1398 SelectionText
*clipText
= new SelectionText();
1399 CopySelectionRange(clipText
);
1400 StoreOnClipboard(clipText
);
1402 if (sel
.IsRectangular()) {
1403 ::OpenClipboard(NULL
);
1404 ::SetClipboardData(cfColumnSelect
, 0);
1411 void ScintillaGTK::Paste() {
1412 atomSought
= atomUTF8
;
1413 gtk_selection_convert(GTK_WIDGET(PWidget(wMain
)),
1414 atomClipboard
, atomSought
, GDK_CURRENT_TIME
);
1417 void ScintillaGTK::CreateCallTipWindow(PRectangle rc
) {
1418 if (!ct
.wCallTip
.Created()) {
1419 ct
.wCallTip
= gtk_window_new(GTK_WINDOW_POPUP
);
1420 ct
.wDraw
= gtk_drawing_area_new();
1421 GtkWidget
*widcdrw
= PWidget(ct
.wDraw
); // // No code inside the G_OBJECT macro
1422 gtk_container_add(GTK_CONTAINER(PWidget(ct
.wCallTip
)), widcdrw
);
1423 #if GTK_CHECK_VERSION(3,0,0)
1424 g_signal_connect(G_OBJECT(widcdrw
), "draw",
1425 G_CALLBACK(ScintillaGTK::DrawCT
), &ct
);
1427 g_signal_connect(G_OBJECT(widcdrw
), "expose_event",
1428 G_CALLBACK(ScintillaGTK::ExposeCT
), &ct
);
1430 g_signal_connect(G_OBJECT(widcdrw
), "button_press_event",
1431 G_CALLBACK(ScintillaGTK::PressCT
), static_cast<void *>(this));
1432 gtk_widget_set_events(widcdrw
,
1433 GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
);
1435 gtk_widget_set_size_request(PWidget(ct
.wDraw
), rc
.Width(), rc
.Height());
1437 if (PWindow(ct
.wCallTip
)) {
1438 gdk_window_resize(PWindow(ct
.wCallTip
), rc
.Width(), rc
.Height());
1442 void ScintillaGTK::AddToPopUp(const char *label
, int cmd
, bool enabled
) {
1443 GtkWidget
*menuItem
;
1445 menuItem
= gtk_menu_item_new_with_label(label
);
1447 menuItem
= gtk_separator_menu_item_new();
1448 gtk_menu_shell_append(GTK_MENU_SHELL(popup
.GetID()), menuItem
);
1449 g_object_set_data(G_OBJECT(menuItem
), "CmdNum", reinterpret_cast<void *>(cmd
));
1450 g_signal_connect(G_OBJECT(menuItem
),"activate", G_CALLBACK(PopUpCB
), this);
1454 gtk_widget_set_sensitive(menuItem
, enabled
);
1458 bool ScintillaGTK::OwnPrimarySelection() {
1459 return ((gdk_selection_owner_get(GDK_SELECTION_PRIMARY
)
1460 == PWindow(wMain
)) &&
1461 (PWindow(wMain
) != NULL
));
1464 void ScintillaGTK::ClaimSelection() {
1465 // X Windows has a 'primary selection' as well as the clipboard.
1466 // Whenever the user selects some text, we become the primary selection
1467 if (!sel
.Empty() && IS_WIDGET_REALIZED(GTK_WIDGET(PWidget(wMain
)))) {
1468 primarySelection
= true;
1469 gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain
)),
1470 GDK_SELECTION_PRIMARY
, GDK_CURRENT_TIME
);
1472 } else if (OwnPrimarySelection()) {
1473 primarySelection
= true;
1474 if (primary
.Empty())
1475 gtk_selection_owner_set(NULL
, GDK_SELECTION_PRIMARY
, GDK_CURRENT_TIME
);
1477 primarySelection
= false;
1482 #if GTK_CHECK_VERSION(3,0,0)
1483 static const guchar
*DataOfGSD(GtkSelectionData
*sd
) { return gtk_selection_data_get_data(sd
); }
1484 static gint
LengthOfGSD(GtkSelectionData
*sd
) { return gtk_selection_data_get_length(sd
); }
1485 static GdkAtom
TypeOfGSD(GtkSelectionData
*sd
) { return gtk_selection_data_get_data_type(sd
); }
1486 static GdkAtom
SelectionOfGSD(GtkSelectionData
*sd
) { return gtk_selection_data_get_selection(sd
); }
1488 static const guchar
*DataOfGSD(GtkSelectionData
*sd
) { return sd
->data
; }
1489 static gint
LengthOfGSD(GtkSelectionData
*sd
) { return sd
->length
; }
1490 static GdkAtom
TypeOfGSD(GtkSelectionData
*sd
) { return sd
->type
; }
1491 static GdkAtom
SelectionOfGSD(GtkSelectionData
*sd
) { return sd
->selection
; }
1494 // Detect rectangular text, convert line ends to current mode, convert from or to UTF-8
1495 void ScintillaGTK::GetGtkSelectionText(GtkSelectionData
*selectionData
, SelectionText
&selText
) {
1496 const char *data
= reinterpret_cast<const char *>(DataOfGSD(selectionData
));
1497 int len
= LengthOfGSD(selectionData
);
1498 GdkAtom selectionTypeData
= TypeOfGSD(selectionData
);
1500 // Return empty string if selection is not a string
1501 if ((selectionTypeData
!= GDK_TARGET_STRING
) && (selectionTypeData
!= atomUTF8
)) {
1506 // Check for "\n\0" ending to string indicating that selection is rectangular
1509 isRectangular
= ::IsClipboardFormatAvailable(cfColumnSelect
) != 0;
1511 isRectangular
= ((len
> 2) && (data
[len
- 1] == 0 && data
[len
- 2] == '\n'));
1513 len
--; // Forget the extra '\0'
1516 std::string
dest(data
, len
);
1517 if (selectionTypeData
== GDK_TARGET_STRING
) {
1518 if (IsUnicodeMode()) {
1519 // Unknown encoding so assume in Latin1
1520 dest
= UTF8FromLatin1(dest
.c_str(), dest
.length());
1521 selText
.Copy(dest
, SC_CP_UTF8
, 0, isRectangular
, false);
1523 // Assume buffer is in same encoding as selection
1524 selText
.Copy(dest
, pdoc
->dbcsCodePage
,
1525 vs
.styles
[STYLE_DEFAULT
].characterSet
, isRectangular
, false);
1528 const char *charSetBuffer
= CharacterSetID();
1529 if (!IsUnicodeMode() && *charSetBuffer
) {
1530 // Convert to locale
1531 dest
= ConvertText(dest
.c_str(), dest
.length(), charSetBuffer
, "UTF-8", true);
1532 selText
.Copy(dest
, pdoc
->dbcsCodePage
,
1533 vs
.styles
[STYLE_DEFAULT
].characterSet
, isRectangular
, false);
1535 selText
.Copy(dest
, SC_CP_UTF8
, 0, isRectangular
, false);
1540 void ScintillaGTK::ReceivedSelection(GtkSelectionData
*selection_data
) {
1542 if ((SelectionOfGSD(selection_data
) == atomClipboard
) ||
1543 (SelectionOfGSD(selection_data
) == GDK_SELECTION_PRIMARY
)) {
1544 if ((atomSought
== atomUTF8
) && (LengthOfGSD(selection_data
) <= 0)) {
1545 atomSought
= atomString
;
1546 gtk_selection_convert(GTK_WIDGET(PWidget(wMain
)),
1547 SelectionOfGSD(selection_data
), atomSought
, GDK_CURRENT_TIME
);
1548 } else if ((LengthOfGSD(selection_data
) > 0) &&
1549 ((TypeOfGSD(selection_data
) == GDK_TARGET_STRING
) || (TypeOfGSD(selection_data
) == atomUTF8
))) {
1550 SelectionText selText
;
1551 GetGtkSelectionText(selection_data
, selText
);
1554 if (SelectionOfGSD(selection_data
) != GDK_SELECTION_PRIMARY
) {
1555 ClearSelection(multiPasteMode
== SC_MULTIPASTE_EACH
);
1558 InsertPasteShape(selText
.Data(), selText
.Length(),
1559 selText
.rectangular
? pasteRectangular
: pasteStream
);
1560 EnsureCaretVisible();
1563 // else fprintf(stderr, "Target non string %d %d\n", (int)(selection_data->type),
1564 // (int)(atomUTF8));
1567 errorStatus
= SC_STATUS_FAILURE
;
1571 void ScintillaGTK::ReceivedDrop(GtkSelectionData
*selection_data
) {
1572 dragWasDropped
= true;
1573 if (TypeOfGSD(selection_data
) == atomUriList
|| TypeOfGSD(selection_data
) == atomDROPFILES_DND
) {
1574 const char *data
= reinterpret_cast<const char *>(DataOfGSD(selection_data
));
1575 std::vector
<char> drop(data
, data
+ LengthOfGSD(selection_data
));
1576 drop
.push_back('\0');
1577 NotifyURIDropped(&drop
[0]);
1578 } else if ((TypeOfGSD(selection_data
) == GDK_TARGET_STRING
) || (TypeOfGSD(selection_data
) == atomUTF8
)) {
1579 if (TypeOfGSD(selection_data
) > 0) {
1580 SelectionText selText
;
1581 GetGtkSelectionText(selection_data
, selText
);
1582 DropAt(posDrop
, selText
.Data(), selText
.Length(), false, selText
.rectangular
);
1584 } else if (LengthOfGSD(selection_data
) > 0) {
1585 //~ fprintf(stderr, "ReceivedDrop other %p\n", static_cast<void *>(selection_data->type));
1592 void ScintillaGTK::GetSelection(GtkSelectionData
*selection_data
, guint info
, SelectionText
*text
) {
1594 // GDK on Win32 expands any \n into \r\n, so make a copy of
1595 // the clip text now with newlines converted to \n. Use { } to hide symbols
1597 SelectionText
*newline_normalized
= NULL
;
1599 std::string tmpstr
= Document::TransformLineEnds(text
->Data(), text
->Length(), SC_EOL_LF
);
1600 newline_normalized
= new SelectionText();
1601 newline_normalized
->Copy(tmpstr
, SC_CP_UTF8
, 0, text
->rectangular
, false);
1602 text
= newline_normalized
;
1606 // Convert text to utf8 if it isn't already
1607 SelectionText
*converted
= 0;
1608 if ((text
->codePage
!= SC_CP_UTF8
) && (info
== TARGET_UTF8_STRING
)) {
1609 const char *charSet
= ::CharacterSetID(text
->characterSet
);
1611 std::string tmputf
= ConvertText(text
->Data(), text
->Length(), "UTF-8", charSet
, false);
1612 converted
= new SelectionText();
1613 converted
->Copy(tmputf
, SC_CP_UTF8
, 0, text
->rectangular
, false);
1618 // Here is a somewhat evil kludge.
1619 // As I can not work out how to store data on the clipboard in multiple formats
1620 // and need some way to mark the clipping as being stream or rectangular,
1621 // the terminating \0 is included in the length for rectangular clippings.
1622 // All other tested aplications behave benignly by ignoring the \0.
1623 // The #if is here because on Windows cfColumnSelect clip entry is used
1624 // instead as standard indicator of rectangularness (so no need to kludge)
1625 const char *textData
= text
->Data();
1626 int len
= text
->Length();
1627 #if PLAT_GTK_WIN32 == 0
1628 if (text
->rectangular
)
1632 if (info
== TARGET_UTF8_STRING
) {
1633 gtk_selection_data_set_text(selection_data
, textData
, len
);
1635 gtk_selection_data_set(selection_data
,
1636 static_cast<GdkAtom
>(GDK_SELECTION_TYPE_STRING
),
1637 8, reinterpret_cast<const unsigned char *>(textData
), len
);
1642 delete newline_normalized
;
1646 void ScintillaGTK::StoreOnClipboard(SelectionText
*clipText
) {
1647 GtkClipboard
*clipBoard
=
1648 gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain
)), atomClipboard
);
1649 if (clipBoard
== NULL
) // Occurs if widget isn't in a toplevel
1652 if (gtk_clipboard_set_with_data(clipBoard
, clipboardCopyTargets
, nClipboardCopyTargets
,
1653 ClipboardGetSelection
, ClipboardClearSelection
, clipText
)) {
1654 gtk_clipboard_set_can_store(clipBoard
, clipboardCopyTargets
, nClipboardCopyTargets
);
1658 void ScintillaGTK::ClipboardGetSelection(GtkClipboard
*, GtkSelectionData
*selection_data
, guint info
, void *data
) {
1659 GetSelection(selection_data
, info
, static_cast<SelectionText
*>(data
));
1662 void ScintillaGTK::ClipboardClearSelection(GtkClipboard
*, void *data
) {
1663 SelectionText
*obj
= static_cast<SelectionText
*>(data
);
1667 void ScintillaGTK::UnclaimSelection(GdkEventSelection
*selection_event
) {
1669 //Platform::DebugPrintf("UnclaimSelection\n");
1670 if (selection_event
->selection
== GDK_SELECTION_PRIMARY
) {
1671 //Platform::DebugPrintf("UnclaimPrimarySelection\n");
1672 if (!OwnPrimarySelection()) {
1674 primarySelection
= false;
1679 errorStatus
= SC_STATUS_FAILURE
;
1683 void ScintillaGTK::Resize(int width
, int height
) {
1684 //Platform::DebugPrintf("Resize %d %d\n", width, height);
1685 //printf("Resize %d %d\n", width, height);
1687 // Not always needed, but some themes can have different sizes of scrollbars
1688 #if GTK_CHECK_VERSION(3,0,0)
1689 GtkRequisition requisition
;
1690 gtk_widget_get_preferred_size(PWidget(scrollbarv
), NULL
, &requisition
);
1691 verticalScrollBarWidth
= requisition
.width
;
1692 gtk_widget_get_preferred_size(PWidget(scrollbarh
), NULL
, &requisition
);
1693 horizontalScrollBarHeight
= requisition
.height
;
1695 verticalScrollBarWidth
= GTK_WIDGET(PWidget(scrollbarv
))->requisition
.width
;
1696 horizontalScrollBarHeight
= GTK_WIDGET(PWidget(scrollbarh
))->requisition
.height
;
1699 // These allocations should never produce negative sizes as they would wrap around to huge
1700 // unsigned numbers inside GTK+ causing warnings.
1701 bool showSBHorizontal
= horizontalScrollBarVisible
&& !Wrapping();
1703 GtkAllocation alloc
;
1704 if (showSBHorizontal
) {
1705 gtk_widget_show(GTK_WIDGET(PWidget(scrollbarh
)));
1707 alloc
.y
= height
- horizontalScrollBarHeight
;
1708 alloc
.width
= Platform::Maximum(1, width
- verticalScrollBarWidth
);
1709 alloc
.height
= horizontalScrollBarHeight
;
1710 gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarh
)), &alloc
);
1712 gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarh
)));
1713 horizontalScrollBarHeight
= 0; // in case horizontalScrollBarVisible is true.
1716 if (verticalScrollBarVisible
) {
1717 gtk_widget_show(GTK_WIDGET(PWidget(scrollbarv
)));
1718 alloc
.x
= width
- verticalScrollBarWidth
;
1720 alloc
.width
= verticalScrollBarWidth
;
1721 alloc
.height
= Platform::Maximum(1, height
- horizontalScrollBarHeight
);
1722 gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarv
)), &alloc
);
1724 gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarv
)));
1725 verticalScrollBarWidth
= 0;
1727 if (IS_WIDGET_MAPPED(PWidget(wMain
))) {
1733 alloc
.width
= Platform::Maximum(1, width
- verticalScrollBarWidth
);
1734 alloc
.height
= Platform::Maximum(1, height
- horizontalScrollBarHeight
);
1735 gtk_widget_size_allocate(GTK_WIDGET(PWidget(wText
)), &alloc
);
1738 static void SetAdjustmentValue(GtkAdjustment
*object
, int value
) {
1739 GtkAdjustment
*adjustment
= GTK_ADJUSTMENT(object
);
1740 #if GTK_CHECK_VERSION(3,0,0)
1741 int maxValue
= static_cast<int>(
1742 gtk_adjustment_get_upper(adjustment
) - gtk_adjustment_get_page_size(adjustment
));
1744 int maxValue
= static_cast<int>(
1745 adjustment
->upper
- adjustment
->page_size
);
1748 if (value
> maxValue
)
1752 gtk_adjustment_set_value(adjustment
, value
);
1755 static int modifierTranslated(int sciModifier
) {
1756 switch (sciModifier
) {
1758 return GDK_SHIFT_MASK
;
1760 return GDK_CONTROL_MASK
;
1762 return GDK_MOD1_MASK
;
1764 return GDK_MOD4_MASK
;
1770 gint
ScintillaGTK::PressThis(GdkEventButton
*event
) {
1772 //Platform::DebugPrintf("Press %x time=%d state = %x button = %x\n",this,event->time, event->state, event->button);
1773 // Do not use GTK+ double click events as Scintilla has its own double click detection
1774 if (event
->type
!= GDK_BUTTON_PRESS
)
1778 gdk_event_free(reinterpret_cast<GdkEvent
*>(evbtn
));
1781 evbtn
= reinterpret_cast<GdkEventButton
*>(gdk_event_copy(reinterpret_cast<GdkEvent
*>(event
)));
1783 pt
.x
= int(event
->x
);
1784 pt
.y
= int(event
->y
);
1785 PRectangle rcClient
= GetClientRectangle();
1786 //Platform::DebugPrintf("Press %0d,%0d in %0d,%0d %0d,%0d\n",
1787 // pt.x, pt.y, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1788 if ((pt
.x
> rcClient
.right
) || (pt
.y
> rcClient
.bottom
)) {
1789 Platform::DebugPrintf("Bad location\n");
1793 bool shift
= (event
->state
& GDK_SHIFT_MASK
) != 0;
1794 bool ctrl
= (event
->state
& GDK_CONTROL_MASK
) != 0;
1795 // On X, instead of sending literal modifiers use the user specified
1796 // modifier, defaulting to control instead of alt.
1797 // This is because most X window managers grab alt + click for moving
1798 bool alt
= (event
->state
& modifierTranslated(rectangularSelectionModifier
)) != 0;
1800 gtk_widget_grab_focus(PWidget(wMain
));
1801 if (event
->button
== 1) {
1804 // GDK reports the Command modifer key as GDK_MOD2_MASK for button events,
1805 // not GDK_META_MASK like in key events.
1806 ctrl
= (event
->state
& GDK_MOD2_MASK
) != 0;
1810 ButtonDownWithModifiers(pt
, event
->time
, ModifierFlags(shift
, ctrl
, alt
, meta
));
1811 } else if (event
->button
== 2) {
1812 // Grab the primary selection if it exists
1813 SelectionPosition pos
= SPositionFromLocation(pt
, false, false, UserVirtualSpace());
1814 if (OwnPrimarySelection() && primary
.Empty())
1815 CopySelectionRange(&primary
);
1818 SetSelection(pos
, pos
);
1819 atomSought
= atomUTF8
;
1820 gtk_selection_convert(GTK_WIDGET(PWidget(wMain
)), GDK_SELECTION_PRIMARY
,
1821 atomSought
, event
->time
);
1822 } else if (event
->button
== 3) {
1823 if (!PointInSelection(pt
))
1824 SetEmptySelection(PositionFromLocation(pt
));
1825 if (displayPopupMenu
) {
1827 // Convert to screen
1830 gdk_window_get_origin(PWindow(wMain
), &ox
, &oy
);
1831 ContextMenu(Point(pt
.x
+ ox
, pt
.y
+ oy
));
1835 } else if (event
->button
== 4) {
1836 // Wheel scrolling up (only GTK 1.x does it this way)
1838 SetAdjustmentValue(adjustmenth
, xOffset
- 6);
1840 SetAdjustmentValue(adjustmentv
, topLine
- 3);
1841 } else if (event
->button
== 5) {
1842 // Wheel scrolling down (only GTK 1.x does it this way)
1844 SetAdjustmentValue(adjustmenth
, xOffset
+ 6);
1846 SetAdjustmentValue(adjustmentv
, topLine
+ 3);
1849 errorStatus
= SC_STATUS_FAILURE
;
1854 gint
ScintillaGTK::Press(GtkWidget
*widget
, GdkEventButton
*event
) {
1855 if (event
->window
!= WindowFromWidget(widget
))
1857 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1858 return sciThis
->PressThis(event
);
1861 gint
ScintillaGTK::MouseRelease(GtkWidget
*widget
, GdkEventButton
*event
) {
1862 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1864 //Platform::DebugPrintf("Release %x %d %d\n",sciThis,event->time,event->state);
1865 if (!sciThis
->HaveMouseCapture())
1867 if (event
->button
== 1) {
1869 pt
.x
= int(event
->x
);
1870 pt
.y
= int(event
->y
);
1871 //Platform::DebugPrintf("Up %x %x %d %d %d\n",
1872 // sciThis,event->window,event->time, pt.x, pt.y);
1873 if (event
->window
!= PWindow(sciThis
->wMain
))
1874 // If mouse released on scroll bar then the position is relative to the
1875 // scrollbar, not the drawing window so just repeat the most recent point.
1876 pt
= sciThis
->ptMouseLast
;
1877 sciThis
->ButtonUp(pt
, event
->time
, (event
->state
& GDK_CONTROL_MASK
) != 0);
1880 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
1885 // win32gtk and GTK >= 2 use SCROLL_* events instead of passing the
1886 // button4/5/6/7 events to the GTK app
1887 gint
ScintillaGTK::ScrollEvent(GtkWidget
*widget
, GdkEventScroll
*event
) {
1888 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1891 if (widget
== NULL
|| event
== NULL
)
1894 // Compute amount and direction to scroll (even tho on win32 there is
1895 // intensity of scrolling info in the native message, gtk doesn't
1896 // support this so we simulate similarly adaptive scrolling)
1897 // Note that this is disabled on OS X (Darwin) where the X11 server already has
1898 // and adaptive scrolling algorithm that fights with this one
1900 #if defined(__MWERKS__) || defined(__APPLE_CPP__) || defined(__APPLE_CC__)
1901 cLineScroll
= sciThis
->linesPerScroll
;
1902 if (cLineScroll
== 0)
1904 sciThis
->wheelMouseIntensity
= cLineScroll
;
1906 int timeDelta
= 1000000;
1908 g_get_current_time(&curTime
);
1909 if (curTime
.tv_sec
== sciThis
->lastWheelMouseTime
.tv_sec
)
1910 timeDelta
= curTime
.tv_usec
- sciThis
->lastWheelMouseTime
.tv_usec
;
1911 else if (curTime
.tv_sec
== sciThis
->lastWheelMouseTime
.tv_sec
+ 1)
1912 timeDelta
= 1000000 + (curTime
.tv_usec
- sciThis
->lastWheelMouseTime
.tv_usec
);
1913 if ((event
->direction
== sciThis
->lastWheelMouseDirection
) && (timeDelta
< 250000)) {
1914 if (sciThis
->wheelMouseIntensity
< 12)
1915 sciThis
->wheelMouseIntensity
++;
1916 cLineScroll
= sciThis
->wheelMouseIntensity
;
1918 cLineScroll
= sciThis
->linesPerScroll
;
1919 if (cLineScroll
== 0)
1921 sciThis
->wheelMouseIntensity
= cLineScroll
;
1924 if (event
->direction
== GDK_SCROLL_UP
|| event
->direction
== GDK_SCROLL_LEFT
) {
1927 g_get_current_time(&sciThis
->lastWheelMouseTime
);
1928 sciThis
->lastWheelMouseDirection
= event
->direction
;
1930 // Note: Unpatched versions of win32gtk don't set the 'state' value so
1931 // only regular scrolling is supported there. Also, unpatched win32gtk
1932 // issues spurious button 2 mouse events during wheeling, which can cause
1933 // problems (a patch for both was submitted by archaeopteryx.com on 13Jun2001)
1935 // Data zoom not supported
1936 if (event
->state
& GDK_SHIFT_MASK
) {
1940 #if GTK_CHECK_VERSION(3,4,0)
1941 // Smooth scrolling not supported
1942 if (event
->direction
== GDK_SCROLL_SMOOTH
) {
1947 // Horizontal scrolling
1948 if (event
->direction
== GDK_SCROLL_LEFT
|| event
->direction
== GDK_SCROLL_RIGHT
) {
1949 sciThis
->HorizontalScrollTo(sciThis
->xOffset
+ cLineScroll
);
1951 // Text font size zoom
1952 } else if (event
->state
& GDK_CONTROL_MASK
) {
1953 if (cLineScroll
< 0) {
1954 sciThis
->KeyCommand(SCI_ZOOMIN
);
1956 sciThis
->KeyCommand(SCI_ZOOMOUT
);
1959 // Regular scrolling
1961 sciThis
->ScrollTo(sciThis
->topLine
+ cLineScroll
);
1965 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
1970 gint
ScintillaGTK::Motion(GtkWidget
*widget
, GdkEventMotion
*event
) {
1971 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1973 //Platform::DebugPrintf("Motion %x %d\n",sciThis,event->time);
1974 if (event
->window
!= WindowFromWidget(widget
))
1978 GdkModifierType state
;
1979 if (event
->is_hint
) {
1980 #if GTK_CHECK_VERSION(3,0,0)
1981 gdk_window_get_device_position(event
->window
,
1982 event
->device
, &x
, &y
, &state
);
1984 gdk_window_get_pointer(event
->window
, &x
, &y
, &state
);
1987 x
= static_cast<int>(event
->x
);
1988 y
= static_cast<int>(event
->y
);
1989 state
= static_cast<GdkModifierType
>(event
->state
);
1991 //Platform::DebugPrintf("Move %x %x %d %c %d %d\n",
1992 // sciThis,event->window,event->time,event->is_hint? 'h' :'.', x, y);
1994 int modifiers
= ((event
->state
& GDK_SHIFT_MASK
) != 0 ? SCI_SHIFT
: 0) |
1995 ((event
->state
& GDK_CONTROL_MASK
) != 0 ? SCI_CTRL
: 0) |
1996 ((event
->state
& modifierTranslated(sciThis
->rectangularSelectionModifier
)) != 0 ? SCI_ALT
: 0);
1997 sciThis
->ButtonMoveWithModifiers(pt
, modifiers
);
1999 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2004 // Map the keypad keys to their equivalent functions
2005 static int KeyTranslate(int keyIn
) {
2007 #if GTK_CHECK_VERSION(3,0,0)
2008 case GDK_KEY_ISO_Left_Tab
:
2010 case GDK_KEY_KP_Down
:
2014 case GDK_KEY_KP_Left
:
2016 case GDK_KEY_KP_Right
:
2018 case GDK_KEY_KP_Home
:
2020 case GDK_KEY_KP_End
:
2022 case GDK_KEY_KP_Page_Up
:
2024 case GDK_KEY_KP_Page_Down
:
2026 case GDK_KEY_KP_Delete
:
2028 case GDK_KEY_KP_Insert
:
2030 case GDK_KEY_KP_Enter
:
2045 case GDK_KEY_Page_Up
:
2047 case GDK_KEY_Page_Down
:
2049 case GDK_KEY_Delete
:
2051 case GDK_KEY_Insert
:
2053 case GDK_KEY_Escape
:
2055 case GDK_KEY_BackSpace
:
2059 case GDK_KEY_Return
:
2061 case GDK_KEY_KP_Add
:
2063 case GDK_KEY_KP_Subtract
:
2064 return SCK_SUBTRACT
;
2065 case GDK_KEY_KP_Divide
:
2067 case GDK_KEY_Super_L
:
2069 case GDK_KEY_Super_R
:
2076 case GDK_ISO_Left_Tab
:
2090 case GDK_KP_Page_Up
:
2092 case GDK_KP_Page_Down
:
2131 case GDK_KP_Subtract
:
2132 return SCK_SUBTRACT
;
2147 gboolean
ScintillaGTK::KeyThis(GdkEventKey
*event
) {
2149 //fprintf(stderr, "SC-key: %d %x [%s]\n",
2150 // event->keyval, event->state, (event->length > 0) ? event->string : "empty");
2151 if (gtk_im_context_filter_keypress(im_context
, event
)) {
2154 if (!event
->keyval
) {
2158 bool shift
= (event
->state
& GDK_SHIFT_MASK
) != 0;
2159 bool ctrl
= (event
->state
& GDK_CONTROL_MASK
) != 0;
2160 bool alt
= (event
->state
& GDK_MOD1_MASK
) != 0;
2161 guint key
= event
->keyval
;
2162 if ((ctrl
|| alt
) && (key
< 128))
2164 #if GTK_CHECK_VERSION(3,0,0)
2165 else if (!ctrl
&& (key
>= GDK_KEY_KP_Multiply
&& key
<= GDK_KEY_KP_9
))
2167 else if (!ctrl
&& (key
>= GDK_KP_Multiply
&& key
<= GDK_KP_9
))
2170 // Hack for keys over 256 and below command keys but makes Hungarian work.
2171 // This will have to change for Unicode
2172 else if (key
>= 0xFE00)
2173 key
= KeyTranslate(key
);
2175 bool consumed
= false;
2176 #if !(PLAT_GTK_MACOSX)
2177 bool added
= KeyDown(key
, shift
, ctrl
, alt
, &consumed
) != 0;
2180 ctrl
= (event
->state
& GDK_META_MASK
) != 0;
2181 bool added
= KeyDownWithModifiers(key
, (shift
? SCI_SHIFT
: 0) |
2182 (ctrl
? SCI_CTRL
: 0) |
2183 (alt
? SCI_ALT
: 0) |
2184 (meta
? SCI_META
: 0), &consumed
) != 0;
2188 //fprintf(stderr, "SK-key: %d %x %x\n",event->keyval, event->state, consumed);
2189 if (event
->keyval
== 0xffffff && event
->length
> 0) {
2191 const int lengthInserted
= pdoc
->InsertString(CurrentPosition(), event
->string
, strlen(event
->string
));
2192 if (lengthInserted
> 0) {
2193 MovePositionTo(CurrentPosition() + lengthInserted
);
2198 errorStatus
= SC_STATUS_FAILURE
;
2203 gboolean
ScintillaGTK::KeyPress(GtkWidget
*widget
, GdkEventKey
*event
) {
2204 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2205 return sciThis
->KeyThis(event
);
2208 gboolean
ScintillaGTK::KeyRelease(GtkWidget
*widget
, GdkEventKey
*event
) {
2209 //Platform::DebugPrintf("SC-keyrel: %d %x %3s\n",event->keyval, event->state, event->string);
2210 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2211 if (gtk_im_context_filter_keypress(sciThis
->im_context
, event
)) {
2217 #if GTK_CHECK_VERSION(3,0,0)
2219 gboolean
ScintillaGTK::DrawPreeditThis(GtkWidget
*widget
, cairo_t
*cr
) {
2223 PangoAttrList
*attrs
;
2225 gtk_im_context_get_preedit_string(im_context
, &str
, &attrs
, &cursor_pos
);
2226 PangoLayout
*layout
= gtk_widget_create_pango_layout(PWidget(wText
), str
);
2227 pango_layout_set_attributes(layout
, attrs
);
2229 cairo_move_to(cr
, 0, 0);
2230 pango_cairo_show_layout(cr
, layout
);
2233 pango_attr_list_unref(attrs
);
2234 g_object_unref(layout
);
2236 errorStatus
= SC_STATUS_FAILURE
;
2241 gboolean
ScintillaGTK::DrawPreedit(GtkWidget
*widget
, cairo_t
*cr
, ScintillaGTK
*sciThis
) {
2242 return sciThis
->DrawPreeditThis(widget
, cr
);
2247 gboolean
ScintillaGTK::ExposePreeditThis(GtkWidget
*widget
, GdkEventExpose
*ose
) {
2251 PangoAttrList
*attrs
;
2253 gtk_im_context_get_preedit_string(im_context
, &str
, &attrs
, &cursor_pos
);
2254 PangoLayout
*layout
= gtk_widget_create_pango_layout(PWidget(wText
), str
);
2255 pango_layout_set_attributes(layout
, attrs
);
2257 cairo_t
*context
= gdk_cairo_create(reinterpret_cast<GdkDrawable
*>(WindowFromWidget(widget
)));
2258 cairo_move_to(context
, 0, 0);
2259 pango_cairo_show_layout(context
, layout
);
2260 cairo_destroy(context
);
2262 pango_attr_list_unref(attrs
);
2263 g_object_unref(layout
);
2265 errorStatus
= SC_STATUS_FAILURE
;
2270 gboolean
ScintillaGTK::ExposePreedit(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
) {
2271 return sciThis
->ExposePreeditThis(widget
, ose
);
2276 void ScintillaGTK::CommitThis(char *utfVal
) {
2278 //~ fprintf(stderr, "Commit '%s'\n", utfVal);
2279 if (IsUnicodeMode()) {
2280 AddCharUTF(utfVal
, strlen(utfVal
));
2282 const char *source
= CharacterSetID();
2284 Converter
conv(source
, "UTF-8", true);
2286 char localeVal
[4] = "\0\0\0";
2288 size_t inLeft
= strlen(utfVal
);
2289 char *pout
= localeVal
;
2290 size_t outLeft
= sizeof(localeVal
);
2291 size_t conversions
= conv
.Convert(&pin
, &inLeft
, &pout
, &outLeft
);
2292 if (conversions
!= ((size_t)(-1))) {
2294 for (int i
= 0; localeVal
[i
]; i
++) {
2295 AddChar(localeVal
[i
]);
2298 fprintf(stderr
, "Conversion failed '%s'\n", utfVal
);
2304 errorStatus
= SC_STATUS_FAILURE
;
2308 void ScintillaGTK::Commit(GtkIMContext
*, char *str
, ScintillaGTK
*sciThis
) {
2309 sciThis
->CommitThis(str
);
2312 void ScintillaGTK::PreeditChangedThis() {
2315 PangoAttrList
*attrs
;
2317 gtk_im_context_get_preedit_string(im_context
, &str
, &attrs
, &cursor_pos
);
2318 if (strlen(str
) > 0) {
2319 PangoLayout
*layout
= gtk_widget_create_pango_layout(PWidget(wText
), str
);
2320 pango_layout_set_attributes(layout
, attrs
);
2323 pango_layout_get_pixel_size(layout
, &w
, &h
);
2324 g_object_unref(layout
);
2327 gdk_window_get_origin(PWindow(wText
), &x
, &y
);
2329 Point pt
= PointMainCaret();
2335 gtk_window_move(GTK_WINDOW(PWidget(wPreedit
)), x
+ pt
.x
, y
+ pt
.y
);
2336 gtk_window_resize(GTK_WINDOW(PWidget(wPreedit
)), w
, h
);
2337 gtk_widget_show(PWidget(wPreedit
));
2338 gtk_widget_queue_draw_area(PWidget(wPreeditDraw
), 0, 0, w
, h
);
2340 gtk_widget_hide(PWidget(wPreedit
));
2343 pango_attr_list_unref(attrs
);
2345 errorStatus
= SC_STATUS_FAILURE
;
2349 void ScintillaGTK::PreeditChanged(GtkIMContext
*, ScintillaGTK
*sciThis
) {
2350 sciThis
->PreeditChangedThis();
2353 void ScintillaGTK::StyleSetText(GtkWidget
*widget
, GtkStyle
*, void*) {
2354 RealizeText(widget
, NULL
);
2357 void ScintillaGTK::RealizeText(GtkWidget
*widget
, void*) {
2358 // Set NULL background to avoid automatic clearing so Scintilla responsible for all drawing
2359 if (WindowFromWidget(widget
)) {
2360 #if GTK_CHECK_VERSION(3,0,0)
2361 gdk_window_set_background_pattern(WindowFromWidget(widget
), NULL
);
2363 gdk_window_set_back_pixmap(WindowFromWidget(widget
), NULL
, FALSE
);
2368 static GObjectClass
*scintilla_class_parent_class
;
2370 void ScintillaGTK::Destroy(GObject
*object
) {
2372 ScintillaObject
*scio
= reinterpret_cast<ScintillaObject
*>(object
);
2374 // This avoids a double destruction
2377 ScintillaGTK
*sciThis
= reinterpret_cast<ScintillaGTK
*>(scio
->pscin
);
2378 //Platform::DebugPrintf("Destroying %x %x\n", sciThis, object);
2379 sciThis
->Finalise();
2383 scintilla_class_parent_class
->finalize(object
);
2385 // Its dead so nowhere to save the status
2389 #if GTK_CHECK_VERSION(3,0,0)
2391 gboolean
ScintillaGTK::DrawTextThis(cairo_t
*cr
) {
2393 paintState
= painting
;
2394 repaintFullWindow
= false;
2396 rcPaint
= GetClientRectangle();
2398 PLATFORM_ASSERT(rgnUpdate
== NULL
);
2399 rgnUpdate
= cairo_copy_clip_rectangle_list(cr
);
2400 if (rgnUpdate
&& rgnUpdate
->status
!= CAIRO_STATUS_SUCCESS
) {
2401 // If not successful then ignore
2402 fprintf(stderr
, "DrawTextThis failed to copy update region %d [%d]\n", rgnUpdate
->status
, rgnUpdate
->num_rectangles
);
2403 cairo_rectangle_list_destroy(rgnUpdate
);
2407 double x1
, y1
, x2
, y2
;
2408 cairo_clip_extents(cr
, &x1
, &y1
, &x2
, &y2
);
2412 rcPaint
.bottom
= y2
;
2413 PRectangle rcClient
= GetClientRectangle();
2414 paintingAllText
= rcPaint
.Contains(rcClient
);
2415 Surface
*surfaceWindow
= Surface::Allocate(SC_TECHNOLOGY_DEFAULT
);
2416 if (surfaceWindow
) {
2417 surfaceWindow
->Init(cr
, PWidget(wText
));
2418 Paint(surfaceWindow
, rcPaint
);
2419 surfaceWindow
->Release();
2420 delete surfaceWindow
;
2422 if ((paintState
== paintAbandoned
) || repaintFullWindow
) {
2423 // Painting area was insufficient to cover new styling or brace highlight positions
2426 paintState
= notPainting
;
2427 repaintFullWindow
= false;
2430 cairo_rectangle_list_destroy(rgnUpdate
);
2433 paintState
= notPainting
;
2435 errorStatus
= SC_STATUS_FAILURE
;
2441 gboolean
ScintillaGTK::DrawText(GtkWidget
*, cairo_t
*cr
, ScintillaGTK
*sciThis
) {
2442 return sciThis
->DrawTextThis(cr
);
2445 gboolean
ScintillaGTK::DrawThis(cairo_t
*cr
) {
2447 gtk_container_propagate_draw(
2448 GTK_CONTAINER(PWidget(wMain
)), PWidget(scrollbarh
), cr
);
2449 gtk_container_propagate_draw(
2450 GTK_CONTAINER(PWidget(wMain
)), PWidget(scrollbarv
), cr
);
2451 // Starting from the following version, the expose event are not propagated
2452 // for double buffered non native windows, so we need to call it ourselves
2453 // or keep the default handler
2454 #if GTK_CHECK_VERSION(3,0,0)
2455 // we want to forward on any >= 3.9.2 runtime
2456 if (gtk_check_version(3,9,2) == NULL
) {
2457 gtk_container_propagate_draw(
2458 GTK_CONTAINER(PWidget(wMain
)), PWidget(wText
), cr
);
2462 errorStatus
= SC_STATUS_FAILURE
;
2467 gboolean
ScintillaGTK::DrawMain(GtkWidget
*widget
, cairo_t
*cr
) {
2468 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2469 return sciThis
->DrawThis(cr
);
2474 gboolean
ScintillaGTK::ExposeTextThis(GtkWidget
* /*widget*/, GdkEventExpose
*ose
) {
2476 paintState
= painting
;
2478 rcPaint
.left
= ose
->area
.x
;
2479 rcPaint
.top
= ose
->area
.y
;
2480 rcPaint
.right
= ose
->area
.x
+ ose
->area
.width
;
2481 rcPaint
.bottom
= ose
->area
.y
+ ose
->area
.height
;
2483 PLATFORM_ASSERT(rgnUpdate
== NULL
);
2484 rgnUpdate
= gdk_region_copy(ose
->region
);
2485 PRectangle rcClient
= GetClientRectangle();
2486 paintingAllText
= rcPaint
.Contains(rcClient
);
2487 Surface
*surfaceWindow
= Surface::Allocate(SC_TECHNOLOGY_DEFAULT
);
2488 if (surfaceWindow
) {
2489 cairo_t
*cr
= gdk_cairo_create(PWindow(wText
));
2490 surfaceWindow
->Init(cr
, PWidget(wText
));
2491 Paint(surfaceWindow
, rcPaint
);
2492 surfaceWindow
->Release();
2493 delete surfaceWindow
;
2496 if (paintState
== paintAbandoned
) {
2497 // Painting area was insufficient to cover new styling or brace highlight positions
2500 paintState
= notPainting
;
2503 gdk_region_destroy(rgnUpdate
);
2507 errorStatus
= SC_STATUS_FAILURE
;
2513 gboolean
ScintillaGTK::ExposeText(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
) {
2514 return sciThis
->ExposeTextThis(widget
, ose
);
2517 gboolean
ScintillaGTK::ExposeMain(GtkWidget
*widget
, GdkEventExpose
*ose
) {
2518 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2519 //Platform::DebugPrintf("Expose Main %0d,%0d %0d,%0d\n",
2520 //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2521 return sciThis
->Expose(widget
, ose
);
2524 gboolean
ScintillaGTK::Expose(GtkWidget
*, GdkEventExpose
*ose
) {
2526 //fprintf(stderr, "Expose %0d,%0d %0d,%0d\n",
2527 //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2529 // The text is painted in ExposeText
2530 gtk_container_propagate_expose(
2531 GTK_CONTAINER(PWidget(wMain
)), PWidget(scrollbarh
), ose
);
2532 gtk_container_propagate_expose(
2533 GTK_CONTAINER(PWidget(wMain
)), PWidget(scrollbarv
), ose
);
2536 errorStatus
= SC_STATUS_FAILURE
;
2543 void ScintillaGTK::ScrollSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
) {
2545 #if GTK_CHECK_VERSION(3,0,0)
2546 sciThis
->ScrollTo(static_cast<int>(gtk_adjustment_get_value(adj
)), false);
2548 sciThis
->ScrollTo(static_cast<int>(adj
->value
), false);
2551 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2555 void ScintillaGTK::ScrollHSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
) {
2557 #if GTK_CHECK_VERSION(3,0,0)
2558 sciThis
->HorizontalScrollTo(static_cast<int>(gtk_adjustment_get_value(adj
)));
2560 sciThis
->HorizontalScrollTo(static_cast<int>(adj
->value
));
2563 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2567 void ScintillaGTK::SelectionReceived(GtkWidget
*widget
,
2568 GtkSelectionData
*selection_data
, guint
) {
2569 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2570 //Platform::DebugPrintf("Selection received\n");
2571 sciThis
->ReceivedSelection(selection_data
);
2574 void ScintillaGTK::SelectionGet(GtkWidget
*widget
,
2575 GtkSelectionData
*selection_data
, guint info
, guint
) {
2576 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2578 //Platform::DebugPrintf("Selection get\n");
2579 if (SelectionOfGSD(selection_data
) == GDK_SELECTION_PRIMARY
) {
2580 if (sciThis
->primary
.Empty()) {
2581 sciThis
->CopySelectionRange(&sciThis
->primary
);
2583 sciThis
->GetSelection(selection_data
, info
, &sciThis
->primary
);
2586 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2590 gint
ScintillaGTK::SelectionClear(GtkWidget
*widget
, GdkEventSelection
*selection_event
) {
2591 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2592 //Platform::DebugPrintf("Selection clear\n");
2593 sciThis
->UnclaimSelection(selection_event
);
2594 if (GTK_WIDGET_CLASS(sciThis
->parentClass
)->selection_clear_event
) {
2595 return GTK_WIDGET_CLASS(sciThis
->parentClass
)->selection_clear_event(widget
, selection_event
);
2600 gboolean
ScintillaGTK::DragMotionThis(GdkDragContext
*context
,
2601 gint x
, gint y
, guint dragtime
) {
2604 SetDragPosition(SPositionFromLocation(npt
, false, false, UserVirtualSpace()));
2605 #if GTK_CHECK_VERSION(3,0,0)
2606 GdkDragAction preferredAction
= gdk_drag_context_get_suggested_action(context
);
2607 GdkDragAction actions
= gdk_drag_context_get_actions(context
);
2609 GdkDragAction preferredAction
= context
->suggested_action
;
2610 GdkDragAction actions
= context
->actions
;
2612 SelectionPosition pos
= SPositionFromLocation(npt
);
2613 if ((inDragDrop
== ddDragging
) && (PositionInSelection(pos
.Position()))) {
2614 // Avoid dragging selection onto itself as that produces a move
2615 // with no real effect but which creates undo actions.
2616 preferredAction
= static_cast<GdkDragAction
>(0);
2617 } else if (actions
== static_cast<GdkDragAction
>
2618 (GDK_ACTION_COPY
| GDK_ACTION_MOVE
)) {
2619 preferredAction
= GDK_ACTION_MOVE
;
2621 gdk_drag_status(context
, preferredAction
, dragtime
);
2623 errorStatus
= SC_STATUS_FAILURE
;
2628 gboolean
ScintillaGTK::DragMotion(GtkWidget
*widget
, GdkDragContext
*context
,
2629 gint x
, gint y
, guint dragtime
) {
2630 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2631 return sciThis
->DragMotionThis(context
, x
, y
, dragtime
);
2634 void ScintillaGTK::DragLeave(GtkWidget
*widget
, GdkDragContext
* /*context*/, guint
) {
2635 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2637 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2638 //Platform::DebugPrintf("DragLeave %x\n", sciThis);
2640 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2644 void ScintillaGTK::DragEnd(GtkWidget
*widget
, GdkDragContext
* /*context*/) {
2645 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2647 // If drag did not result in drop here or elsewhere
2648 if (!sciThis
->dragWasDropped
)
2649 sciThis
->SetEmptySelection(sciThis
->posDrag
);
2650 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2651 //Platform::DebugPrintf("DragEnd %x %d\n", sciThis, sciThis->dragWasDropped);
2652 sciThis
->inDragDrop
= ddNone
;
2654 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2658 gboolean
ScintillaGTK::Drop(GtkWidget
*widget
, GdkDragContext
* /*context*/,
2659 gint
, gint
, guint
) {
2660 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2662 //Platform::DebugPrintf("Drop %x\n", sciThis);
2663 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2665 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2670 void ScintillaGTK::DragDataReceived(GtkWidget
*widget
, GdkDragContext
* /*context*/,
2671 gint
, gint
, GtkSelectionData
*selection_data
, guint
/*info*/, guint
) {
2672 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2674 sciThis
->ReceivedDrop(selection_data
);
2675 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2677 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2681 void ScintillaGTK::DragDataGet(GtkWidget
*widget
, GdkDragContext
*context
,
2682 GtkSelectionData
*selection_data
, guint info
, guint
) {
2683 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2685 sciThis
->dragWasDropped
= true;
2686 if (!sciThis
->sel
.Empty()) {
2687 sciThis
->GetSelection(selection_data
, info
, &sciThis
->drag
);
2689 #if GTK_CHECK_VERSION(3,0,0)
2690 GdkDragAction action
= gdk_drag_context_get_selected_action(context
);
2692 GdkDragAction action
= context
->action
;
2694 if (action
== GDK_ACTION_MOVE
) {
2695 for (size_t r
=0; r
<sciThis
->sel
.Count(); r
++) {
2696 if (sciThis
->posDrop
>= sciThis
->sel
.Range(r
).Start()) {
2697 if (sciThis
->posDrop
> sciThis
->sel
.Range(r
).End()) {
2698 sciThis
->posDrop
.Add(-sciThis
->sel
.Range(r
).Length());
2700 sciThis
->posDrop
.Add(-SelectionRange(sciThis
->posDrop
, sciThis
->sel
.Range(r
).Start()).Length());
2704 sciThis
->ClearSelection();
2706 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2708 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2712 int ScintillaGTK::TimeOut(ScintillaGTK
*sciThis
) {
2717 gboolean
ScintillaGTK::IdleCallback(ScintillaGTK
*sciThis
) {
2718 // Idler will be automatically stopped, if there is nothing
2719 // to do while idle.
2720 #ifndef GDK_VERSION_3_6
2721 gdk_threads_enter();
2723 bool ret
= sciThis
->Idle();
2725 // FIXME: This will remove the idler from GTK, we don't want to
2726 // remove it as it is removed automatically when this function
2727 // returns false (although, it should be harmless).
2728 sciThis
->SetIdle(false);
2730 #ifndef GDK_VERSION_3_6
2731 gdk_threads_leave();
2736 gboolean
ScintillaGTK::StyleIdle(ScintillaGTK
*sciThis
) {
2737 #ifndef GDK_VERSION_3_6
2738 gdk_threads_enter();
2740 sciThis
->IdleWork();
2741 #ifndef GDK_VERSION_3_6
2742 gdk_threads_leave();
2744 // Idler will be automatically stopped
2748 void ScintillaGTK::QueueIdleWork(WorkNeeded::workItems items
, int upTo
) {
2749 Editor::QueueIdleWork(items
, upTo
);
2750 if (!workNeeded
.active
) {
2751 // Only allow one style needed to be queued
2752 workNeeded
.active
= true;
2753 g_idle_add_full(G_PRIORITY_HIGH_IDLE
,
2754 reinterpret_cast<GSourceFunc
>(StyleIdle
), this, NULL
);
2758 void ScintillaGTK::PopUpCB(GtkMenuItem
*menuItem
, ScintillaGTK
*sciThis
) {
2759 guint action
= (sptr_t
)(g_object_get_data(G_OBJECT(menuItem
), "CmdNum"));
2761 sciThis
->Command(action
);
2765 gboolean
ScintillaGTK::PressCT(GtkWidget
*widget
, GdkEventButton
*event
, ScintillaGTK
*sciThis
) {
2767 if (event
->window
!= WindowFromWidget(widget
))
2769 if (event
->type
!= GDK_BUTTON_PRESS
)
2772 pt
.x
= int(event
->x
);
2773 pt
.y
= int(event
->y
);
2774 sciThis
->ct
.MouseClick(pt
);
2775 sciThis
->CallTipClick();
2781 #if GTK_CHECK_VERSION(3,0,0)
2783 gboolean
ScintillaGTK::DrawCT(GtkWidget
*widget
, cairo_t
*cr
, CallTip
*ctip
) {
2785 Surface
*surfaceWindow
= Surface::Allocate(SC_TECHNOLOGY_DEFAULT
);
2786 if (surfaceWindow
) {
2787 surfaceWindow
->Init(cr
, widget
);
2788 surfaceWindow
->SetUnicodeMode(SC_CP_UTF8
== ctip
->codePage
);
2789 surfaceWindow
->SetDBCSMode(ctip
->codePage
);
2790 ctip
->PaintCT(surfaceWindow
);
2791 surfaceWindow
->Release();
2792 delete surfaceWindow
;
2795 // No pointer back to Scintilla to save status
2802 gboolean
ScintillaGTK::ExposeCT(GtkWidget
*widget
, GdkEventExpose
* /*ose*/, CallTip
*ctip
) {
2804 Surface
*surfaceWindow
= Surface::Allocate(SC_TECHNOLOGY_DEFAULT
);
2805 if (surfaceWindow
) {
2806 cairo_t
*cr
= gdk_cairo_create(WindowFromWidget(widget
));
2807 surfaceWindow
->Init(cr
, widget
);
2808 surfaceWindow
->SetUnicodeMode(SC_CP_UTF8
== ctip
->codePage
);
2809 surfaceWindow
->SetDBCSMode(ctip
->codePage
);
2810 ctip
->PaintCT(surfaceWindow
);
2811 surfaceWindow
->Release();
2812 delete surfaceWindow
;
2816 // No pointer back to Scintilla to save status
2823 sptr_t
ScintillaGTK::DirectFunction(
2824 sptr_t ptr
, unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
2825 return reinterpret_cast<ScintillaGTK
*>(ptr
)->WndProc(iMessage
, wParam
, lParam
);
2828 sptr_t
scintilla_send_message(ScintillaObject
*sci
, unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
2829 ScintillaGTK
*psci
= reinterpret_cast<ScintillaGTK
*>(sci
->pscin
);
2830 return psci
->WndProc(iMessage
, wParam
, lParam
);
2833 static void scintilla_class_init(ScintillaClass
*klass
);
2834 static void scintilla_init(ScintillaObject
*sci
);
2836 extern void Platform_Initialise();
2837 extern void Platform_Finalise();
2839 GType
scintilla_get_type() {
2840 static GType scintilla_type
= 0;
2843 if (!scintilla_type
) {
2844 scintilla_type
= g_type_from_name("Scintilla");
2845 if (!scintilla_type
) {
2846 static GTypeInfo scintilla_info
= {
2847 (guint16
) sizeof (ScintillaClass
),
2848 NULL
, //(GBaseInitFunc)
2849 NULL
, //(GBaseFinalizeFunc)
2850 (GClassInitFunc
) scintilla_class_init
,
2851 NULL
, //(GClassFinalizeFunc)
2852 NULL
, //gconstpointer data
2853 (guint16
) sizeof (ScintillaObject
),
2855 (GInstanceInitFunc
) scintilla_init
,
2856 NULL
//(GTypeValueTable*)
2859 scintilla_type
= g_type_register_static(
2860 GTK_TYPE_CONTAINER
, "Scintilla", &scintilla_info
, (GTypeFlags
) 0);
2866 return scintilla_type
;
2869 void ScintillaGTK::ClassInit(OBJECT_CLASS
* object_class
, GtkWidgetClass
*widget_class
, GtkContainerClass
*container_class
) {
2870 Platform_Initialise();
2872 Scintilla_LinkLexers();
2874 atomClipboard
= gdk_atom_intern("CLIPBOARD", FALSE
);
2875 atomUTF8
= gdk_atom_intern("UTF8_STRING", FALSE
);
2876 atomString
= GDK_SELECTION_TYPE_STRING
;
2877 atomUriList
= gdk_atom_intern("text/uri-list", FALSE
);
2878 atomDROPFILES_DND
= gdk_atom_intern("DROPFILES_DND", FALSE
);
2880 // Define default signal handlers for the class: Could move more
2881 // of the signal handlers here (those that currently attached to wDraw
2882 // in Initialise() may require coordinate translation?)
2884 object_class
->finalize
= Destroy
;
2885 #if GTK_CHECK_VERSION(3,0,0)
2886 widget_class
->get_preferred_width
= GetPreferredWidth
;
2887 widget_class
->get_preferred_height
= GetPreferredHeight
;
2889 widget_class
->size_request
= SizeRequest
;
2891 widget_class
->size_allocate
= SizeAllocate
;
2892 #if GTK_CHECK_VERSION(3,0,0)
2893 widget_class
->draw
= DrawMain
;
2895 widget_class
->expose_event
= ExposeMain
;
2897 widget_class
->motion_notify_event
= Motion
;
2898 widget_class
->button_press_event
= Press
;
2899 widget_class
->button_release_event
= MouseRelease
;
2900 widget_class
->scroll_event
= ScrollEvent
;
2901 widget_class
->key_press_event
= KeyPress
;
2902 widget_class
->key_release_event
= KeyRelease
;
2903 widget_class
->focus_in_event
= FocusIn
;
2904 widget_class
->focus_out_event
= FocusOut
;
2905 widget_class
->selection_received
= SelectionReceived
;
2906 widget_class
->selection_get
= SelectionGet
;
2907 widget_class
->selection_clear_event
= SelectionClear
;
2909 widget_class
->drag_data_received
= DragDataReceived
;
2910 widget_class
->drag_motion
= DragMotion
;
2911 widget_class
->drag_leave
= DragLeave
;
2912 widget_class
->drag_end
= DragEnd
;
2913 widget_class
->drag_drop
= Drop
;
2914 widget_class
->drag_data_get
= DragDataGet
;
2916 widget_class
->realize
= Realize
;
2917 widget_class
->unrealize
= UnRealize
;
2918 widget_class
->map
= Map
;
2919 widget_class
->unmap
= UnMap
;
2921 container_class
->forall
= MainForAll
;
2924 #define SIG_MARSHAL scintilla_marshal_NONE__INT_POINTER
2925 #define MARSHAL_ARGUMENTS G_TYPE_INT, G_TYPE_POINTER
2927 static void scintilla_class_init(ScintillaClass
*klass
) {
2929 OBJECT_CLASS
*object_class
= (OBJECT_CLASS
*) klass
;
2930 GtkWidgetClass
*widget_class
= (GtkWidgetClass
*) klass
;
2931 GtkContainerClass
*container_class
= (GtkContainerClass
*) klass
;
2933 GSignalFlags sigflags
= GSignalFlags(G_SIGNAL_ACTION
| G_SIGNAL_RUN_LAST
);
2934 scintilla_signals
[COMMAND_SIGNAL
] = g_signal_new(
2936 G_TYPE_FROM_CLASS(object_class
),
2938 G_STRUCT_OFFSET(ScintillaClass
, command
),
2939 NULL
, //(GSignalAccumulator)
2943 2, MARSHAL_ARGUMENTS
);
2945 scintilla_signals
[NOTIFY_SIGNAL
] = g_signal_new(
2947 G_TYPE_FROM_CLASS(object_class
),
2949 G_STRUCT_OFFSET(ScintillaClass
, notify
),
2954 2, MARSHAL_ARGUMENTS
);
2956 klass
->command
= NULL
;
2957 klass
->notify
= NULL
;
2958 scintilla_class_parent_class
= G_OBJECT_CLASS(g_type_class_peek_parent(klass
));
2959 ScintillaGTK::ClassInit(object_class
, widget_class
, container_class
);
2964 static void scintilla_init(ScintillaObject
*sci
) {
2966 #if GTK_CHECK_VERSION(2,20,0)
2967 gtk_widget_set_can_focus(GTK_WIDGET(sci
), TRUE
);
2969 GTK_WIDGET_SET_FLAGS(sci
, GTK_CAN_FOCUS
);
2971 sci
->pscin
= new ScintillaGTK(sci
);
2976 GtkWidget
* scintilla_new() {
2977 GtkWidget
*widget
= GTK_WIDGET(g_object_new(scintilla_get_type(), NULL
));
2978 gtk_widget_set_direction(widget
, GTK_TEXT_DIR_LTR
);
2983 void scintilla_set_id(ScintillaObject
*sci
, uptr_t id
) {
2984 ScintillaGTK
*psci
= reinterpret_cast<ScintillaGTK
*>(sci
->pscin
);
2988 void scintilla_release_resources(void) {
2990 Platform_Finalise();