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.
23 #include <gdk/gdkkeysyms.h>
25 #if defined(__WIN32__) || defined(_MSC_VER)
32 #include "Scintilla.h"
33 #include "ScintillaWidget.h"
37 #include "StringCopy.h"
39 #include "LexerModule.h"
41 #include "SplitVector.h"
42 #include "Partitioning.h"
43 #include "RunStyles.h"
44 #include "ContractionState.h"
45 #include "CellBuffer.h"
48 #include "Indicator.h"
50 #include "LineMarker.h"
52 #include "ViewStyle.h"
53 #include "CharClassify.h"
54 #include "Decoration.h"
55 #include "CaseFolder.h"
57 #include "CaseConvert.h"
58 #include "UniConversion.h"
59 #include "UnicodeFromUTF8.h"
60 #include "Selection.h"
61 #include "PositionCache.h"
62 #include "EditModel.h"
63 #include "MarginView.h"
66 #include "AutoComplete.h"
67 #include "ScintillaBase.h"
70 #include "ExternalLexer.h"
73 #include "scintilla-marshal.h"
75 #include "Converter.h"
77 #if defined(__clang__)
78 // Clang 3.0 incorrectly displays sentinel warnings. Fixed by clang 3.1.
79 #pragma GCC diagnostic ignored "-Wsentinel"
82 #if GTK_CHECK_VERSION(2,20,0)
83 #define IS_WIDGET_REALIZED(w) (gtk_widget_get_realized(GTK_WIDGET(w)))
84 #define IS_WIDGET_MAPPED(w) (gtk_widget_get_mapped(GTK_WIDGET(w)))
85 #define IS_WIDGET_VISIBLE(w) (gtk_widget_get_visible(GTK_WIDGET(w)))
87 #define IS_WIDGET_REALIZED(w) (GTK_WIDGET_REALIZED(w))
88 #define IS_WIDGET_MAPPED(w) (GTK_WIDGET_MAPPED(w))
89 #define IS_WIDGET_VISIBLE(w) (GTK_WIDGET_VISIBLE(w))
92 #define SC_INDICATOR_INPUT INDIC_IME
93 #define SC_INDICATOR_TARGET INDIC_IME+1
94 #define SC_INDICATOR_CONVERTED INDIC_IME+2
95 #define SC_INDICATOR_UNKNOWN INDIC_IME_MAX
97 static GdkWindow
*WindowFromWidget(GtkWidget
*w
) {
98 #if GTK_CHECK_VERSION(3,0,0)
99 return gtk_widget_get_window(w
);
106 // Constant conditional expressions are because of GTK+ headers
107 #pragma warning(disable: 4127)
108 // Ignore unreferenced local functions in GTK+ headers
109 #pragma warning(disable: 4505)
112 #define OBJECT_CLASS GObjectClass
115 using namespace Scintilla
;
118 static GdkWindow
*PWindow(const Window
&w
) {
119 GtkWidget
*widget
= reinterpret_cast<GtkWidget
*>(w
.GetID());
120 #if GTK_CHECK_VERSION(3,0,0)
121 return gtk_widget_get_window(widget
);
123 return widget
->window
;
127 extern std::string
UTF8FromLatin1(const char *s
, int len
);
129 class ScintillaGTK
: public ScintillaBase
{
130 _ScintillaObject
*sci
;
134 GtkAdjustment
*adjustmentv
;
135 GtkAdjustment
*adjustmenth
;
136 int verticalScrollBarWidth
;
137 int horizontalScrollBarHeight
;
139 SelectionText primary
;
141 GdkEventButton
*evbtn
;
145 int rectangularSelectionModifier
;
147 GtkWidgetClass
*parentClass
;
149 static GdkAtom atomClipboard
;
150 static GdkAtom atomUTF8
;
151 static GdkAtom atomString
;
152 static GdkAtom atomUriList
;
153 static GdkAtom atomDROPFILES_DND
;
157 CLIPFORMAT cfColumnSelect
;
162 GtkIMContext
*im_context
;
163 PangoScript lastNonCommonScript
;
165 // Wheel mouse support
166 unsigned int linesPerScroll
;
167 GTimeVal lastWheelMouseTime
;
168 gint lastWheelMouseDirection
;
169 gint wheelMouseIntensity
;
171 #if GTK_CHECK_VERSION(3,0,0)
172 cairo_rectangle_list_t
*rgnUpdate
;
174 GdkRegion
*rgnUpdate
;
176 bool repaintFullWindow
;
178 // Private so ScintillaGTK objects can not be copied
179 ScintillaGTK(const ScintillaGTK
&);
180 ScintillaGTK
&operator=(const ScintillaGTK
&);
183 explicit ScintillaGTK(_ScintillaObject
*sci_
);
184 virtual ~ScintillaGTK();
185 static void ClassInit(OBJECT_CLASS
* object_class
, GtkWidgetClass
*widget_class
, GtkContainerClass
*container_class
);
187 virtual void Initialise();
188 virtual void Finalise();
189 virtual bool AbandonPaint();
190 virtual void DisplayCursor(Window::Cursor c
);
191 virtual bool DragThreshold(Point ptStart
, Point ptNow
);
192 virtual void StartDrag();
193 int TargetAsUTF8(char *text
);
194 int EncodedFromUTF8(char *utf8
, char *encoded
) const;
195 virtual bool ValidCodePage(int codePage
) const;
196 public: // Public for scintilla_send_message
197 virtual sptr_t
WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
199 virtual sptr_t
DefWndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
202 ScintillaGTK
*scintilla
;
204 TimeThunk() : reason(tickCaret
), scintilla(NULL
), timer(0) {}
206 TimeThunk timers
[tickDwell
+1];
207 virtual bool FineTickerAvailable();
208 virtual bool FineTickerRunning(TickReason reason
);
209 virtual void FineTickerStart(TickReason reason
, int millis
, int tolerance
);
210 virtual void FineTickerCancel(TickReason reason
);
211 virtual bool SetIdle(bool on
);
212 virtual void SetMouseCapture(bool on
);
213 virtual bool HaveMouseCapture();
214 virtual bool PaintContains(PRectangle rc
);
216 virtual PRectangle
GetClientRectangle() const;
217 virtual void ScrollText(int linesToMove
);
218 virtual void SetVerticalScrollPos();
219 virtual void SetHorizontalScrollPos();
220 virtual bool ModifyScrollBars(int nMax
, int nPage
);
221 void ReconfigureScrollBars();
222 virtual void NotifyChange();
223 virtual void NotifyFocus(bool focus
);
224 virtual void NotifyParent(SCNotification scn
);
225 void NotifyKey(int key
, int modifiers
);
226 void NotifyURIDropped(const char *list
);
227 const char *CharacterSetID() const;
228 virtual CaseFolder
*CaseFolderForEncoding();
229 virtual std::string
CaseMapString(const std::string
&s
, int caseMapping
);
230 virtual int KeyDefault(int key
, int modifiers
);
231 virtual void CopyToClipboard(const SelectionText
&selectedText
);
233 virtual void Paste();
234 virtual void CreateCallTipWindow(PRectangle rc
);
235 virtual void AddToPopUp(const char *label
, int cmd
= 0, bool enabled
= true);
236 bool OwnPrimarySelection();
237 virtual void ClaimSelection();
238 void GetGtkSelectionText(GtkSelectionData
*selectionData
, SelectionText
&selText
);
239 void ReceivedSelection(GtkSelectionData
*selection_data
);
240 void ReceivedDrop(GtkSelectionData
*selection_data
);
241 static void GetSelection(GtkSelectionData
*selection_data
, guint info
, SelectionText
*selected
);
242 void StoreOnClipboard(SelectionText
*clipText
);
243 static void ClipboardGetSelection(GtkClipboard
* clip
, GtkSelectionData
*selection_data
, guint info
, void *data
);
244 static void ClipboardClearSelection(GtkClipboard
* clip
, void *data
);
246 void UnclaimSelection(GdkEventSelection
*selection_event
);
247 void Resize(int width
, int height
);
249 // Callback functions
250 void RealizeThis(GtkWidget
*widget
);
251 static void Realize(GtkWidget
*widget
);
252 void UnRealizeThis(GtkWidget
*widget
);
253 static void UnRealize(GtkWidget
*widget
);
255 static void Map(GtkWidget
*widget
);
257 static void UnMap(GtkWidget
*widget
);
258 gint
FocusInThis(GtkWidget
*widget
);
259 static gint
FocusIn(GtkWidget
*widget
, GdkEventFocus
*event
);
260 gint
FocusOutThis(GtkWidget
*widget
);
261 static gint
FocusOut(GtkWidget
*widget
, GdkEventFocus
*event
);
262 static void SizeRequest(GtkWidget
*widget
, GtkRequisition
*requisition
);
263 #if GTK_CHECK_VERSION(3,0,0)
264 static void GetPreferredWidth(GtkWidget
*widget
, gint
*minimalWidth
, gint
*naturalWidth
);
265 static void GetPreferredHeight(GtkWidget
*widget
, gint
*minimalHeight
, gint
*naturalHeight
);
267 static void SizeAllocate(GtkWidget
*widget
, GtkAllocation
*allocation
);
268 #if GTK_CHECK_VERSION(3,0,0)
269 gboolean
DrawTextThis(cairo_t
*cr
);
270 static gboolean
DrawText(GtkWidget
*widget
, cairo_t
*cr
, ScintillaGTK
*sciThis
);
271 gboolean
DrawThis(cairo_t
*cr
);
272 static gboolean
DrawMain(GtkWidget
*widget
, cairo_t
*cr
);
274 gboolean
ExposeTextThis(GtkWidget
*widget
, GdkEventExpose
*ose
);
275 static gboolean
ExposeText(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
);
276 gboolean
Expose(GtkWidget
*widget
, GdkEventExpose
*ose
);
277 static gboolean
ExposeMain(GtkWidget
*widget
, GdkEventExpose
*ose
);
279 static void Draw(GtkWidget
*widget
, GdkRectangle
*area
);
280 void ForAll(GtkCallback callback
, gpointer callback_data
);
281 static void MainForAll(GtkContainer
*container
, gboolean include_internals
, GtkCallback callback
, gpointer callback_data
);
283 static void ScrollSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
);
284 static void ScrollHSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
);
285 gint
PressThis(GdkEventButton
*event
);
286 static gint
Press(GtkWidget
*widget
, GdkEventButton
*event
);
287 static gint
MouseRelease(GtkWidget
*widget
, GdkEventButton
*event
);
288 static gint
ScrollEvent(GtkWidget
*widget
, GdkEventScroll
*event
);
289 static gint
Motion(GtkWidget
*widget
, GdkEventMotion
*event
);
290 gboolean
KeyThis(GdkEventKey
*event
);
291 static gboolean
KeyPress(GtkWidget
*widget
, GdkEventKey
*event
);
292 static gboolean
KeyRelease(GtkWidget
*widget
, GdkEventKey
*event
);
293 #if GTK_CHECK_VERSION(3,0,0)
294 gboolean
DrawPreeditThis(GtkWidget
*widget
, cairo_t
*cr
);
295 static gboolean
DrawPreedit(GtkWidget
*widget
, cairo_t
*cr
, ScintillaGTK
*sciThis
);
297 gboolean
ExposePreeditThis(GtkWidget
*widget
, GdkEventExpose
*ose
);
298 static gboolean
ExposePreedit(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
);
302 void CommitThis(char *str
);
303 static void Commit(GtkIMContext
*context
, char *str
, ScintillaGTK
*sciThis
);
304 void PreeditChangedInlineThis();
305 void PreeditChangedWindowedThis();
306 static void PreeditChanged(GtkIMContext
*context
, ScintillaGTK
*sciThis
);
307 void MoveImeCarets(int pos
);
308 void DrawImeIndicator(int indicator
, int len
);
309 static void GetImeUnderlines(PangoAttrList
*attrs
, bool *normalInput
);
310 static void GetImeBackgrounds(PangoAttrList
*attrs
, bool *targetInput
);
311 void SetCandidateWindowPos();
313 static void StyleSetText(GtkWidget
*widget
, GtkStyle
*previous
, void*);
314 static void RealizeText(GtkWidget
*widget
, void*);
315 static void Destroy(GObject
*object
);
316 static void SelectionReceived(GtkWidget
*widget
, GtkSelectionData
*selection_data
,
318 static void ClipboardReceived(GtkClipboard
*clipboard
, GtkSelectionData
*selection_data
,
320 static void SelectionGet(GtkWidget
*widget
, GtkSelectionData
*selection_data
,
321 guint info
, guint time
);
322 static gint
SelectionClear(GtkWidget
*widget
, GdkEventSelection
*selection_event
);
323 gboolean
DragMotionThis(GdkDragContext
*context
, gint x
, gint y
, guint dragtime
);
324 static gboolean
DragMotion(GtkWidget
*widget
, GdkDragContext
*context
,
325 gint x
, gint y
, guint dragtime
);
326 static void DragLeave(GtkWidget
*widget
, GdkDragContext
*context
,
328 static void DragEnd(GtkWidget
*widget
, GdkDragContext
*context
);
329 static gboolean
Drop(GtkWidget
*widget
, GdkDragContext
*context
,
330 gint x
, gint y
, guint time
);
331 static void DragDataReceived(GtkWidget
*widget
, GdkDragContext
*context
,
332 gint x
, gint y
, GtkSelectionData
*selection_data
, guint info
, guint time
);
333 static void DragDataGet(GtkWidget
*widget
, GdkDragContext
*context
,
334 GtkSelectionData
*selection_data
, guint info
, guint time
);
335 static gboolean
TimeOut(TimeThunk
*tt
);
336 static gboolean
IdleCallback(ScintillaGTK
*sciThis
);
337 static gboolean
StyleIdle(ScintillaGTK
*sciThis
);
338 virtual void QueueIdleWork(WorkNeeded::workItems items
, int upTo
);
339 static void PopUpCB(GtkMenuItem
*menuItem
, ScintillaGTK
*sciThis
);
341 #if GTK_CHECK_VERSION(3,0,0)
342 static gboolean
DrawCT(GtkWidget
*widget
, cairo_t
*cr
, CallTip
*ctip
);
344 static gboolean
ExposeCT(GtkWidget
*widget
, GdkEventExpose
*ose
, CallTip
*ct
);
346 static gboolean
PressCT(GtkWidget
*widget
, GdkEventButton
*event
, ScintillaGTK
*sciThis
);
348 static sptr_t
DirectFunction(sptr_t ptr
,
349 unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
358 static gint scintilla_signals
[LAST_SIGNAL
] = { 0 };
363 TARGET_COMPOUND_TEXT
,
368 GdkAtom
ScintillaGTK::atomClipboard
= 0;
369 GdkAtom
ScintillaGTK::atomUTF8
= 0;
370 GdkAtom
ScintillaGTK::atomString
= 0;
371 GdkAtom
ScintillaGTK::atomUriList
= 0;
372 GdkAtom
ScintillaGTK::atomDROPFILES_DND
= 0;
374 static const GtkTargetEntry clipboardCopyTargets
[] = {
375 { (gchar
*) "UTF8_STRING", 0, TARGET_UTF8_STRING
},
376 { (gchar
*) "STRING", 0, TARGET_STRING
},
378 static const gint nClipboardCopyTargets
= ELEMENTS(clipboardCopyTargets
);
380 static const GtkTargetEntry clipboardPasteTargets
[] = {
381 { (gchar
*) "text/uri-list", 0, TARGET_URI
},
382 { (gchar
*) "UTF8_STRING", 0, TARGET_UTF8_STRING
},
383 { (gchar
*) "STRING", 0, TARGET_STRING
},
385 static const gint nClipboardPasteTargets
= ELEMENTS(clipboardPasteTargets
);
387 static GtkWidget
*PWidget(Window
&w
) {
388 return reinterpret_cast<GtkWidget
*>(w
.GetID());
391 static ScintillaGTK
*ScintillaFromWidget(GtkWidget
*widget
) {
392 ScintillaObject
*scio
= reinterpret_cast<ScintillaObject
*>(widget
);
393 return reinterpret_cast<ScintillaGTK
*>(scio
->pscin
);
396 ScintillaGTK::ScintillaGTK(_ScintillaObject
*sci_
) :
397 adjustmentv(0), adjustmenth(0),
398 verticalScrollBarWidth(30), horizontalScrollBarHeight(30),
399 evbtn(0), capturedMouse(false), dragWasDropped(false),
400 lastKey(0), rectangularSelectionModifier(SCMOD_CTRL
), parentClass(0),
401 im_context(NULL
), lastNonCommonScript(PANGO_SCRIPT_INVALID_CODE
),
402 lastWheelMouseDirection(0),
403 wheelMouseIntensity(0),
405 repaintFullWindow(false) {
407 wMain
= GTK_WIDGET(sci
);
410 rectangularSelectionModifier
= SCMOD_ALT
;
412 rectangularSelectionModifier
= SCMOD_CTRL
;
416 // There does not seem to be a real standard for indicating that the clipboard
417 // contains a rectangular selection, so copy Developer Studio.
418 cfColumnSelect
= static_cast<CLIPFORMAT
>(
419 ::RegisterClipboardFormat("MSDEVColumnSelect"));
421 // Get intellimouse parameters when running on win32; otherwise use
422 // reasonable default
423 #ifndef SPI_GETWHEELSCROLLLINES
424 #define SPI_GETWHEELSCROLLLINES 104
426 ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &linesPerScroll
, 0);
430 lastWheelMouseTime
.tv_sec
= 0;
431 lastWheelMouseTime
.tv_usec
= 0;
436 ScintillaGTK::~ScintillaGTK() {
437 g_idle_remove_by_data(this);
439 gdk_event_free(reinterpret_cast<GdkEvent
*>(evbtn
));
445 static void UnRefCursor(GdkCursor
*cursor
) {
446 #if GTK_CHECK_VERSION(3,0,0)
447 g_object_unref(cursor
);
449 gdk_cursor_unref(cursor
);
453 void ScintillaGTK::RealizeThis(GtkWidget
*widget
) {
454 //Platform::DebugPrintf("ScintillaGTK::realize this\n");
455 #if GTK_CHECK_VERSION(2,20,0)
456 gtk_widget_set_realized(widget
, TRUE
);
458 GTK_WIDGET_SET_FLAGS(widget
, GTK_REALIZED
);
461 attrs
.window_type
= GDK_WINDOW_CHILD
;
462 GtkAllocation allocation
;
463 #if GTK_CHECK_VERSION(3,0,0)
464 gtk_widget_get_allocation(widget
, &allocation
);
466 allocation
= widget
->allocation
;
468 attrs
.x
= allocation
.x
;
469 attrs
.y
= allocation
.y
;
470 attrs
.width
= allocation
.width
;
471 attrs
.height
= allocation
.height
;
472 attrs
.wclass
= GDK_INPUT_OUTPUT
;
473 attrs
.visual
= gtk_widget_get_visual(widget
);
474 #if !GTK_CHECK_VERSION(3,0,0)
475 attrs
.colormap
= gtk_widget_get_colormap(widget
);
477 attrs
.event_mask
= gtk_widget_get_events(widget
) | GDK_EXPOSURE_MASK
;
478 GdkCursor
*cursor
= gdk_cursor_new(GDK_XTERM
);
479 attrs
.cursor
= cursor
;
480 #if GTK_CHECK_VERSION(3,0,0)
481 gtk_widget_set_window(widget
, gdk_window_new(gtk_widget_get_parent_window(widget
), &attrs
,
482 GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
| GDK_WA_CURSOR
));
483 gdk_window_set_user_data(gtk_widget_get_window(widget
), widget
);
484 GtkStyleContext
*styleContext
= gtk_widget_get_style_context(widget
);
486 GdkRGBA colourBackWidget
;
487 gtk_style_context_get_background_color(styleContext
, GTK_STATE_FLAG_NORMAL
, &colourBackWidget
);
488 gdk_window_set_background_rgba(gtk_widget_get_window(widget
), &colourBackWidget
);
490 gdk_window_show(gtk_widget_get_window(widget
));
493 widget
->window
= gdk_window_new(gtk_widget_get_parent_window(widget
), &attrs
,
494 GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
| GDK_WA_COLORMAP
| GDK_WA_CURSOR
);
495 gdk_window_set_user_data(widget
->window
, widget
);
496 widget
->style
= gtk_style_attach(widget
->style
, widget
->window
);
497 gdk_window_set_background(widget
->window
, &widget
->style
->bg
[GTK_STATE_NORMAL
]);
498 gdk_window_show(widget
->window
);
501 gtk_widget_realize(PWidget(wPreedit
));
502 gtk_widget_realize(PWidget(wPreeditDraw
));
504 im_context
= gtk_im_multicontext_new();
505 g_signal_connect(G_OBJECT(im_context
), "commit",
506 G_CALLBACK(Commit
), this);
507 g_signal_connect(G_OBJECT(im_context
), "preedit_changed",
508 G_CALLBACK(PreeditChanged
), this);
509 gtk_im_context_set_client_window(im_context
, WindowFromWidget(widget
));
510 GtkWidget
*widtxt
= PWidget(wText
); // // No code inside the G_OBJECT macro
511 g_signal_connect_after(G_OBJECT(widtxt
), "style_set",
512 G_CALLBACK(ScintillaGTK::StyleSetText
), NULL
);
513 g_signal_connect_after(G_OBJECT(widtxt
), "realize",
514 G_CALLBACK(ScintillaGTK::RealizeText
), NULL
);
515 gtk_widget_realize(widtxt
);
516 gtk_widget_realize(PWidget(scrollbarv
));
517 gtk_widget_realize(PWidget(scrollbarh
));
519 cursor
= gdk_cursor_new(GDK_XTERM
);
520 gdk_window_set_cursor(PWindow(wText
), cursor
);
523 cursor
= gdk_cursor_new(GDK_LEFT_PTR
);
524 gdk_window_set_cursor(PWindow(scrollbarv
), cursor
);
527 cursor
= gdk_cursor_new(GDK_LEFT_PTR
);
528 gdk_window_set_cursor(PWindow(scrollbarh
), cursor
);
531 gtk_selection_add_targets(widget
, GDK_SELECTION_PRIMARY
,
532 clipboardCopyTargets
, nClipboardCopyTargets
);
535 void ScintillaGTK::Realize(GtkWidget
*widget
) {
536 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
537 sciThis
->RealizeThis(widget
);
540 void ScintillaGTK::UnRealizeThis(GtkWidget
*widget
) {
542 gtk_selection_clear_targets(widget
, GDK_SELECTION_PRIMARY
);
544 if (IS_WIDGET_MAPPED(widget
)) {
545 gtk_widget_unmap(widget
);
547 #if GTK_CHECK_VERSION(2,20,0)
548 gtk_widget_set_realized(widget
, FALSE
);
550 GTK_WIDGET_UNSET_FLAGS(widget
, GTK_REALIZED
);
552 gtk_widget_unrealize(PWidget(wText
));
553 gtk_widget_unrealize(PWidget(scrollbarv
));
554 gtk_widget_unrealize(PWidget(scrollbarh
));
555 gtk_widget_unrealize(PWidget(wPreedit
));
556 gtk_widget_unrealize(PWidget(wPreeditDraw
));
557 g_object_unref(im_context
);
559 if (GTK_WIDGET_CLASS(parentClass
)->unrealize
)
560 GTK_WIDGET_CLASS(parentClass
)->unrealize(widget
);
564 errorStatus
= SC_STATUS_FAILURE
;
568 void ScintillaGTK::UnRealize(GtkWidget
*widget
) {
569 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
570 sciThis
->UnRealizeThis(widget
);
573 static void MapWidget(GtkWidget
*widget
) {
575 IS_WIDGET_VISIBLE(widget
) &&
576 !IS_WIDGET_MAPPED(widget
)) {
577 gtk_widget_map(widget
);
581 void ScintillaGTK::MapThis() {
583 //Platform::DebugPrintf("ScintillaGTK::map this\n");
584 #if GTK_CHECK_VERSION(2,20,0)
585 gtk_widget_set_mapped(PWidget(wMain
), TRUE
);
587 GTK_WIDGET_SET_FLAGS(PWidget(wMain
), GTK_MAPPED
);
589 MapWidget(PWidget(wText
));
590 MapWidget(PWidget(scrollbarh
));
591 MapWidget(PWidget(scrollbarv
));
592 wMain
.SetCursor(Window::cursorArrow
);
593 scrollbarv
.SetCursor(Window::cursorArrow
);
594 scrollbarh
.SetCursor(Window::cursorArrow
);
596 gdk_window_show(PWindow(wMain
));
598 errorStatus
= SC_STATUS_FAILURE
;
602 void ScintillaGTK::Map(GtkWidget
*widget
) {
603 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
607 void ScintillaGTK::UnMapThis() {
609 //Platform::DebugPrintf("ScintillaGTK::unmap this\n");
610 #if GTK_CHECK_VERSION(2,20,0)
611 gtk_widget_set_mapped(PWidget(wMain
), FALSE
);
613 GTK_WIDGET_UNSET_FLAGS(PWidget(wMain
), GTK_MAPPED
);
616 gdk_window_hide(PWindow(wMain
));
617 gtk_widget_unmap(PWidget(wText
));
618 gtk_widget_unmap(PWidget(scrollbarh
));
619 gtk_widget_unmap(PWidget(scrollbarv
));
621 errorStatus
= SC_STATUS_FAILURE
;
625 void ScintillaGTK::UnMap(GtkWidget
*widget
) {
626 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
627 sciThis
->UnMapThis();
630 void ScintillaGTK::ForAll(GtkCallback callback
, gpointer callback_data
) {
632 (*callback
) (PWidget(wText
), callback_data
);
633 (*callback
) (PWidget(scrollbarv
), callback_data
);
634 (*callback
) (PWidget(scrollbarh
), callback_data
);
636 errorStatus
= SC_STATUS_FAILURE
;
640 void ScintillaGTK::MainForAll(GtkContainer
*container
, gboolean include_internals
, GtkCallback callback
, gpointer callback_data
) {
641 ScintillaGTK
*sciThis
= ScintillaFromWidget((GtkWidget
*)container
);
643 if (callback
!= NULL
&& include_internals
) {
644 sciThis
->ForAll(callback
, callback_data
);
650 class PreEditString
{
654 PangoAttrList
*attrs
;
660 explicit PreEditString(GtkIMContext
*im_context
) {
661 gtk_im_context_get_preedit_string(im_context
, &str
, &attrs
, &cursor_pos
);
662 validUTF8
= g_utf8_validate(str
, strlen(str
), NULL
);
663 uniStr
= g_utf8_to_ucs4_fast(str
, strlen(str
), &uniStrLen
);
664 pscript
= pango_script_for_unichar(uniStr
[0]);
669 pango_attr_list_unref(attrs
);
675 gint
ScintillaGTK::FocusInThis(GtkWidget
*widget
) {
678 if (im_context
!= NULL
) {
679 PreEditString
pes(im_context
);
680 if (PWidget(wPreedit
) != NULL
) {
681 if (strlen(pes
.str
) > 0) {
682 gtk_widget_show(PWidget(wPreedit
));
684 gtk_widget_hide(PWidget(wPreedit
));
687 gtk_im_context_focus_in(im_context
);
691 errorStatus
= SC_STATUS_FAILURE
;
696 gint
ScintillaGTK::FocusIn(GtkWidget
*widget
, GdkEventFocus
* /*event*/) {
697 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
698 return sciThis
->FocusInThis(widget
);
701 gint
ScintillaGTK::FocusOutThis(GtkWidget
*widget
) {
703 SetFocusState(false);
705 if (PWidget(wPreedit
) != NULL
)
706 gtk_widget_hide(PWidget(wPreedit
));
707 if (im_context
!= NULL
)
708 gtk_im_context_focus_out(im_context
);
711 errorStatus
= SC_STATUS_FAILURE
;
716 gint
ScintillaGTK::FocusOut(GtkWidget
*widget
, GdkEventFocus
* /*event*/) {
717 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
718 return sciThis
->FocusOutThis(widget
);
721 void ScintillaGTK::SizeRequest(GtkWidget
*widget
, GtkRequisition
*requisition
) {
722 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
723 requisition
->width
= 1;
724 requisition
->height
= 1;
725 GtkRequisition child_requisition
;
726 #if GTK_CHECK_VERSION(3,0,0)
727 gtk_widget_get_preferred_size(PWidget(sciThis
->scrollbarh
), NULL
, &child_requisition
);
728 gtk_widget_get_preferred_size(PWidget(sciThis
->scrollbarv
), NULL
, &child_requisition
);
730 gtk_widget_size_request(PWidget(sciThis
->scrollbarh
), &child_requisition
);
731 gtk_widget_size_request(PWidget(sciThis
->scrollbarv
), &child_requisition
);
735 #if GTK_CHECK_VERSION(3,0,0)
737 void ScintillaGTK::GetPreferredWidth(GtkWidget
*widget
, gint
*minimalWidth
, gint
*naturalWidth
) {
738 GtkRequisition requisition
;
739 SizeRequest(widget
, &requisition
);
740 *minimalWidth
= *naturalWidth
= requisition
.width
;
743 void ScintillaGTK::GetPreferredHeight(GtkWidget
*widget
, gint
*minimalHeight
, gint
*naturalHeight
) {
744 GtkRequisition requisition
;
745 SizeRequest(widget
, &requisition
);
746 *minimalHeight
= *naturalHeight
= requisition
.height
;
751 void ScintillaGTK::SizeAllocate(GtkWidget
*widget
, GtkAllocation
*allocation
) {
752 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
754 #if GTK_CHECK_VERSION(2,20,0)
755 gtk_widget_set_allocation(widget
, allocation
);
757 widget
->allocation
= *allocation
;
759 if (IS_WIDGET_REALIZED(widget
))
760 gdk_window_move_resize(WindowFromWidget(widget
),
766 sciThis
->Resize(allocation
->width
, allocation
->height
);
769 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
773 void ScintillaGTK::Initialise() {
774 //Platform::DebugPrintf("ScintillaGTK::Initialise\n");
775 parentClass
= reinterpret_cast<GtkWidgetClass
*>(
776 g_type_class_ref(gtk_container_get_type()));
778 #if GTK_CHECK_VERSION(2,20,0)
779 gtk_widget_set_can_focus(PWidget(wMain
), TRUE
);
780 gtk_widget_set_sensitive(PWidget(wMain
), TRUE
);
782 GTK_WIDGET_SET_FLAGS(PWidget(wMain
), GTK_CAN_FOCUS
);
783 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(PWidget(wMain
)), GTK_SENSITIVE
);
785 gtk_widget_set_events(PWidget(wMain
),
790 | GDK_KEY_RELEASE_MASK
791 | GDK_FOCUS_CHANGE_MASK
792 | GDK_LEAVE_NOTIFY_MASK
793 | GDK_BUTTON_PRESS_MASK
794 | GDK_BUTTON_RELEASE_MASK
795 | GDK_POINTER_MOTION_MASK
796 | GDK_POINTER_MOTION_HINT_MASK
);
798 wText
= gtk_drawing_area_new();
799 gtk_widget_set_parent(PWidget(wText
), PWidget(wMain
));
800 GtkWidget
*widtxt
= PWidget(wText
); // No code inside the G_OBJECT macro
801 gtk_widget_show(widtxt
);
802 #if GTK_CHECK_VERSION(3,0,0)
803 g_signal_connect(G_OBJECT(widtxt
), "draw",
804 G_CALLBACK(ScintillaGTK::DrawText
), this);
806 g_signal_connect(G_OBJECT(widtxt
), "expose_event",
807 G_CALLBACK(ScintillaGTK::ExposeText
), this);
809 #if GTK_CHECK_VERSION(3,0,0)
810 // we need a runtime check because we don't want double buffering when
811 // running on >= 3.9.2
812 if (gtk_check_version(3,9,2) != NULL
/* on < 3.9.2 */)
815 #if !GTK_CHECK_VERSION(3,14,0)
816 // Avoid background drawing flash/missing redraws
817 gtk_widget_set_double_buffered(widtxt
, FALSE
);
820 gtk_widget_set_events(widtxt
, GDK_EXPOSURE_MASK
);
821 gtk_widget_set_size_request(widtxt
, 100, 100);
822 adjustmentv
= GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 201.0, 1.0, 20.0, 20.0));
823 #if GTK_CHECK_VERSION(3,0,0)
824 scrollbarv
= gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL
, GTK_ADJUSTMENT(adjustmentv
));
826 scrollbarv
= gtk_vscrollbar_new(GTK_ADJUSTMENT(adjustmentv
));
828 #if GTK_CHECK_VERSION(2,20,0)
829 gtk_widget_set_can_focus(PWidget(scrollbarv
), FALSE
);
831 GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarv
), GTK_CAN_FOCUS
);
833 g_signal_connect(G_OBJECT(adjustmentv
), "value_changed",
834 G_CALLBACK(ScrollSignal
), this);
835 gtk_widget_set_parent(PWidget(scrollbarv
), PWidget(wMain
));
836 gtk_widget_show(PWidget(scrollbarv
));
838 adjustmenth
= GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 101.0, 1.0, 20.0, 20.0));
839 #if GTK_CHECK_VERSION(3,0,0)
840 scrollbarh
= gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL
, GTK_ADJUSTMENT(adjustmenth
));
842 scrollbarh
= gtk_hscrollbar_new(GTK_ADJUSTMENT(adjustmenth
));
844 #if GTK_CHECK_VERSION(2,20,0)
845 gtk_widget_set_can_focus(PWidget(scrollbarh
), FALSE
);
847 GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarh
), GTK_CAN_FOCUS
);
849 g_signal_connect(G_OBJECT(adjustmenth
), "value_changed",
850 G_CALLBACK(ScrollHSignal
), this);
851 gtk_widget_set_parent(PWidget(scrollbarh
), PWidget(wMain
));
852 gtk_widget_show(PWidget(scrollbarh
));
854 gtk_widget_grab_focus(PWidget(wMain
));
856 gtk_drag_dest_set(GTK_WIDGET(PWidget(wMain
)),
857 GTK_DEST_DEFAULT_ALL
, clipboardPasteTargets
, nClipboardPasteTargets
,
858 static_cast<GdkDragAction
>(GDK_ACTION_COPY
| GDK_ACTION_MOVE
));
860 /* create pre-edit window */
861 wPreedit
= gtk_window_new(GTK_WINDOW_POPUP
);
862 wPreeditDraw
= gtk_drawing_area_new();
863 GtkWidget
*predrw
= PWidget(wPreeditDraw
); // No code inside the G_OBJECT macro
864 #if GTK_CHECK_VERSION(3,0,0)
865 g_signal_connect(G_OBJECT(predrw
), "draw",
866 G_CALLBACK(DrawPreedit
), this);
868 g_signal_connect(G_OBJECT(predrw
), "expose_event",
869 G_CALLBACK(ExposePreedit
), this);
871 gtk_container_add(GTK_CONTAINER(PWidget(wPreedit
)), predrw
);
872 gtk_widget_show(predrw
);
874 // Set caret period based on GTK settings
875 gboolean blinkOn
= false;
876 if (g_object_class_find_property(G_OBJECT_GET_CLASS(
877 G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink")) {
878 g_object_get(G_OBJECT(
879 gtk_settings_get_default()), "gtk-cursor-blink", &blinkOn
, NULL
);
882 g_object_class_find_property(G_OBJECT_GET_CLASS(
883 G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink-time")) {
885 g_object_get(G_OBJECT(
886 gtk_settings_get_default()), "gtk-cursor-blink-time", &value
, NULL
);
887 caret
.period
= gint(value
/ 1.75);
892 for (TickReason tr
= tickCaret
; tr
<= tickDwell
; tr
= static_cast<TickReason
>(tr
+ 1)) {
893 timers
[tr
].reason
= tr
;
894 timers
[tr
].scintilla
= this;
896 vs
.indicators
[SC_INDICATOR_UNKNOWN
] = Indicator(INDIC_HIDDEN
, ColourDesired(0, 0, 0xff));
897 vs
.indicators
[SC_INDICATOR_INPUT
] = Indicator(INDIC_DOTS
, ColourDesired(0, 0, 0xff));
898 vs
.indicators
[SC_INDICATOR_CONVERTED
] = Indicator(INDIC_COMPOSITIONTHICK
, ColourDesired(0, 0, 0xff));
899 vs
.indicators
[SC_INDICATOR_TARGET
] = Indicator(INDIC_STRAIGHTBOX
, ColourDesired(0, 0, 0xff));
902 void ScintillaGTK::Finalise() {
903 for (TickReason tr
= tickCaret
; tr
<= tickDwell
; tr
= static_cast<TickReason
>(tr
+ 1)) {
904 FineTickerCancel(tr
);
906 ScintillaBase::Finalise();
909 bool ScintillaGTK::AbandonPaint() {
910 if ((paintState
== painting
) && !paintingAllText
) {
911 repaintFullWindow
= true;
916 void ScintillaGTK::DisplayCursor(Window::Cursor c
) {
917 if (cursorMode
== SC_CURSORNORMAL
)
920 wText
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
923 bool ScintillaGTK::DragThreshold(Point ptStart
, Point ptNow
) {
924 return gtk_drag_check_threshold(GTK_WIDGET(PWidget(wMain
)),
925 ptStart
.x
, ptStart
.y
, ptNow
.x
, ptNow
.y
);
928 void ScintillaGTK::StartDrag() {
929 PLATFORM_ASSERT(evbtn
!= 0);
930 dragWasDropped
= false;
931 inDragDrop
= ddDragging
;
932 GtkTargetList
*tl
= gtk_target_list_new(clipboardCopyTargets
, nClipboardCopyTargets
);
933 #if GTK_CHECK_VERSION(3,10,0)
934 gtk_drag_begin_with_coordinates(GTK_WIDGET(PWidget(wMain
)),
936 static_cast<GdkDragAction
>(GDK_ACTION_COPY
| GDK_ACTION_MOVE
),
938 reinterpret_cast<GdkEvent
*>(evbtn
),
941 gtk_drag_begin(GTK_WIDGET(PWidget(wMain
)),
943 static_cast<GdkDragAction
>(GDK_ACTION_COPY
| GDK_ACTION_MOVE
),
945 reinterpret_cast<GdkEvent
*>(evbtn
));
949 static std::string
ConvertText(const char *s
, size_t len
, const char *charSetDest
,
950 const char *charSetSource
, bool transliterations
, bool silent
=false) {
951 // s is not const because of different versions of iconv disagreeing about const
952 std::string destForm
;
953 Converter
conv(charSetDest
, charSetSource
, transliterations
);
955 size_t outLeft
= len
*3+1;
956 destForm
= std::string(outLeft
, '\0');
957 // g_iconv does not actually write to its input argument so safe to cast away const
958 char *pin
= const_cast<char *>(s
);
960 char *putf
= &destForm
[0];
962 size_t conversions
= conv
.Convert(&pin
, &inLeft
, &pout
, &outLeft
);
963 if (conversions
== ((size_t)(-1))) {
966 fprintf(stderr
, "iconv %s->%s failed for %0x '%s'\n",
967 charSetSource
, charSetDest
, (unsigned char)(*s
), s
);
969 fprintf(stderr
, "iconv %s->%s failed for %s\n",
970 charSetSource
, charSetDest
, s
);
972 destForm
= std::string();
974 destForm
.resize(pout
- putf
);
977 fprintf(stderr
, "Can not iconv %s %s\n", charSetDest
, charSetSource
);
982 // Returns the target converted to UTF8.
983 // Return the length in bytes.
984 int ScintillaGTK::TargetAsUTF8(char *text
) {
985 int targetLength
= targetEnd
- targetStart
;
986 if (IsUnicodeMode()) {
988 pdoc
->GetCharRange(text
, targetStart
, targetLength
);
992 const char *charSetBuffer
= CharacterSetID();
993 if (*charSetBuffer
) {
994 std::string s
= RangeText(targetStart
, targetEnd
);
995 std::string tmputf
= ConvertText(&s
[0], targetLength
, "UTF-8", charSetBuffer
, false);
997 memcpy(text
, tmputf
.c_str(), tmputf
.length());
999 return tmputf
.length();
1002 pdoc
->GetCharRange(text
, targetStart
, targetLength
);
1006 return targetLength
;
1009 // Translates a nul terminated UTF8 string into the document encoding.
1010 // Return the length of the result in bytes.
1011 int ScintillaGTK::EncodedFromUTF8(char *utf8
, char *encoded
) const {
1012 int inputLength
= (lengthForEncode
>= 0) ? lengthForEncode
: strlen(utf8
);
1013 if (IsUnicodeMode()) {
1015 memcpy(encoded
, utf8
, inputLength
);
1020 const char *charSetBuffer
= CharacterSetID();
1021 if (*charSetBuffer
) {
1022 std::string tmpEncoded
= ConvertText(utf8
, inputLength
, charSetBuffer
, "UTF-8", true);
1024 memcpy(encoded
, tmpEncoded
.c_str(), tmpEncoded
.length());
1026 return tmpEncoded
.length();
1029 memcpy(encoded
, utf8
, inputLength
);
1038 bool ScintillaGTK::ValidCodePage(int codePage
) const {
1039 return codePage
== 0
1040 || codePage
== SC_CP_UTF8
1045 || codePage
== 1361;
1048 sptr_t
ScintillaGTK::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
1053 gtk_widget_grab_focus(PWidget(wMain
));
1056 case SCI_GETDIRECTFUNCTION
:
1057 return reinterpret_cast<sptr_t
>(DirectFunction
);
1059 case SCI_GETDIRECTPOINTER
:
1060 return reinterpret_cast<sptr_t
>(this);
1063 case SCI_LOADLEXERLIBRARY
:
1064 LexerManager::GetInstance()->Load(reinterpret_cast<const char*>(lParam
));
1067 case SCI_TARGETASUTF8
:
1068 return TargetAsUTF8(reinterpret_cast<char*>(lParam
));
1070 case SCI_ENCODEDFROMUTF8
:
1071 return EncodedFromUTF8(reinterpret_cast<char*>(wParam
),
1072 reinterpret_cast<char*>(lParam
));
1074 case SCI_SETRECTANGULARSELECTIONMODIFIER
:
1075 rectangularSelectionModifier
= wParam
;
1078 case SCI_GETRECTANGULARSELECTIONMODIFIER
:
1079 return rectangularSelectionModifier
;
1082 return ScintillaBase::WndProc(iMessage
, wParam
, lParam
);
1084 } catch (std::bad_alloc
&) {
1085 errorStatus
= SC_STATUS_BADALLOC
;
1087 errorStatus
= SC_STATUS_FAILURE
;
1092 sptr_t
ScintillaGTK::DefWndProc(unsigned int, uptr_t
, sptr_t
) {
1097 * Report that this Editor subclass has a working implementation of FineTickerStart.
1099 bool ScintillaGTK::FineTickerAvailable() {
1103 bool ScintillaGTK::FineTickerRunning(TickReason reason
) {
1104 return timers
[reason
].timer
!= 0;
1107 void ScintillaGTK::FineTickerStart(TickReason reason
, int millis
, int /* tolerance */) {
1108 FineTickerCancel(reason
);
1109 timers
[reason
].timer
= g_timeout_add(millis
, reinterpret_cast<GSourceFunc
>(TimeOut
), &timers
[reason
]);
1112 void ScintillaGTK::FineTickerCancel(TickReason reason
) {
1113 if (timers
[reason
].timer
) {
1114 g_source_remove(timers
[reason
].timer
);
1115 timers
[reason
].timer
= 0;
1119 bool ScintillaGTK::SetIdle(bool on
) {
1121 // Start idler, if it's not running.
1124 idler
.idlerID
= reinterpret_cast<IdlerID
>(
1125 g_idle_add_full(G_PRIORITY_DEFAULT_IDLE
,
1126 reinterpret_cast<GSourceFunc
>(IdleCallback
), this, NULL
));
1129 // Stop idler, if it's running
1131 idler
.state
= false;
1132 g_source_remove(GPOINTER_TO_UINT(idler
.idlerID
));
1138 void ScintillaGTK::SetMouseCapture(bool on
) {
1139 if (mouseDownCaptures
) {
1141 gtk_grab_add(GTK_WIDGET(PWidget(wMain
)));
1143 gtk_grab_remove(GTK_WIDGET(PWidget(wMain
)));
1149 bool ScintillaGTK::HaveMouseCapture() {
1150 return capturedMouse
;
1153 #if GTK_CHECK_VERSION(3,0,0)
1155 // Is crcTest completely in crcContainer?
1156 static bool CRectContains(const cairo_rectangle_t
&crcContainer
, const cairo_rectangle_t
&crcTest
) {
1158 (crcTest
.x
>= crcContainer
.x
) && ((crcTest
.x
+ crcTest
.width
) <= (crcContainer
.x
+ crcContainer
.width
)) &&
1159 (crcTest
.y
>= crcContainer
.y
) && ((crcTest
.y
+ crcTest
.height
) <= (crcContainer
.y
+ crcContainer
.height
));
1162 // Is crcTest completely in crcListContainer?
1163 // May incorrectly return false if complex shape
1164 static bool CRectListContains(const cairo_rectangle_list_t
*crcListContainer
, const cairo_rectangle_t
&crcTest
) {
1165 for (int r
=0; r
<crcListContainer
->num_rectangles
; r
++) {
1166 if (CRectContains(crcListContainer
->rectangles
[r
], crcTest
))
1174 bool ScintillaGTK::PaintContains(PRectangle rc
) {
1175 // This allows optimization when a rectangle is completely in the update region.
1176 // It is OK to return false when too difficult to determine as that just performs extra drawing
1177 bool contains
= true;
1178 if (paintState
== painting
) {
1179 if (!rcPaint
.Contains(rc
)) {
1181 } else if (rgnUpdate
) {
1182 #if GTK_CHECK_VERSION(3,0,0)
1183 cairo_rectangle_t grc
= {rc
.left
, rc
.top
,
1184 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
};
1185 contains
= CRectListContains(rgnUpdate
, grc
);
1187 GdkRectangle grc
= {static_cast<gint
>(rc
.left
), static_cast<gint
>(rc
.top
),
1188 static_cast<gint
>(rc
.right
- rc
.left
), static_cast<gint
>(rc
.bottom
- rc
.top
)};
1189 if (gdk_region_rect_in(rgnUpdate
, &grc
) != GDK_OVERLAP_RECTANGLE_IN
) {
1198 // Redraw all of text area. This paint will not be abandoned.
1199 void ScintillaGTK::FullPaint() {
1200 wText
.InvalidateAll();
1203 PRectangle
ScintillaGTK::GetClientRectangle() const {
1204 Window
&win
= const_cast<Window
&>(wMain
);
1205 PRectangle rc
= win
.GetClientPosition();
1206 if (verticalScrollBarVisible
)
1207 rc
.right
-= verticalScrollBarWidth
;
1208 if (horizontalScrollBarVisible
&& !Wrapping())
1209 rc
.bottom
-= horizontalScrollBarHeight
;
1211 rc
.right
-= rc
.left
;
1212 rc
.bottom
-= rc
.top
;
1218 void ScintillaGTK::ScrollText(int linesToMove
) {
1219 int diff
= vs
.lineHeight
* -linesToMove
;
1220 //Platform::DebugPrintf("ScintillaGTK::ScrollText %d %d %0d,%0d %0d,%0d\n", linesToMove, diff,
1221 // rc.left, rc.top, rc.right, rc.bottom);
1222 GtkWidget
*wi
= PWidget(wText
);
1225 if (IS_WIDGET_REALIZED(wi
)) {
1226 gdk_window_scroll(WindowFromWidget(wi
), 0, -diff
);
1227 gdk_window_process_updates(WindowFromWidget(wi
), FALSE
);
1231 void ScintillaGTK::SetVerticalScrollPos() {
1233 gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmentv
), topLine
);
1236 void ScintillaGTK::SetHorizontalScrollPos() {
1238 gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmenth
), xOffset
);
1241 bool ScintillaGTK::ModifyScrollBars(int nMax
, int nPage
) {
1242 bool modified
= false;
1243 int pageScroll
= LinesToScroll();
1245 #if GTK_CHECK_VERSION(3,0,0)
1246 if (gtk_adjustment_get_upper(adjustmentv
) != (nMax
+ 1) ||
1247 gtk_adjustment_get_page_size(adjustmentv
) != nPage
||
1248 gtk_adjustment_get_page_increment(adjustmentv
) != pageScroll
) {
1249 gtk_adjustment_set_upper(adjustmentv
, nMax
+ 1);
1250 gtk_adjustment_set_page_size(adjustmentv
, nPage
);
1251 gtk_adjustment_set_page_increment(adjustmentv
, pageScroll
);
1252 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv
));
1256 if (GTK_ADJUSTMENT(adjustmentv
)->upper
!= (nMax
+ 1) ||
1257 GTK_ADJUSTMENT(adjustmentv
)->page_size
!= nPage
||
1258 GTK_ADJUSTMENT(adjustmentv
)->page_increment
!= pageScroll
) {
1259 GTK_ADJUSTMENT(adjustmentv
)->upper
= nMax
+ 1;
1260 GTK_ADJUSTMENT(adjustmentv
)->page_size
= nPage
;
1261 GTK_ADJUSTMENT(adjustmentv
)->page_increment
= pageScroll
;
1262 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv
));
1267 PRectangle rcText
= GetTextRectangle();
1268 int horizEndPreferred
= scrollWidth
;
1269 if (horizEndPreferred
< 0)
1270 horizEndPreferred
= 0;
1271 unsigned int pageWidth
= rcText
.Width();
1272 unsigned int pageIncrement
= pageWidth
/ 3;
1273 unsigned int charWidth
= vs
.styles
[STYLE_DEFAULT
].aveCharWidth
;
1274 #if GTK_CHECK_VERSION(3,0,0)
1275 if (gtk_adjustment_get_upper(adjustmenth
) != horizEndPreferred
||
1276 gtk_adjustment_get_page_size(adjustmenth
) != pageWidth
||
1277 gtk_adjustment_get_page_increment(adjustmenth
) != pageIncrement
||
1278 gtk_adjustment_get_step_increment(adjustmenth
) != charWidth
) {
1279 gtk_adjustment_set_upper(adjustmenth
, horizEndPreferred
);
1280 gtk_adjustment_set_page_size(adjustmenth
, pageWidth
);
1281 gtk_adjustment_set_page_increment(adjustmenth
, pageIncrement
);
1282 gtk_adjustment_set_step_increment(adjustmenth
, charWidth
);
1283 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth
));
1287 if (GTK_ADJUSTMENT(adjustmenth
)->upper
!= horizEndPreferred
||
1288 GTK_ADJUSTMENT(adjustmenth
)->page_size
!= pageWidth
||
1289 GTK_ADJUSTMENT(adjustmenth
)->page_increment
!= pageIncrement
||
1290 GTK_ADJUSTMENT(adjustmenth
)->step_increment
!= charWidth
) {
1291 GTK_ADJUSTMENT(adjustmenth
)->upper
= horizEndPreferred
;
1292 GTK_ADJUSTMENT(adjustmenth
)->step_increment
= charWidth
;
1293 GTK_ADJUSTMENT(adjustmenth
)->page_size
= pageWidth
;
1294 GTK_ADJUSTMENT(adjustmenth
)->page_increment
= pageIncrement
;
1295 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth
));
1299 if (modified
&& (paintState
== painting
)) {
1300 repaintFullWindow
= true;
1306 void ScintillaGTK::ReconfigureScrollBars() {
1307 PRectangle rc
= wMain
.GetClientPosition();
1308 Resize(rc
.Width(), rc
.Height());
1311 void ScintillaGTK::NotifyChange() {
1312 g_signal_emit(G_OBJECT(sci
), scintilla_signals
[COMMAND_SIGNAL
], 0,
1313 Platform::LongFromTwoShorts(GetCtrlID(), SCEN_CHANGE
), PWidget(wMain
));
1316 void ScintillaGTK::NotifyFocus(bool focus
) {
1317 g_signal_emit(G_OBJECT(sci
), scintilla_signals
[COMMAND_SIGNAL
], 0,
1318 Platform::LongFromTwoShorts
1319 (GetCtrlID(), focus
? SCEN_SETFOCUS
: SCEN_KILLFOCUS
), PWidget(wMain
));
1320 Editor::NotifyFocus(focus
);
1323 void ScintillaGTK::NotifyParent(SCNotification scn
) {
1324 scn
.nmhdr
.hwndFrom
= PWidget(wMain
);
1325 scn
.nmhdr
.idFrom
= GetCtrlID();
1326 g_signal_emit(G_OBJECT(sci
), scintilla_signals
[NOTIFY_SIGNAL
], 0,
1330 void ScintillaGTK::NotifyKey(int key
, int modifiers
) {
1331 SCNotification scn
= {};
1332 scn
.nmhdr
.code
= SCN_KEY
;
1334 scn
.modifiers
= modifiers
;
1339 void ScintillaGTK::NotifyURIDropped(const char *list
) {
1340 SCNotification scn
= {};
1341 scn
.nmhdr
.code
= SCN_URIDROPPED
;
1347 const char *CharacterSetID(int characterSet
);
1349 const char *ScintillaGTK::CharacterSetID() const {
1350 return ::CharacterSetID(vs
.styles
[STYLE_DEFAULT
].characterSet
);
1353 class CaseFolderDBCS
: public CaseFolderTable
{
1354 const char *charSet
;
1356 explicit CaseFolderDBCS(const char *charSet_
) : charSet(charSet_
) {
1359 virtual size_t Fold(char *folded
, size_t sizeFolded
, const char *mixed
, size_t lenMixed
) {
1360 if ((lenMixed
== 1) && (sizeFolded
> 0)) {
1361 folded
[0] = mapping
[static_cast<unsigned char>(mixed
[0])];
1363 } else if (*charSet
) {
1364 std::string sUTF8
= ConvertText(mixed
, lenMixed
,
1365 "UTF-8", charSet
, false);
1366 if (!sUTF8
.empty()) {
1367 gchar
*mapped
= g_utf8_casefold(sUTF8
.c_str(), sUTF8
.length());
1368 size_t lenMapped
= strlen(mapped
);
1369 if (lenMapped
< sizeFolded
) {
1370 memcpy(folded
, mapped
, lenMapped
);
1379 // Something failed so return a single NUL byte
1385 CaseFolder
*ScintillaGTK::CaseFolderForEncoding() {
1386 if (pdoc
->dbcsCodePage
== SC_CP_UTF8
) {
1387 return new CaseFolderUnicode();
1389 const char *charSetBuffer
= CharacterSetID();
1390 if (charSetBuffer
) {
1391 if (pdoc
->dbcsCodePage
== 0) {
1392 CaseFolderTable
*pcf
= new CaseFolderTable();
1393 pcf
->StandardASCII();
1394 // Only for single byte encodings
1395 for (int i
=0x80; i
<0x100; i
++) {
1396 char sCharacter
[2] = "A";
1398 // Silent as some bytes have no assigned character
1399 std::string sUTF8
= ConvertText(sCharacter
, 1,
1400 "UTF-8", charSetBuffer
, false, true);
1401 if (!sUTF8
.empty()) {
1402 gchar
*mapped
= g_utf8_casefold(sUTF8
.c_str(), sUTF8
.length());
1404 std::string mappedBack
= ConvertText(mapped
, strlen(mapped
),
1405 charSetBuffer
, "UTF-8", false, true);
1406 if ((mappedBack
.length() == 1) && (mappedBack
[0] != sCharacter
[0])) {
1407 pcf
->SetTranslation(sCharacter
[0], mappedBack
[0]);
1415 return new CaseFolderDBCS(charSetBuffer
);
1425 gchar
*mapped
; // Must be freed with g_free
1426 CaseMapper(const std::string
&sUTF8
, bool toUpperCase
) {
1428 mapped
= g_utf8_strup(sUTF8
.c_str(), sUTF8
.length());
1430 mapped
= g_utf8_strdown(sUTF8
.c_str(), sUTF8
.length());
1440 std::string
ScintillaGTK::CaseMapString(const std::string
&s
, int caseMapping
) {
1441 if ((s
.size() == 0) || (caseMapping
== cmSame
))
1444 if (IsUnicodeMode()) {
1445 std::string
retMapped(s
.length() * maxExpansionCaseConversion
, 0);
1446 size_t lenMapped
= CaseConvertString(&retMapped
[0], retMapped
.length(), s
.c_str(), s
.length(),
1447 (caseMapping
== cmUpper
) ? CaseConversionUpper
: CaseConversionLower
);
1448 retMapped
.resize(lenMapped
);
1452 const char *charSetBuffer
= CharacterSetID();
1454 if (!*charSetBuffer
) {
1455 CaseMapper
mapper(s
, caseMapping
== cmUpper
);
1456 return std::string(mapper
.mapped
, strlen(mapper
.mapped
));
1458 // Change text to UTF-8
1459 std::string sUTF8
= ConvertText(s
.c_str(), s
.length(),
1460 "UTF-8", charSetBuffer
, false);
1461 CaseMapper
mapper(sUTF8
, caseMapping
== cmUpper
);
1462 return ConvertText(mapper
.mapped
, strlen(mapper
.mapped
), charSetBuffer
, "UTF-8", false);
1466 int ScintillaGTK::KeyDefault(int key
, int modifiers
) {
1467 // Pass up to container in case it is an accelerator
1468 NotifyKey(key
, modifiers
);
1472 void ScintillaGTK::CopyToClipboard(const SelectionText
&selectedText
) {
1473 SelectionText
*clipText
= new SelectionText();
1474 clipText
->Copy(selectedText
);
1475 StoreOnClipboard(clipText
);
1478 void ScintillaGTK::Copy() {
1480 SelectionText
*clipText
= new SelectionText();
1481 CopySelectionRange(clipText
);
1482 StoreOnClipboard(clipText
);
1484 if (sel
.IsRectangular()) {
1485 ::OpenClipboard(NULL
);
1486 ::SetClipboardData(cfColumnSelect
, 0);
1493 void ScintillaGTK::ClipboardReceived(GtkClipboard
*clipboard
, GtkSelectionData
*selection_data
, gpointer data
) {
1494 ScintillaGTK
*sciThis
= static_cast<ScintillaGTK
*>(data
);
1495 sciThis
->ReceivedSelection(selection_data
);
1498 void ScintillaGTK::Paste() {
1499 atomSought
= atomUTF8
;
1500 GtkClipboard
*clipBoard
=
1501 gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain
)), atomClipboard
);
1502 if (clipBoard
== NULL
)
1504 gtk_clipboard_request_contents(clipBoard
, atomSought
, ClipboardReceived
, this);
1507 void ScintillaGTK::CreateCallTipWindow(PRectangle rc
) {
1508 if (!ct
.wCallTip
.Created()) {
1509 ct
.wCallTip
= gtk_window_new(GTK_WINDOW_POPUP
);
1510 ct
.wDraw
= gtk_drawing_area_new();
1511 GtkWidget
*widcdrw
= PWidget(ct
.wDraw
); // // No code inside the G_OBJECT macro
1512 gtk_container_add(GTK_CONTAINER(PWidget(ct
.wCallTip
)), widcdrw
);
1513 #if GTK_CHECK_VERSION(3,0,0)
1514 g_signal_connect(G_OBJECT(widcdrw
), "draw",
1515 G_CALLBACK(ScintillaGTK::DrawCT
), &ct
);
1517 g_signal_connect(G_OBJECT(widcdrw
), "expose_event",
1518 G_CALLBACK(ScintillaGTK::ExposeCT
), &ct
);
1520 g_signal_connect(G_OBJECT(widcdrw
), "button_press_event",
1521 G_CALLBACK(ScintillaGTK::PressCT
), static_cast<void *>(this));
1522 gtk_widget_set_events(widcdrw
,
1523 GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
);
1525 gtk_widget_set_size_request(PWidget(ct
.wDraw
), rc
.Width(), rc
.Height());
1527 if (PWindow(ct
.wCallTip
)) {
1528 gdk_window_resize(PWindow(ct
.wCallTip
), rc
.Width(), rc
.Height());
1532 void ScintillaGTK::AddToPopUp(const char *label
, int cmd
, bool enabled
) {
1533 GtkWidget
*menuItem
;
1535 menuItem
= gtk_menu_item_new_with_label(label
);
1537 menuItem
= gtk_separator_menu_item_new();
1538 gtk_menu_shell_append(GTK_MENU_SHELL(popup
.GetID()), menuItem
);
1539 g_object_set_data(G_OBJECT(menuItem
), "CmdNum", reinterpret_cast<void *>(cmd
));
1540 g_signal_connect(G_OBJECT(menuItem
),"activate", G_CALLBACK(PopUpCB
), this);
1544 gtk_widget_set_sensitive(menuItem
, enabled
);
1548 bool ScintillaGTK::OwnPrimarySelection() {
1549 return ((gdk_selection_owner_get(GDK_SELECTION_PRIMARY
)
1550 == PWindow(wMain
)) &&
1551 (PWindow(wMain
) != NULL
));
1554 void ScintillaGTK::ClaimSelection() {
1555 // X Windows has a 'primary selection' as well as the clipboard.
1556 // Whenever the user selects some text, we become the primary selection
1557 if (!sel
.Empty() && IS_WIDGET_REALIZED(GTK_WIDGET(PWidget(wMain
)))) {
1558 primarySelection
= true;
1559 gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain
)),
1560 GDK_SELECTION_PRIMARY
, GDK_CURRENT_TIME
);
1562 } else if (OwnPrimarySelection()) {
1563 primarySelection
= true;
1564 if (primary
.Empty())
1565 gtk_selection_owner_set(NULL
, GDK_SELECTION_PRIMARY
, GDK_CURRENT_TIME
);
1567 primarySelection
= false;
1572 #if GTK_CHECK_VERSION(3,0,0)
1573 static const guchar
*DataOfGSD(GtkSelectionData
*sd
) { return gtk_selection_data_get_data(sd
); }
1574 static gint
LengthOfGSD(GtkSelectionData
*sd
) { return gtk_selection_data_get_length(sd
); }
1575 static GdkAtom
TypeOfGSD(GtkSelectionData
*sd
) { return gtk_selection_data_get_data_type(sd
); }
1576 static GdkAtom
SelectionOfGSD(GtkSelectionData
*sd
) { return gtk_selection_data_get_selection(sd
); }
1578 static const guchar
*DataOfGSD(GtkSelectionData
*sd
) { return sd
->data
; }
1579 static gint
LengthOfGSD(GtkSelectionData
*sd
) { return sd
->length
; }
1580 static GdkAtom
TypeOfGSD(GtkSelectionData
*sd
) { return sd
->type
; }
1581 static GdkAtom
SelectionOfGSD(GtkSelectionData
*sd
) { return sd
->selection
; }
1584 // Detect rectangular text, convert line ends to current mode, convert from or to UTF-8
1585 void ScintillaGTK::GetGtkSelectionText(GtkSelectionData
*selectionData
, SelectionText
&selText
) {
1586 const char *data
= reinterpret_cast<const char *>(DataOfGSD(selectionData
));
1587 int len
= LengthOfGSD(selectionData
);
1588 GdkAtom selectionTypeData
= TypeOfGSD(selectionData
);
1590 // Return empty string if selection is not a string
1591 if ((selectionTypeData
!= GDK_TARGET_STRING
) && (selectionTypeData
!= atomUTF8
)) {
1596 // Check for "\n\0" ending to string indicating that selection is rectangular
1599 isRectangular
= ::IsClipboardFormatAvailable(cfColumnSelect
) != 0;
1601 isRectangular
= ((len
> 2) && (data
[len
- 1] == 0 && data
[len
- 2] == '\n'));
1603 len
--; // Forget the extra '\0'
1607 // Win32 includes an ending '\0' byte in 'len' for clipboard text from
1608 // external applications; ignore it.
1609 if ((len
> 0) && (data
[len
- 1] == '\0'))
1613 std::string
dest(data
, len
);
1614 if (selectionTypeData
== GDK_TARGET_STRING
) {
1615 if (IsUnicodeMode()) {
1616 // Unknown encoding so assume in Latin1
1617 dest
= UTF8FromLatin1(dest
.c_str(), dest
.length());
1618 selText
.Copy(dest
, SC_CP_UTF8
, 0, isRectangular
, false);
1620 // Assume buffer is in same encoding as selection
1621 selText
.Copy(dest
, pdoc
->dbcsCodePage
,
1622 vs
.styles
[STYLE_DEFAULT
].characterSet
, isRectangular
, false);
1625 const char *charSetBuffer
= CharacterSetID();
1626 if (!IsUnicodeMode() && *charSetBuffer
) {
1627 // Convert to locale
1628 dest
= ConvertText(dest
.c_str(), dest
.length(), charSetBuffer
, "UTF-8", true);
1629 selText
.Copy(dest
, pdoc
->dbcsCodePage
,
1630 vs
.styles
[STYLE_DEFAULT
].characterSet
, isRectangular
, false);
1632 selText
.Copy(dest
, SC_CP_UTF8
, 0, isRectangular
, false);
1637 void ScintillaGTK::ReceivedSelection(GtkSelectionData
*selection_data
) {
1639 if ((SelectionOfGSD(selection_data
) == atomClipboard
) ||
1640 (SelectionOfGSD(selection_data
) == GDK_SELECTION_PRIMARY
)) {
1641 if ((atomSought
== atomUTF8
) && (LengthOfGSD(selection_data
) <= 0)) {
1642 atomSought
= atomString
;
1643 gtk_selection_convert(GTK_WIDGET(PWidget(wMain
)),
1644 SelectionOfGSD(selection_data
), atomSought
, GDK_CURRENT_TIME
);
1645 } else if ((LengthOfGSD(selection_data
) > 0) &&
1646 ((TypeOfGSD(selection_data
) == GDK_TARGET_STRING
) || (TypeOfGSD(selection_data
) == atomUTF8
))) {
1647 SelectionText selText
;
1648 GetGtkSelectionText(selection_data
, selText
);
1651 if (SelectionOfGSD(selection_data
) != GDK_SELECTION_PRIMARY
) {
1652 ClearSelection(multiPasteMode
== SC_MULTIPASTE_EACH
);
1655 InsertPasteShape(selText
.Data(), selText
.Length(),
1656 selText
.rectangular
? pasteRectangular
: pasteStream
);
1657 EnsureCaretVisible();
1660 // else fprintf(stderr, "Target non string %d %d\n", (int)(selection_data->type),
1661 // (int)(atomUTF8));
1664 errorStatus
= SC_STATUS_FAILURE
;
1668 void ScintillaGTK::ReceivedDrop(GtkSelectionData
*selection_data
) {
1669 dragWasDropped
= true;
1670 if (TypeOfGSD(selection_data
) == atomUriList
|| TypeOfGSD(selection_data
) == atomDROPFILES_DND
) {
1671 const char *data
= reinterpret_cast<const char *>(DataOfGSD(selection_data
));
1672 std::vector
<char> drop(data
, data
+ LengthOfGSD(selection_data
));
1673 drop
.push_back('\0');
1674 NotifyURIDropped(&drop
[0]);
1675 } else if ((TypeOfGSD(selection_data
) == GDK_TARGET_STRING
) || (TypeOfGSD(selection_data
) == atomUTF8
)) {
1676 if (LengthOfGSD(selection_data
) > 0) {
1677 SelectionText selText
;
1678 GetGtkSelectionText(selection_data
, selText
);
1679 DropAt(posDrop
, selText
.Data(), selText
.Length(), false, selText
.rectangular
);
1681 } else if (LengthOfGSD(selection_data
) > 0) {
1682 //~ fprintf(stderr, "ReceivedDrop other %p\n", static_cast<void *>(selection_data->type));
1689 void ScintillaGTK::GetSelection(GtkSelectionData
*selection_data
, guint info
, SelectionText
*text
) {
1691 // GDK on Win32 expands any \n into \r\n, so make a copy of
1692 // the clip text now with newlines converted to \n. Use { } to hide symbols
1694 SelectionText
*newline_normalized
= NULL
;
1696 std::string tmpstr
= Document::TransformLineEnds(text
->Data(), text
->Length(), SC_EOL_LF
);
1697 newline_normalized
= new SelectionText();
1698 newline_normalized
->Copy(tmpstr
, SC_CP_UTF8
, 0, text
->rectangular
, false);
1699 text
= newline_normalized
;
1703 // Convert text to utf8 if it isn't already
1704 SelectionText
*converted
= 0;
1705 if ((text
->codePage
!= SC_CP_UTF8
) && (info
== TARGET_UTF8_STRING
)) {
1706 const char *charSet
= ::CharacterSetID(text
->characterSet
);
1708 std::string tmputf
= ConvertText(text
->Data(), text
->Length(), "UTF-8", charSet
, false);
1709 converted
= new SelectionText();
1710 converted
->Copy(tmputf
, SC_CP_UTF8
, 0, text
->rectangular
, false);
1715 // Here is a somewhat evil kludge.
1716 // As I can not work out how to store data on the clipboard in multiple formats
1717 // and need some way to mark the clipping as being stream or rectangular,
1718 // the terminating \0 is included in the length for rectangular clippings.
1719 // All other tested aplications behave benignly by ignoring the \0.
1720 // The #if is here because on Windows cfColumnSelect clip entry is used
1721 // instead as standard indicator of rectangularness (so no need to kludge)
1722 const char *textData
= text
->Data();
1723 int len
= text
->Length();
1724 #if PLAT_GTK_WIN32 == 0
1725 if (text
->rectangular
)
1729 if (info
== TARGET_UTF8_STRING
) {
1730 gtk_selection_data_set_text(selection_data
, textData
, len
);
1732 gtk_selection_data_set(selection_data
,
1733 static_cast<GdkAtom
>(GDK_SELECTION_TYPE_STRING
),
1734 8, reinterpret_cast<const unsigned char *>(textData
), len
);
1739 delete newline_normalized
;
1743 void ScintillaGTK::StoreOnClipboard(SelectionText
*clipText
) {
1744 GtkClipboard
*clipBoard
=
1745 gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain
)), atomClipboard
);
1746 if (clipBoard
== NULL
) // Occurs if widget isn't in a toplevel
1749 if (gtk_clipboard_set_with_data(clipBoard
, clipboardCopyTargets
, nClipboardCopyTargets
,
1750 ClipboardGetSelection
, ClipboardClearSelection
, clipText
)) {
1751 gtk_clipboard_set_can_store(clipBoard
, clipboardCopyTargets
, nClipboardCopyTargets
);
1755 void ScintillaGTK::ClipboardGetSelection(GtkClipboard
*, GtkSelectionData
*selection_data
, guint info
, void *data
) {
1756 GetSelection(selection_data
, info
, static_cast<SelectionText
*>(data
));
1759 void ScintillaGTK::ClipboardClearSelection(GtkClipboard
*, void *data
) {
1760 SelectionText
*obj
= static_cast<SelectionText
*>(data
);
1764 void ScintillaGTK::UnclaimSelection(GdkEventSelection
*selection_event
) {
1766 //Platform::DebugPrintf("UnclaimSelection\n");
1767 if (selection_event
->selection
== GDK_SELECTION_PRIMARY
) {
1768 //Platform::DebugPrintf("UnclaimPrimarySelection\n");
1769 if (!OwnPrimarySelection()) {
1771 primarySelection
= false;
1776 errorStatus
= SC_STATUS_FAILURE
;
1780 void ScintillaGTK::Resize(int width
, int height
) {
1781 //Platform::DebugPrintf("Resize %d %d\n", width, height);
1782 //printf("Resize %d %d\n", width, height);
1784 // Not always needed, but some themes can have different sizes of scrollbars
1785 #if GTK_CHECK_VERSION(3,0,0)
1786 GtkRequisition requisition
;
1787 gtk_widget_get_preferred_size(PWidget(scrollbarv
), NULL
, &requisition
);
1788 verticalScrollBarWidth
= requisition
.width
;
1789 gtk_widget_get_preferred_size(PWidget(scrollbarh
), NULL
, &requisition
);
1790 horizontalScrollBarHeight
= requisition
.height
;
1792 verticalScrollBarWidth
= GTK_WIDGET(PWidget(scrollbarv
))->requisition
.width
;
1793 horizontalScrollBarHeight
= GTK_WIDGET(PWidget(scrollbarh
))->requisition
.height
;
1796 // These allocations should never produce negative sizes as they would wrap around to huge
1797 // unsigned numbers inside GTK+ causing warnings.
1798 bool showSBHorizontal
= horizontalScrollBarVisible
&& !Wrapping();
1800 GtkAllocation alloc
;
1801 if (showSBHorizontal
) {
1802 gtk_widget_show(GTK_WIDGET(PWidget(scrollbarh
)));
1804 alloc
.y
= height
- horizontalScrollBarHeight
;
1805 alloc
.width
= Platform::Maximum(1, width
- verticalScrollBarWidth
);
1806 alloc
.height
= horizontalScrollBarHeight
;
1807 gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarh
)), &alloc
);
1809 gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarh
)));
1810 horizontalScrollBarHeight
= 0; // in case horizontalScrollBarVisible is true.
1813 if (verticalScrollBarVisible
) {
1814 gtk_widget_show(GTK_WIDGET(PWidget(scrollbarv
)));
1815 alloc
.x
= width
- verticalScrollBarWidth
;
1817 alloc
.width
= verticalScrollBarWidth
;
1818 alloc
.height
= Platform::Maximum(1, height
- horizontalScrollBarHeight
);
1819 gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarv
)), &alloc
);
1821 gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarv
)));
1822 verticalScrollBarWidth
= 0;
1824 if (IS_WIDGET_MAPPED(PWidget(wMain
))) {
1830 alloc
.width
= Platform::Maximum(1, width
- verticalScrollBarWidth
);
1831 alloc
.height
= Platform::Maximum(1, height
- horizontalScrollBarHeight
);
1832 gtk_widget_size_allocate(GTK_WIDGET(PWidget(wText
)), &alloc
);
1835 static void SetAdjustmentValue(GtkAdjustment
*object
, int value
) {
1836 GtkAdjustment
*adjustment
= GTK_ADJUSTMENT(object
);
1837 #if GTK_CHECK_VERSION(3,0,0)
1838 int maxValue
= static_cast<int>(
1839 gtk_adjustment_get_upper(adjustment
) - gtk_adjustment_get_page_size(adjustment
));
1841 int maxValue
= static_cast<int>(
1842 adjustment
->upper
- adjustment
->page_size
);
1845 if (value
> maxValue
)
1849 gtk_adjustment_set_value(adjustment
, value
);
1852 static int modifierTranslated(int sciModifier
) {
1853 switch (sciModifier
) {
1855 return GDK_SHIFT_MASK
;
1857 return GDK_CONTROL_MASK
;
1859 return GDK_MOD1_MASK
;
1861 return GDK_MOD4_MASK
;
1867 gint
ScintillaGTK::PressThis(GdkEventButton
*event
) {
1869 //Platform::DebugPrintf("Press %x time=%d state = %x button = %x\n",this,event->time, event->state, event->button);
1870 // Do not use GTK+ double click events as Scintilla has its own double click detection
1871 if (event
->type
!= GDK_BUTTON_PRESS
)
1875 gdk_event_free(reinterpret_cast<GdkEvent
*>(evbtn
));
1878 evbtn
= reinterpret_cast<GdkEventButton
*>(gdk_event_copy(reinterpret_cast<GdkEvent
*>(event
)));
1880 pt
.x
= int(event
->x
);
1881 pt
.y
= int(event
->y
);
1882 PRectangle rcClient
= GetClientRectangle();
1883 //Platform::DebugPrintf("Press %0d,%0d in %0d,%0d %0d,%0d\n",
1884 // pt.x, pt.y, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1885 if ((pt
.x
> rcClient
.right
) || (pt
.y
> rcClient
.bottom
)) {
1886 Platform::DebugPrintf("Bad location\n");
1890 bool shift
= (event
->state
& GDK_SHIFT_MASK
) != 0;
1891 bool ctrl
= (event
->state
& GDK_CONTROL_MASK
) != 0;
1892 // On X, instead of sending literal modifiers use the user specified
1893 // modifier, defaulting to control instead of alt.
1894 // This is because most X window managers grab alt + click for moving
1895 bool alt
= (event
->state
& modifierTranslated(rectangularSelectionModifier
)) != 0;
1897 gtk_widget_grab_focus(PWidget(wMain
));
1898 if (event
->button
== 1) {
1901 // GDK reports the Command modifer key as GDK_MOD2_MASK for button events,
1902 // not GDK_META_MASK like in key events.
1903 ctrl
= (event
->state
& GDK_MOD2_MASK
) != 0;
1907 ButtonDownWithModifiers(pt
, event
->time
, ModifierFlags(shift
, ctrl
, alt
, meta
));
1908 } else if (event
->button
== 2) {
1909 // Grab the primary selection if it exists
1910 SelectionPosition pos
= SPositionFromLocation(pt
, false, false, UserVirtualSpace());
1911 if (OwnPrimarySelection() && primary
.Empty())
1912 CopySelectionRange(&primary
);
1915 SetSelection(pos
, pos
);
1916 atomSought
= atomUTF8
;
1917 gtk_selection_convert(GTK_WIDGET(PWidget(wMain
)), GDK_SELECTION_PRIMARY
,
1918 atomSought
, event
->time
);
1919 } else if (event
->button
== 3) {
1920 if (!PointInSelection(pt
))
1921 SetEmptySelection(PositionFromLocation(pt
));
1922 if (displayPopupMenu
) {
1924 // Convert to screen
1927 gdk_window_get_origin(PWindow(wMain
), &ox
, &oy
);
1928 ContextMenu(Point(pt
.x
+ ox
, pt
.y
+ oy
));
1932 } else if (event
->button
== 4) {
1933 // Wheel scrolling up (only GTK 1.x does it this way)
1935 SetAdjustmentValue(adjustmenth
, xOffset
- 6);
1937 SetAdjustmentValue(adjustmentv
, topLine
- 3);
1938 } else if (event
->button
== 5) {
1939 // Wheel scrolling down (only GTK 1.x does it this way)
1941 SetAdjustmentValue(adjustmenth
, xOffset
+ 6);
1943 SetAdjustmentValue(adjustmentv
, topLine
+ 3);
1946 errorStatus
= SC_STATUS_FAILURE
;
1951 gint
ScintillaGTK::Press(GtkWidget
*widget
, GdkEventButton
*event
) {
1952 if (event
->window
!= WindowFromWidget(widget
))
1954 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1955 return sciThis
->PressThis(event
);
1958 gint
ScintillaGTK::MouseRelease(GtkWidget
*widget
, GdkEventButton
*event
) {
1959 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1961 //Platform::DebugPrintf("Release %x %d %d\n",sciThis,event->time,event->state);
1962 if (!sciThis
->HaveMouseCapture())
1964 if (event
->button
== 1) {
1966 pt
.x
= int(event
->x
);
1967 pt
.y
= int(event
->y
);
1968 //Platform::DebugPrintf("Up %x %x %d %d %d\n",
1969 // sciThis,event->window,event->time, pt.x, pt.y);
1970 if (event
->window
!= PWindow(sciThis
->wMain
))
1971 // If mouse released on scroll bar then the position is relative to the
1972 // scrollbar, not the drawing window so just repeat the most recent point.
1973 pt
= sciThis
->ptMouseLast
;
1974 sciThis
->ButtonUp(pt
, event
->time
, (event
->state
& GDK_CONTROL_MASK
) != 0);
1977 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
1982 // win32gtk and GTK >= 2 use SCROLL_* events instead of passing the
1983 // button4/5/6/7 events to the GTK app
1984 gint
ScintillaGTK::ScrollEvent(GtkWidget
*widget
, GdkEventScroll
*event
) {
1985 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1988 if (widget
== NULL
|| event
== NULL
)
1991 // Compute amount and direction to scroll (even tho on win32 there is
1992 // intensity of scrolling info in the native message, gtk doesn't
1993 // support this so we simulate similarly adaptive scrolling)
1994 // Note that this is disabled on OS X (Darwin) with the X11 backend
1995 // where the X11 server already has an adaptive scrolling algorithm
1996 // that fights with this one
1998 #if defined(__APPLE__) && !defined(GDK_WINDOWING_QUARTZ)
1999 cLineScroll
= sciThis
->linesPerScroll
;
2000 if (cLineScroll
== 0)
2002 sciThis
->wheelMouseIntensity
= cLineScroll
;
2004 int timeDelta
= 1000000;
2006 g_get_current_time(&curTime
);
2007 if (curTime
.tv_sec
== sciThis
->lastWheelMouseTime
.tv_sec
)
2008 timeDelta
= curTime
.tv_usec
- sciThis
->lastWheelMouseTime
.tv_usec
;
2009 else if (curTime
.tv_sec
== sciThis
->lastWheelMouseTime
.tv_sec
+ 1)
2010 timeDelta
= 1000000 + (curTime
.tv_usec
- sciThis
->lastWheelMouseTime
.tv_usec
);
2011 if ((event
->direction
== sciThis
->lastWheelMouseDirection
) && (timeDelta
< 250000)) {
2012 if (sciThis
->wheelMouseIntensity
< 12)
2013 sciThis
->wheelMouseIntensity
++;
2014 cLineScroll
= sciThis
->wheelMouseIntensity
;
2016 cLineScroll
= sciThis
->linesPerScroll
;
2017 if (cLineScroll
== 0)
2019 sciThis
->wheelMouseIntensity
= cLineScroll
;
2022 if (event
->direction
== GDK_SCROLL_UP
|| event
->direction
== GDK_SCROLL_LEFT
) {
2025 g_get_current_time(&sciThis
->lastWheelMouseTime
);
2026 sciThis
->lastWheelMouseDirection
= event
->direction
;
2028 // Note: Unpatched versions of win32gtk don't set the 'state' value so
2029 // only regular scrolling is supported there. Also, unpatched win32gtk
2030 // issues spurious button 2 mouse events during wheeling, which can cause
2031 // problems (a patch for both was submitted by archaeopteryx.com on 13Jun2001)
2033 // Data zoom not supported
2034 if (event
->state
& GDK_SHIFT_MASK
) {
2038 #if GTK_CHECK_VERSION(3,4,0)
2039 // Smooth scrolling not supported
2040 if (event
->direction
== GDK_SCROLL_SMOOTH
) {
2045 // Horizontal scrolling
2046 if (event
->direction
== GDK_SCROLL_LEFT
|| event
->direction
== GDK_SCROLL_RIGHT
) {
2047 sciThis
->HorizontalScrollTo(sciThis
->xOffset
+ cLineScroll
);
2049 // Text font size zoom
2050 } else if (event
->state
& GDK_CONTROL_MASK
) {
2051 if (cLineScroll
< 0) {
2052 sciThis
->KeyCommand(SCI_ZOOMIN
);
2054 sciThis
->KeyCommand(SCI_ZOOMOUT
);
2057 // Regular scrolling
2059 sciThis
->ScrollTo(sciThis
->topLine
+ cLineScroll
);
2063 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2068 gint
ScintillaGTK::Motion(GtkWidget
*widget
, GdkEventMotion
*event
) {
2069 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2071 //Platform::DebugPrintf("Motion %x %d\n",sciThis,event->time);
2072 if (event
->window
!= WindowFromWidget(widget
))
2076 GdkModifierType state
;
2077 if (event
->is_hint
) {
2078 #if GTK_CHECK_VERSION(3,0,0)
2079 gdk_window_get_device_position(event
->window
,
2080 event
->device
, &x
, &y
, &state
);
2082 gdk_window_get_pointer(event
->window
, &x
, &y
, &state
);
2085 x
= static_cast<int>(event
->x
);
2086 y
= static_cast<int>(event
->y
);
2087 state
= static_cast<GdkModifierType
>(event
->state
);
2089 //Platform::DebugPrintf("Move %x %x %d %c %d %d\n",
2090 // sciThis,event->window,event->time,event->is_hint? 'h' :'.', x, y);
2092 int modifiers
= ((event
->state
& GDK_SHIFT_MASK
) != 0 ? SCI_SHIFT
: 0) |
2093 ((event
->state
& GDK_CONTROL_MASK
) != 0 ? SCI_CTRL
: 0) |
2094 ((event
->state
& modifierTranslated(sciThis
->rectangularSelectionModifier
)) != 0 ? SCI_ALT
: 0);
2095 sciThis
->ButtonMoveWithModifiers(pt
, modifiers
);
2097 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2102 // Map the keypad keys to their equivalent functions
2103 static int KeyTranslate(int keyIn
) {
2105 #if GTK_CHECK_VERSION(3,0,0)
2106 case GDK_KEY_ISO_Left_Tab
:
2108 case GDK_KEY_KP_Down
:
2112 case GDK_KEY_KP_Left
:
2114 case GDK_KEY_KP_Right
:
2116 case GDK_KEY_KP_Home
:
2118 case GDK_KEY_KP_End
:
2120 case GDK_KEY_KP_Page_Up
:
2122 case GDK_KEY_KP_Page_Down
:
2124 case GDK_KEY_KP_Delete
:
2126 case GDK_KEY_KP_Insert
:
2128 case GDK_KEY_KP_Enter
:
2143 case GDK_KEY_Page_Up
:
2145 case GDK_KEY_Page_Down
:
2147 case GDK_KEY_Delete
:
2149 case GDK_KEY_Insert
:
2151 case GDK_KEY_Escape
:
2153 case GDK_KEY_BackSpace
:
2157 case GDK_KEY_Return
:
2159 case GDK_KEY_KP_Add
:
2161 case GDK_KEY_KP_Subtract
:
2162 return SCK_SUBTRACT
;
2163 case GDK_KEY_KP_Divide
:
2165 case GDK_KEY_Super_L
:
2167 case GDK_KEY_Super_R
:
2174 case GDK_ISO_Left_Tab
:
2188 case GDK_KP_Page_Up
:
2190 case GDK_KP_Page_Down
:
2229 case GDK_KP_Subtract
:
2230 return SCK_SUBTRACT
;
2245 gboolean
ScintillaGTK::KeyThis(GdkEventKey
*event
) {
2247 //fprintf(stderr, "SC-key: %d %x [%s]\n",
2248 // event->keyval, event->state, (event->length > 0) ? event->string : "empty");
2249 if (gtk_im_context_filter_keypress(im_context
, event
)) {
2252 if (!event
->keyval
) {
2256 bool shift
= (event
->state
& GDK_SHIFT_MASK
) != 0;
2257 bool ctrl
= (event
->state
& GDK_CONTROL_MASK
) != 0;
2258 bool alt
= (event
->state
& GDK_MOD1_MASK
) != 0;
2259 guint key
= event
->keyval
;
2260 if ((ctrl
|| alt
) && (key
< 128))
2262 #if GTK_CHECK_VERSION(3,0,0)
2263 else if (!ctrl
&& (key
>= GDK_KEY_KP_Multiply
&& key
<= GDK_KEY_KP_9
))
2265 else if (!ctrl
&& (key
>= GDK_KP_Multiply
&& key
<= GDK_KP_9
))
2268 // Hack for keys over 256 and below command keys but makes Hungarian work.
2269 // This will have to change for Unicode
2270 else if (key
>= 0xFE00)
2271 key
= KeyTranslate(key
);
2273 bool consumed
= false;
2274 #if !(PLAT_GTK_MACOSX)
2275 bool added
= KeyDown(key
, shift
, ctrl
, alt
, &consumed
) != 0;
2278 ctrl
= (event
->state
& GDK_META_MASK
) != 0;
2279 bool added
= KeyDownWithModifiers(key
, (shift
? SCI_SHIFT
: 0) |
2280 (ctrl
? SCI_CTRL
: 0) |
2281 (alt
? SCI_ALT
: 0) |
2282 (meta
? SCI_META
: 0), &consumed
) != 0;
2286 //fprintf(stderr, "SK-key: %d %x %x\n",event->keyval, event->state, consumed);
2287 if (event
->keyval
== 0xffffff && event
->length
> 0) {
2289 const int lengthInserted
= pdoc
->InsertString(CurrentPosition(), event
->string
, strlen(event
->string
));
2290 if (lengthInserted
> 0) {
2291 MovePositionTo(CurrentPosition() + lengthInserted
);
2296 errorStatus
= SC_STATUS_FAILURE
;
2301 gboolean
ScintillaGTK::KeyPress(GtkWidget
*widget
, GdkEventKey
*event
) {
2302 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2303 return sciThis
->KeyThis(event
);
2306 gboolean
ScintillaGTK::KeyRelease(GtkWidget
*widget
, GdkEventKey
*event
) {
2307 //Platform::DebugPrintf("SC-keyrel: %d %x %3s\n",event->keyval, event->state, event->string);
2308 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2309 if (gtk_im_context_filter_keypress(sciThis
->im_context
, event
)) {
2315 #if GTK_CHECK_VERSION(3,0,0)
2317 gboolean
ScintillaGTK::DrawPreeditThis(GtkWidget
*widget
, cairo_t
*cr
) {
2319 PreEditString
pes(im_context
);
2320 PangoLayout
*layout
= gtk_widget_create_pango_layout(PWidget(wText
), pes
.str
);
2321 pango_layout_set_attributes(layout
, pes
.attrs
);
2323 cairo_move_to(cr
, 0, 0);
2324 pango_cairo_show_layout(cr
, layout
);
2326 g_object_unref(layout
);
2328 errorStatus
= SC_STATUS_FAILURE
;
2333 gboolean
ScintillaGTK::DrawPreedit(GtkWidget
*widget
, cairo_t
*cr
, ScintillaGTK
*sciThis
) {
2334 return sciThis
->DrawPreeditThis(widget
, cr
);
2339 gboolean
ScintillaGTK::ExposePreeditThis(GtkWidget
*widget
, GdkEventExpose
*ose
) {
2341 PreEditString
pes(im_context
);
2342 PangoLayout
*layout
= gtk_widget_create_pango_layout(PWidget(wText
), pes
.str
);
2343 pango_layout_set_attributes(layout
, pes
.attrs
);
2345 cairo_t
*context
= gdk_cairo_create(reinterpret_cast<GdkDrawable
*>(WindowFromWidget(widget
)));
2346 cairo_move_to(context
, 0, 0);
2347 pango_cairo_show_layout(context
, layout
);
2348 cairo_destroy(context
);
2349 g_object_unref(layout
);
2351 errorStatus
= SC_STATUS_FAILURE
;
2356 gboolean
ScintillaGTK::ExposePreedit(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
) {
2357 return sciThis
->ExposePreeditThis(widget
, ose
);
2362 bool ScintillaGTK::KoreanIME() {
2363 PreEditString
pes(im_context
);
2364 if (pes
.pscript
!= PANGO_SCRIPT_COMMON
)
2365 lastNonCommonScript
= pes
.pscript
;
2366 return lastNonCommonScript
== PANGO_SCRIPT_HANGUL
;
2369 void ScintillaGTK::MoveImeCarets(int pos
) {
2370 // Move carets relatively by bytes
2371 for (size_t r
=0; r
<sel
.Count(); r
++) {
2372 int positionInsert
= sel
.Range(r
).Start().Position();
2373 sel
.Range(r
).caret
.SetPosition(positionInsert
+ pos
);
2374 sel
.Range(r
).anchor
.SetPosition(positionInsert
+ pos
);
2378 void ScintillaGTK::DrawImeIndicator(int indicator
, int len
) {
2379 // Emulate the visual style of IME characters with indicators.
2380 // Draw an indicator on the character before caret by the character bytes of len
2381 // so it should be called after addCharUTF().
2382 // It does not affect caret positions.
2383 if (indicator
< 8 || indicator
> INDIC_MAX
) {
2386 pdoc
->decorations
.SetCurrentIndicator(indicator
);
2387 for (size_t r
=0; r
<sel
.Count(); r
++) {
2388 int positionInsert
= sel
.Range(r
).Start().Position();
2389 pdoc
->DecorationFillRange(positionInsert
- len
, 1, len
);
2393 void ScintillaGTK::GetImeUnderlines(PangoAttrList
*attrs
, bool *normalInput
) {
2394 // Whether single underlines attribute is or not
2395 // attr position is counted by the number of UTF-8 bytes
2396 PangoAttrIterator
*iterunderline
= pango_attr_list_get_iterator(attrs
);
2397 if (iterunderline
) {
2399 PangoAttribute
*attrunderline
= pango_attr_iterator_get(iterunderline
, PANGO_ATTR_UNDERLINE
);
2400 if (attrunderline
) {
2401 glong start
= attrunderline
->start_index
;
2402 glong end
= attrunderline
->end_index
;
2403 PangoUnderline uline
= (PangoUnderline
)((PangoAttrInt
*)attrunderline
)->value
;
2404 for (glong i
=start
; i
< end
; ++i
) {
2406 case PANGO_UNDERLINE_NONE
:
2407 normalInput
[i
] = false;
2409 case PANGO_UNDERLINE_SINGLE
: // normal input
2410 normalInput
[i
] = true;
2412 case PANGO_UNDERLINE_DOUBLE
:
2413 case PANGO_UNDERLINE_LOW
:
2414 case PANGO_UNDERLINE_ERROR
:
2419 } while (pango_attr_iterator_next(iterunderline
));
2420 pango_attr_iterator_destroy(iterunderline
);
2424 void ScintillaGTK::GetImeBackgrounds(PangoAttrList
*attrs
, bool *targetInput
) {
2425 // Whether background color attribue is or not
2426 // attr position is measured in UTF-8 bytes
2427 PangoAttrIterator
*itercolor
= pango_attr_list_get_iterator(attrs
);
2430 PangoAttribute
*backcolor
= pango_attr_iterator_get(itercolor
, PANGO_ATTR_BACKGROUND
);
2432 glong start
= backcolor
->start_index
;
2433 glong end
= backcolor
->end_index
;
2434 for (glong i
=start
; i
< end
; ++i
) {
2435 targetInput
[i
] = true; // target converted
2438 } while (pango_attr_iterator_next(itercolor
));
2439 pango_attr_iterator_destroy(itercolor
);
2443 void ScintillaGTK::SetCandidateWindowPos() {
2444 // Composition box accompanies candidate box.
2445 Point pt
= PointMainCaret();
2446 GdkRectangle imeBox
= {0}; // No need to set width
2447 imeBox
.x
= pt
.x
; // Only need positiion
2448 imeBox
.y
= pt
.y
+ vs
.lineHeight
; // underneath the first charater
2449 gtk_im_context_set_cursor_location(im_context
, &imeBox
);
2452 void ScintillaGTK::CommitThis(char *commitStr
) {
2454 //~ fprintf(stderr, "Commit '%s'\n", commitStr);
2455 view
.imeCaretBlockOverride
= false;
2457 if (pdoc
->TentativeActive()) {
2458 pdoc
->TentativeUndo();
2461 const char *charSetSource
= CharacterSetID();
2463 glong uniStrLen
= 0;
2464 gunichar
*uniStr
= g_utf8_to_ucs4_fast(commitStr
, strlen(commitStr
), &uniStrLen
);
2465 for (glong i
= 0; i
< uniStrLen
; i
++) {
2467 gunichar uniChar
[1] = {0};
2468 uniChar
[0] = uniStr
[i
];
2470 glong oneCharLen
= 0;
2471 gchar
*oneChar
= g_ucs4_to_utf8(uniChar
, 1, NULL
, &oneCharLen
, NULL
);
2473 if (IsUnicodeMode()) {
2476 std::string oneCharSTD
= ConvertText(oneChar
, oneCharLen
, charSetSource
, "UTF-8", true);
2477 oneCharLen
= oneCharSTD
.copy(oneChar
,oneCharSTD
.length(), 0);
2478 oneChar
[oneCharLen
] = '\0';
2481 AddCharUTF(oneChar
, oneCharLen
);
2485 ShowCaretAtCurrentPosition();
2487 errorStatus
= SC_STATUS_FAILURE
;
2491 void ScintillaGTK::Commit(GtkIMContext
*, char *str
, ScintillaGTK
*sciThis
) {
2492 sciThis
->CommitThis(str
);
2495 void ScintillaGTK::PreeditChangedInlineThis() {
2496 // Copy & paste by johnsonj with a lot of helps of Neil
2497 // Great thanks for my foreruners, jiniya and BLUEnLIVE
2499 view
.imeCaretBlockOverride
= false; // If backspace.
2501 if (pdoc
->TentativeActive()) {
2502 pdoc
->TentativeUndo();
2504 // No tentative undo means start of this composition so
2505 // fill in any virtual spaces.
2509 PreEditString
preeditStr(im_context
);
2510 const char *charSetSource
= CharacterSetID();
2512 if (!preeditStr
.validUTF8
|| (charSetSource
== NULL
)) {
2513 ShowCaretAtCurrentPosition();
2517 if (preeditStr
.uniStrLen
== 0 || preeditStr
.uniStrLen
> maxLenInputIME
) {
2518 //fprintf(stderr, "Do not allow over 200 chars: %i\n", preeditStr.uniStrLen);
2519 ShowCaretAtCurrentPosition();
2523 pdoc
->TentativeStart(); // TentativeActive() from now on
2525 // Get preedit string attribues
2526 bool normalInput
[maxLenInputIME
*3+1] = {false};
2527 bool targetInput
[maxLenInputIME
*3+1] = {false};
2528 GetImeUnderlines(preeditStr
.attrs
, normalInput
);
2529 GetImeBackgrounds(preeditStr
.attrs
, targetInput
);
2531 // Display preedit characters, one by one
2532 glong imeCharPos
[maxLenInputIME
+1] = { 0 };
2533 glong attrPos
= -1; // Start at -1 to designate the last byte of one character.
2534 glong charWidth
= 0;
2536 bool tmpRecordingMacro
= recordingMacro
;
2537 recordingMacro
= false;
2538 for (glong i
= 0; i
< preeditStr
.uniStrLen
; i
++) {
2540 gunichar uniChar
[1] = {0};
2541 uniChar
[0] = preeditStr
.uniStr
[i
];
2543 glong oneCharLen
= 0;
2544 gchar
*oneChar
= g_ucs4_to_utf8(uniChar
, 1, NULL
, &oneCharLen
, NULL
);
2546 // Record attribute positions in UTF-8 bytes
2547 attrPos
+= oneCharLen
;
2549 if (IsUnicodeMode()) {
2552 std::string oneCharSTD
= ConvertText(oneChar
, oneCharLen
, charSetSource
, "UTF-8", true);
2553 oneCharLen
= oneCharSTD
.copy(oneChar
,oneCharSTD
.length(), 0);
2554 oneChar
[oneCharLen
] = '\0';
2557 // Record character positions in UTF-8 or DBCS bytes
2559 charWidth
+= oneCharLen
;
2560 imeCharPos
[i
+1] = charWidth
;
2562 // Display one character
2563 AddCharUTF(oneChar
, oneCharLen
);
2565 // Draw an indicator on the character,
2566 // Overlapping allowed
2567 if (normalInput
[attrPos
]) {
2568 DrawImeIndicator(SC_INDICATOR_INPUT
, oneCharLen
);
2570 if (targetInput
[attrPos
]) {
2571 DrawImeIndicator(SC_INDICATOR_TARGET
, oneCharLen
);
2575 recordingMacro
= tmpRecordingMacro
;
2577 // Move caret to ime cursor position.
2579 view
.imeCaretBlockOverride
= true;
2580 MoveImeCarets( - (imeCharPos
[preeditStr
.uniStrLen
]));
2583 MoveImeCarets( - (imeCharPos
[preeditStr
.uniStrLen
]) + imeCharPos
[preeditStr
.cursor_pos
]);
2586 SetCandidateWindowPos();
2587 ShowCaretAtCurrentPosition();
2589 errorStatus
= SC_STATUS_FAILURE
;
2593 void ScintillaGTK::PreeditChangedWindowedThis() {
2595 PreEditString
pes(im_context
);
2596 if (strlen(pes
.str
) > 0) {
2597 PangoLayout
*layout
= gtk_widget_create_pango_layout(PWidget(wText
), pes
.str
);
2598 pango_layout_set_attributes(layout
, pes
.attrs
);
2601 pango_layout_get_pixel_size(layout
, &w
, &h
);
2602 g_object_unref(layout
);
2605 gdk_window_get_origin(PWindow(wText
), &x
, &y
);
2607 Point pt
= PointMainCaret();
2613 gtk_window_move(GTK_WINDOW(PWidget(wPreedit
)), x
+ pt
.x
, y
+ pt
.y
);
2614 gtk_window_resize(GTK_WINDOW(PWidget(wPreedit
)), w
, h
);
2615 gtk_widget_show(PWidget(wPreedit
));
2616 gtk_widget_queue_draw_area(PWidget(wPreeditDraw
), 0, 0, w
, h
);
2618 gtk_widget_hide(PWidget(wPreedit
));
2621 errorStatus
= SC_STATUS_FAILURE
;
2625 void ScintillaGTK::PreeditChanged(GtkIMContext
*, ScintillaGTK
*sciThis
) {
2626 if ((sciThis
->imeInteraction
== imeInline
) || (sciThis
->KoreanIME())) {
2627 sciThis
->PreeditChangedInlineThis();
2629 sciThis
->PreeditChangedWindowedThis();
2633 void ScintillaGTK::StyleSetText(GtkWidget
*widget
, GtkStyle
*, void*) {
2634 RealizeText(widget
, NULL
);
2637 void ScintillaGTK::RealizeText(GtkWidget
*widget
, void*) {
2638 // Set NULL background to avoid automatic clearing so Scintilla responsible for all drawing
2639 if (WindowFromWidget(widget
)) {
2640 #if GTK_CHECK_VERSION(3,0,0)
2641 gdk_window_set_background_pattern(WindowFromWidget(widget
), NULL
);
2643 gdk_window_set_back_pixmap(WindowFromWidget(widget
), NULL
, FALSE
);
2648 static GObjectClass
*scintilla_class_parent_class
;
2650 void ScintillaGTK::Destroy(GObject
*object
) {
2652 ScintillaObject
*scio
= reinterpret_cast<ScintillaObject
*>(object
);
2654 // This avoids a double destruction
2657 ScintillaGTK
*sciThis
= reinterpret_cast<ScintillaGTK
*>(scio
->pscin
);
2658 //Platform::DebugPrintf("Destroying %x %x\n", sciThis, object);
2659 sciThis
->Finalise();
2663 scintilla_class_parent_class
->finalize(object
);
2665 // Its dead so nowhere to save the status
2669 #if GTK_CHECK_VERSION(3,0,0)
2671 gboolean
ScintillaGTK::DrawTextThis(cairo_t
*cr
) {
2673 paintState
= painting
;
2674 repaintFullWindow
= false;
2676 rcPaint
= GetClientRectangle();
2678 PLATFORM_ASSERT(rgnUpdate
== NULL
);
2679 rgnUpdate
= cairo_copy_clip_rectangle_list(cr
);
2680 if (rgnUpdate
&& rgnUpdate
->status
!= CAIRO_STATUS_SUCCESS
) {
2681 // If not successful then ignore
2682 fprintf(stderr
, "DrawTextThis failed to copy update region %d [%d]\n", rgnUpdate
->status
, rgnUpdate
->num_rectangles
);
2683 cairo_rectangle_list_destroy(rgnUpdate
);
2687 double x1
, y1
, x2
, y2
;
2688 cairo_clip_extents(cr
, &x1
, &y1
, &x2
, &y2
);
2692 rcPaint
.bottom
= y2
;
2693 PRectangle rcClient
= GetClientRectangle();
2694 paintingAllText
= rcPaint
.Contains(rcClient
);
2695 Surface
*surfaceWindow
= Surface::Allocate(SC_TECHNOLOGY_DEFAULT
);
2696 if (surfaceWindow
) {
2697 surfaceWindow
->Init(cr
, PWidget(wText
));
2698 Paint(surfaceWindow
, rcPaint
);
2699 surfaceWindow
->Release();
2700 delete surfaceWindow
;
2702 if ((paintState
== paintAbandoned
) || repaintFullWindow
) {
2703 // Painting area was insufficient to cover new styling or brace highlight positions
2706 paintState
= notPainting
;
2707 repaintFullWindow
= false;
2710 cairo_rectangle_list_destroy(rgnUpdate
);
2713 paintState
= notPainting
;
2715 errorStatus
= SC_STATUS_FAILURE
;
2721 gboolean
ScintillaGTK::DrawText(GtkWidget
*, cairo_t
*cr
, ScintillaGTK
*sciThis
) {
2722 return sciThis
->DrawTextThis(cr
);
2725 gboolean
ScintillaGTK::DrawThis(cairo_t
*cr
) {
2727 gtk_container_propagate_draw(
2728 GTK_CONTAINER(PWidget(wMain
)), PWidget(scrollbarh
), cr
);
2729 gtk_container_propagate_draw(
2730 GTK_CONTAINER(PWidget(wMain
)), PWidget(scrollbarv
), cr
);
2731 // Starting from the following version, the expose event are not propagated
2732 // for double buffered non native windows, so we need to call it ourselves
2733 // or keep the default handler
2734 #if GTK_CHECK_VERSION(3,0,0)
2735 // we want to forward on any >= 3.9.2 runtime
2736 if (gtk_check_version(3,9,2) == NULL
) {
2737 gtk_container_propagate_draw(
2738 GTK_CONTAINER(PWidget(wMain
)), PWidget(wText
), cr
);
2742 errorStatus
= SC_STATUS_FAILURE
;
2747 gboolean
ScintillaGTK::DrawMain(GtkWidget
*widget
, cairo_t
*cr
) {
2748 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2749 return sciThis
->DrawThis(cr
);
2754 gboolean
ScintillaGTK::ExposeTextThis(GtkWidget
* /*widget*/, GdkEventExpose
*ose
) {
2756 paintState
= painting
;
2758 rcPaint
.left
= ose
->area
.x
;
2759 rcPaint
.top
= ose
->area
.y
;
2760 rcPaint
.right
= ose
->area
.x
+ ose
->area
.width
;
2761 rcPaint
.bottom
= ose
->area
.y
+ ose
->area
.height
;
2763 PLATFORM_ASSERT(rgnUpdate
== NULL
);
2764 rgnUpdate
= gdk_region_copy(ose
->region
);
2765 PRectangle rcClient
= GetClientRectangle();
2766 paintingAllText
= rcPaint
.Contains(rcClient
);
2767 Surface
*surfaceWindow
= Surface::Allocate(SC_TECHNOLOGY_DEFAULT
);
2768 if (surfaceWindow
) {
2769 cairo_t
*cr
= gdk_cairo_create(PWindow(wText
));
2770 surfaceWindow
->Init(cr
, PWidget(wText
));
2771 Paint(surfaceWindow
, rcPaint
);
2772 surfaceWindow
->Release();
2773 delete surfaceWindow
;
2776 if (paintState
== paintAbandoned
) {
2777 // Painting area was insufficient to cover new styling or brace highlight positions
2780 paintState
= notPainting
;
2783 gdk_region_destroy(rgnUpdate
);
2787 errorStatus
= SC_STATUS_FAILURE
;
2793 gboolean
ScintillaGTK::ExposeText(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
) {
2794 return sciThis
->ExposeTextThis(widget
, ose
);
2797 gboolean
ScintillaGTK::ExposeMain(GtkWidget
*widget
, GdkEventExpose
*ose
) {
2798 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2799 //Platform::DebugPrintf("Expose Main %0d,%0d %0d,%0d\n",
2800 //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2801 return sciThis
->Expose(widget
, ose
);
2804 gboolean
ScintillaGTK::Expose(GtkWidget
*, GdkEventExpose
*ose
) {
2806 //fprintf(stderr, "Expose %0d,%0d %0d,%0d\n",
2807 //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2809 // The text is painted in ExposeText
2810 gtk_container_propagate_expose(
2811 GTK_CONTAINER(PWidget(wMain
)), PWidget(scrollbarh
), ose
);
2812 gtk_container_propagate_expose(
2813 GTK_CONTAINER(PWidget(wMain
)), PWidget(scrollbarv
), ose
);
2816 errorStatus
= SC_STATUS_FAILURE
;
2823 void ScintillaGTK::ScrollSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
) {
2825 #if GTK_CHECK_VERSION(3,0,0)
2826 sciThis
->ScrollTo(static_cast<int>(gtk_adjustment_get_value(adj
)), false);
2828 sciThis
->ScrollTo(static_cast<int>(adj
->value
), false);
2831 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2835 void ScintillaGTK::ScrollHSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
) {
2837 #if GTK_CHECK_VERSION(3,0,0)
2838 sciThis
->HorizontalScrollTo(static_cast<int>(gtk_adjustment_get_value(adj
)));
2840 sciThis
->HorizontalScrollTo(static_cast<int>(adj
->value
));
2843 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2847 void ScintillaGTK::SelectionReceived(GtkWidget
*widget
,
2848 GtkSelectionData
*selection_data
, guint
) {
2849 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2850 //Platform::DebugPrintf("Selection received\n");
2851 sciThis
->ReceivedSelection(selection_data
);
2854 void ScintillaGTK::SelectionGet(GtkWidget
*widget
,
2855 GtkSelectionData
*selection_data
, guint info
, guint
) {
2856 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2858 //Platform::DebugPrintf("Selection get\n");
2859 if (SelectionOfGSD(selection_data
) == GDK_SELECTION_PRIMARY
) {
2860 if (sciThis
->primary
.Empty()) {
2861 sciThis
->CopySelectionRange(&sciThis
->primary
);
2863 sciThis
->GetSelection(selection_data
, info
, &sciThis
->primary
);
2866 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2870 gint
ScintillaGTK::SelectionClear(GtkWidget
*widget
, GdkEventSelection
*selection_event
) {
2871 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2872 //Platform::DebugPrintf("Selection clear\n");
2873 sciThis
->UnclaimSelection(selection_event
);
2874 if (GTK_WIDGET_CLASS(sciThis
->parentClass
)->selection_clear_event
) {
2875 return GTK_WIDGET_CLASS(sciThis
->parentClass
)->selection_clear_event(widget
, selection_event
);
2880 gboolean
ScintillaGTK::DragMotionThis(GdkDragContext
*context
,
2881 gint x
, gint y
, guint dragtime
) {
2884 SetDragPosition(SPositionFromLocation(npt
, false, false, UserVirtualSpace()));
2885 #if GTK_CHECK_VERSION(3,0,0)
2886 GdkDragAction preferredAction
= gdk_drag_context_get_suggested_action(context
);
2887 GdkDragAction actions
= gdk_drag_context_get_actions(context
);
2889 GdkDragAction preferredAction
= context
->suggested_action
;
2890 GdkDragAction actions
= context
->actions
;
2892 SelectionPosition pos
= SPositionFromLocation(npt
);
2893 if ((inDragDrop
== ddDragging
) && (PositionInSelection(pos
.Position()))) {
2894 // Avoid dragging selection onto itself as that produces a move
2895 // with no real effect but which creates undo actions.
2896 preferredAction
= static_cast<GdkDragAction
>(0);
2897 } else if (actions
== static_cast<GdkDragAction
>
2898 (GDK_ACTION_COPY
| GDK_ACTION_MOVE
)) {
2899 preferredAction
= GDK_ACTION_MOVE
;
2901 gdk_drag_status(context
, preferredAction
, dragtime
);
2903 errorStatus
= SC_STATUS_FAILURE
;
2908 gboolean
ScintillaGTK::DragMotion(GtkWidget
*widget
, GdkDragContext
*context
,
2909 gint x
, gint y
, guint dragtime
) {
2910 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2911 return sciThis
->DragMotionThis(context
, x
, y
, dragtime
);
2914 void ScintillaGTK::DragLeave(GtkWidget
*widget
, GdkDragContext
* /*context*/, guint
) {
2915 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2917 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2918 //Platform::DebugPrintf("DragLeave %x\n", sciThis);
2920 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2924 void ScintillaGTK::DragEnd(GtkWidget
*widget
, GdkDragContext
* /*context*/) {
2925 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2927 // If drag did not result in drop here or elsewhere
2928 if (!sciThis
->dragWasDropped
)
2929 sciThis
->SetEmptySelection(sciThis
->posDrag
);
2930 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2931 //Platform::DebugPrintf("DragEnd %x %d\n", sciThis, sciThis->dragWasDropped);
2932 sciThis
->inDragDrop
= ddNone
;
2934 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2938 gboolean
ScintillaGTK::Drop(GtkWidget
*widget
, GdkDragContext
* /*context*/,
2939 gint
, gint
, guint
) {
2940 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2942 //Platform::DebugPrintf("Drop %x\n", sciThis);
2943 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2945 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2950 void ScintillaGTK::DragDataReceived(GtkWidget
*widget
, GdkDragContext
* /*context*/,
2951 gint
, gint
, GtkSelectionData
*selection_data
, guint
/*info*/, guint
) {
2952 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2954 sciThis
->ReceivedDrop(selection_data
);
2955 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2957 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2961 void ScintillaGTK::DragDataGet(GtkWidget
*widget
, GdkDragContext
*context
,
2962 GtkSelectionData
*selection_data
, guint info
, guint
) {
2963 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2965 sciThis
->dragWasDropped
= true;
2966 if (!sciThis
->sel
.Empty()) {
2967 sciThis
->GetSelection(selection_data
, info
, &sciThis
->drag
);
2969 #if GTK_CHECK_VERSION(3,0,0)
2970 GdkDragAction action
= gdk_drag_context_get_selected_action(context
);
2972 GdkDragAction action
= context
->action
;
2974 if (action
== GDK_ACTION_MOVE
) {
2975 for (size_t r
=0; r
<sciThis
->sel
.Count(); r
++) {
2976 if (sciThis
->posDrop
>= sciThis
->sel
.Range(r
).Start()) {
2977 if (sciThis
->posDrop
> sciThis
->sel
.Range(r
).End()) {
2978 sciThis
->posDrop
.Add(-sciThis
->sel
.Range(r
).Length());
2980 sciThis
->posDrop
.Add(-SelectionRange(sciThis
->posDrop
, sciThis
->sel
.Range(r
).Start()).Length());
2984 sciThis
->ClearSelection();
2986 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2988 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2992 int ScintillaGTK::TimeOut(TimeThunk
*tt
) {
2993 tt
->scintilla
->TickFor(tt
->reason
);
2997 gboolean
ScintillaGTK::IdleCallback(ScintillaGTK
*sciThis
) {
2998 // Idler will be automatically stopped, if there is nothing
2999 // to do while idle.
3000 #ifndef GDK_VERSION_3_6
3001 gdk_threads_enter();
3003 bool ret
= sciThis
->Idle();
3005 // FIXME: This will remove the idler from GTK, we don't want to
3006 // remove it as it is removed automatically when this function
3007 // returns false (although, it should be harmless).
3008 sciThis
->SetIdle(false);
3010 #ifndef GDK_VERSION_3_6
3011 gdk_threads_leave();
3016 gboolean
ScintillaGTK::StyleIdle(ScintillaGTK
*sciThis
) {
3017 #ifndef GDK_VERSION_3_6
3018 gdk_threads_enter();
3020 sciThis
->IdleWork();
3021 #ifndef GDK_VERSION_3_6
3022 gdk_threads_leave();
3024 // Idler will be automatically stopped
3028 void ScintillaGTK::QueueIdleWork(WorkNeeded::workItems items
, int upTo
) {
3029 Editor::QueueIdleWork(items
, upTo
);
3030 if (!workNeeded
.active
) {
3031 // Only allow one style needed to be queued
3032 workNeeded
.active
= true;
3033 g_idle_add_full(G_PRIORITY_HIGH_IDLE
,
3034 reinterpret_cast<GSourceFunc
>(StyleIdle
), this, NULL
);
3038 void ScintillaGTK::PopUpCB(GtkMenuItem
*menuItem
, ScintillaGTK
*sciThis
) {
3039 guint action
= (sptr_t
)(g_object_get_data(G_OBJECT(menuItem
), "CmdNum"));
3041 sciThis
->Command(action
);
3045 gboolean
ScintillaGTK::PressCT(GtkWidget
*widget
, GdkEventButton
*event
, ScintillaGTK
*sciThis
) {
3047 if (event
->window
!= WindowFromWidget(widget
))
3049 if (event
->type
!= GDK_BUTTON_PRESS
)
3052 pt
.x
= int(event
->x
);
3053 pt
.y
= int(event
->y
);
3054 sciThis
->ct
.MouseClick(pt
);
3055 sciThis
->CallTipClick();
3061 #if GTK_CHECK_VERSION(3,0,0)
3063 gboolean
ScintillaGTK::DrawCT(GtkWidget
*widget
, cairo_t
*cr
, CallTip
*ctip
) {
3065 Surface
*surfaceWindow
= Surface::Allocate(SC_TECHNOLOGY_DEFAULT
);
3066 if (surfaceWindow
) {
3067 surfaceWindow
->Init(cr
, widget
);
3068 surfaceWindow
->SetUnicodeMode(SC_CP_UTF8
== ctip
->codePage
);
3069 surfaceWindow
->SetDBCSMode(ctip
->codePage
);
3070 ctip
->PaintCT(surfaceWindow
);
3071 surfaceWindow
->Release();
3072 delete surfaceWindow
;
3075 // No pointer back to Scintilla to save status
3082 gboolean
ScintillaGTK::ExposeCT(GtkWidget
*widget
, GdkEventExpose
* /*ose*/, CallTip
*ctip
) {
3084 Surface
*surfaceWindow
= Surface::Allocate(SC_TECHNOLOGY_DEFAULT
);
3085 if (surfaceWindow
) {
3086 cairo_t
*cr
= gdk_cairo_create(WindowFromWidget(widget
));
3087 surfaceWindow
->Init(cr
, widget
);
3088 surfaceWindow
->SetUnicodeMode(SC_CP_UTF8
== ctip
->codePage
);
3089 surfaceWindow
->SetDBCSMode(ctip
->codePage
);
3090 ctip
->PaintCT(surfaceWindow
);
3091 surfaceWindow
->Release();
3092 delete surfaceWindow
;
3096 // No pointer back to Scintilla to save status
3103 sptr_t
ScintillaGTK::DirectFunction(
3104 sptr_t ptr
, unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
3105 return reinterpret_cast<ScintillaGTK
*>(ptr
)->WndProc(iMessage
, wParam
, lParam
);
3109 sptr_t
scintilla_send_message(ScintillaObject
*sci
, unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
3110 ScintillaGTK
*psci
= reinterpret_cast<ScintillaGTK
*>(sci
->pscin
);
3111 return psci
->WndProc(iMessage
, wParam
, lParam
);
3114 static void scintilla_class_init(ScintillaClass
*klass
);
3115 static void scintilla_init(ScintillaObject
*sci
);
3117 extern void Platform_Initialise();
3118 extern void Platform_Finalise();
3121 GType
scintilla_get_type() {
3122 static GType scintilla_type
= 0;
3125 if (!scintilla_type
) {
3126 scintilla_type
= g_type_from_name("Scintilla");
3127 if (!scintilla_type
) {
3128 static GTypeInfo scintilla_info
= {
3129 (guint16
) sizeof (ScintillaClass
),
3130 NULL
, //(GBaseInitFunc)
3131 NULL
, //(GBaseFinalizeFunc)
3132 (GClassInitFunc
) scintilla_class_init
,
3133 NULL
, //(GClassFinalizeFunc)
3134 NULL
, //gconstpointer data
3135 (guint16
) sizeof (ScintillaObject
),
3137 (GInstanceInitFunc
) scintilla_init
,
3138 NULL
//(GTypeValueTable*)
3141 scintilla_type
= g_type_register_static(
3142 GTK_TYPE_CONTAINER
, "Scintilla", &scintilla_info
, (GTypeFlags
) 0);
3148 return scintilla_type
;
3151 void ScintillaGTK::ClassInit(OBJECT_CLASS
* object_class
, GtkWidgetClass
*widget_class
, GtkContainerClass
*container_class
) {
3152 Platform_Initialise();
3154 Scintilla_LinkLexers();
3156 atomClipboard
= gdk_atom_intern("CLIPBOARD", FALSE
);
3157 atomUTF8
= gdk_atom_intern("UTF8_STRING", FALSE
);
3158 atomString
= GDK_SELECTION_TYPE_STRING
;
3159 atomUriList
= gdk_atom_intern("text/uri-list", FALSE
);
3160 atomDROPFILES_DND
= gdk_atom_intern("DROPFILES_DND", FALSE
);
3162 // Define default signal handlers for the class: Could move more
3163 // of the signal handlers here (those that currently attached to wDraw
3164 // in Initialise() may require coordinate translation?)
3166 object_class
->finalize
= Destroy
;
3167 #if GTK_CHECK_VERSION(3,0,0)
3168 widget_class
->get_preferred_width
= GetPreferredWidth
;
3169 widget_class
->get_preferred_height
= GetPreferredHeight
;
3171 widget_class
->size_request
= SizeRequest
;
3173 widget_class
->size_allocate
= SizeAllocate
;
3174 #if GTK_CHECK_VERSION(3,0,0)
3175 widget_class
->draw
= DrawMain
;
3177 widget_class
->expose_event
= ExposeMain
;
3179 widget_class
->motion_notify_event
= Motion
;
3180 widget_class
->button_press_event
= Press
;
3181 widget_class
->button_release_event
= MouseRelease
;
3182 widget_class
->scroll_event
= ScrollEvent
;
3183 widget_class
->key_press_event
= KeyPress
;
3184 widget_class
->key_release_event
= KeyRelease
;
3185 widget_class
->focus_in_event
= FocusIn
;
3186 widget_class
->focus_out_event
= FocusOut
;
3187 widget_class
->selection_received
= SelectionReceived
;
3188 widget_class
->selection_get
= SelectionGet
;
3189 widget_class
->selection_clear_event
= SelectionClear
;
3191 widget_class
->drag_data_received
= DragDataReceived
;
3192 widget_class
->drag_motion
= DragMotion
;
3193 widget_class
->drag_leave
= DragLeave
;
3194 widget_class
->drag_end
= DragEnd
;
3195 widget_class
->drag_drop
= Drop
;
3196 widget_class
->drag_data_get
= DragDataGet
;
3198 widget_class
->realize
= Realize
;
3199 widget_class
->unrealize
= UnRealize
;
3200 widget_class
->map
= Map
;
3201 widget_class
->unmap
= UnMap
;
3203 container_class
->forall
= MainForAll
;
3206 #define SIG_MARSHAL scintilla_marshal_NONE__INT_POINTER
3207 #define MARSHAL_ARGUMENTS G_TYPE_INT, G_TYPE_POINTER
3209 static void scintilla_class_init(ScintillaClass
*klass
) {
3211 OBJECT_CLASS
*object_class
= (OBJECT_CLASS
*) klass
;
3212 GtkWidgetClass
*widget_class
= (GtkWidgetClass
*) klass
;
3213 GtkContainerClass
*container_class
= (GtkContainerClass
*) klass
;
3215 GSignalFlags sigflags
= GSignalFlags(G_SIGNAL_ACTION
| G_SIGNAL_RUN_LAST
);
3216 scintilla_signals
[COMMAND_SIGNAL
] = g_signal_new(
3218 G_TYPE_FROM_CLASS(object_class
),
3220 G_STRUCT_OFFSET(ScintillaClass
, command
),
3221 NULL
, //(GSignalAccumulator)
3225 2, MARSHAL_ARGUMENTS
);
3227 scintilla_signals
[NOTIFY_SIGNAL
] = g_signal_new(
3229 G_TYPE_FROM_CLASS(object_class
),
3231 G_STRUCT_OFFSET(ScintillaClass
, notify
),
3236 2, MARSHAL_ARGUMENTS
);
3238 klass
->command
= NULL
;
3239 klass
->notify
= NULL
;
3240 scintilla_class_parent_class
= G_OBJECT_CLASS(g_type_class_peek_parent(klass
));
3241 ScintillaGTK::ClassInit(object_class
, widget_class
, container_class
);
3246 static void scintilla_init(ScintillaObject
*sci
) {
3248 #if GTK_CHECK_VERSION(2,20,0)
3249 gtk_widget_set_can_focus(GTK_WIDGET(sci
), TRUE
);
3251 GTK_WIDGET_SET_FLAGS(sci
, GTK_CAN_FOCUS
);
3253 sci
->pscin
= new ScintillaGTK(sci
);
3259 GtkWidget
* scintilla_new() {
3260 GtkWidget
*widget
= GTK_WIDGET(g_object_new(scintilla_get_type(), NULL
));
3261 gtk_widget_set_direction(widget
, GTK_TEXT_DIR_LTR
);
3266 void scintilla_set_id(ScintillaObject
*sci
, uptr_t id
) {
3267 ScintillaGTK
*psci
= reinterpret_cast<ScintillaGTK
*>(sci
->pscin
);
3271 void scintilla_release_resources(void) {
3273 Platform_Finalise();