geany  1.38
About: Geany is a text editor (using GTK2) with basic features of an integrated development environment (syntax highlighting, code folding, symbol name auto-completion, ...). F: office T: editor programming GTK+ IDE
  Fossies Dox: geany-1.38.tar.bz2  ("unofficial" and yet experimental doxygen-generated source code documentation)  

ScintillaGTK.cxx
Go to the documentation of this file.
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.
5
6#include <cstddef>
7#include <cstdlib>
8#include <cassert>
9#include <cstring>
10#include <cstdio>
11#include <ctime>
12#include <cmath>
13
14#include <stdexcept>
15#include <new>
16#include <string>
17#include <vector>
18#include <map>
19#include <algorithm>
20#include <memory>
21
22#include <glib.h>
23#include <gmodule.h>
24#include <gdk/gdk.h>
25#include <gtk/gtk.h>
26#include <gdk/gdkkeysyms.h>
27#if defined(GDK_WINDOWING_WAYLAND)
28#include <gdk/gdkwayland.h>
29#endif
30
31#if defined(_WIN32)
32// On Win32 use windows.h to access clipboard (rectangular format) and systems parameters
33#undef NOMINMAX
34#define NOMINMAX
35#include <windows.h>
36#endif
37
38#include "Platform.h"
39
40#include "ILoader.h"
41#include "ILexer.h"
42#include "Scintilla.h"
43#include "ScintillaWidget.h"
44#include "StringCopy.h"
45#include "CharacterCategory.h"
46#include "Position.h"
47#include "UniqueString.h"
48#include "SplitVector.h"
49#include "Partitioning.h"
50#include "RunStyles.h"
51#include "ContractionState.h"
52#include "CellBuffer.h"
53#include "CallTip.h"
54#include "KeyMap.h"
55#include "Indicator.h"
56#include "LineMarker.h"
57#include "Style.h"
58#include "ViewStyle.h"
59#include "CharClassify.h"
60#include "Decoration.h"
61#include "CaseFolder.h"
62#include "Document.h"
63#include "CaseConvert.h"
64#include "UniConversion.h"
65#include "Selection.h"
66#include "PositionCache.h"
67#include "EditModel.h"
68#include "MarginView.h"
69#include "EditView.h"
70#include "Editor.h"
71#include "AutoComplete.h"
72#include "ScintillaBase.h"
73
74#include "ScintillaGTK.h"
75#include "scintilla-marshal.h"
77
78#include "Converter.h"
79
80#define IS_WIDGET_REALIZED(w) (gtk_widget_get_realized(GTK_WIDGET(w)))
81#define IS_WIDGET_MAPPED(w) (gtk_widget_get_mapped(GTK_WIDGET(w)))
82
83#define SC_INDICATOR_INPUT INDICATOR_IME
84#define SC_INDICATOR_TARGET INDICATOR_IME+1
85#define SC_INDICATOR_CONVERTED INDICATOR_IME+2
86#define SC_INDICATOR_UNKNOWN INDICATOR_IME_MAX
87
88static GdkWindow *WindowFromWidget(GtkWidget *w) noexcept {
89 return gtk_widget_get_window(w);
90}
91
92#ifdef _MSC_VER
93// Constant conditional expressions are because of GTK+ headers
94#pragma warning(disable: 4127)
95// Ignore unreferenced local functions in GTK+ headers
96#pragma warning(disable: 4505)
97#endif
98
99using namespace Scintilla;
100
101static GdkWindow *PWindow(const Window &w) noexcept {
102 GtkWidget *widget = static_cast<GtkWidget *>(w.GetID());
103 return gtk_widget_get_window(widget);
104}
105
106extern std::string UTF8FromLatin1(const char *s, int len);
107
108enum {
113
114static gint scintilla_signals[LAST_SIGNAL] = { 0 };
115
116enum {
123
124GdkAtom ScintillaGTK::atomUTF8 = nullptr;
125GdkAtom ScintillaGTK::atomUTF8Mime = nullptr;
126GdkAtom ScintillaGTK::atomString = nullptr;
127GdkAtom ScintillaGTK::atomUriList = nullptr;
128GdkAtom ScintillaGTK::atomDROPFILES_DND = nullptr;
129
130static const GtkTargetEntry clipboardCopyTargets[] = {
131 { (gchar *) "UTF8_STRING", 0, TARGET_UTF8_STRING },
132 { (gchar *) "STRING", 0, TARGET_STRING },
133};
135
136static const GtkTargetEntry clipboardPasteTargets[] = {
137 { (gchar *) "text/uri-list", 0, TARGET_URI },
138 { (gchar *) "UTF8_STRING", 0, TARGET_UTF8_STRING },
139 { (gchar *) "STRING", 0, TARGET_STRING },
140};
142
143static const GdkDragAction actionCopyOrMove = static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE);
144
145static GtkWidget *PWidget(const Window &w) noexcept {
146 return static_cast<GtkWidget *>(w.GetID());
147}
148
149ScintillaGTK *ScintillaGTK::FromWidget(GtkWidget *widget) noexcept {
150 ScintillaObject *scio = SCINTILLA(widget);
151 return static_cast<ScintillaGTK *>(scio->pscin);
152}
153
154ScintillaGTK::ScintillaGTK(_ScintillaObject *sci_) :
155 adjustmentv(nullptr), adjustmenth(nullptr),
156 verticalScrollBarWidth(30), horizontalScrollBarHeight(30),
157 evbtn(nullptr),
158 buttonMouse(0),
159 capturedMouse(false), dragWasDropped(false),
160 lastKey(0), rectangularSelectionModifier(SCMOD_CTRL),
161 parentClass(nullptr),
162 atomSought(nullptr),
163 preeditInitialized(false),
164 im_context(nullptr),
165 lastNonCommonScript(G_UNICODE_SCRIPT_INVALID_CODE),
166 lastWheelMouseTime(0),
167 lastWheelMouseDirection(0),
168 wheelMouseIntensity(0),
169 smoothScrollY(0),
170 smoothScrollX(0),
171 rgnUpdate(nullptr),
172 repaintFullWindow(false),
173 styleIdleID(0),
174 accessibilityEnabled(SC_ACCESSIBILITY_ENABLED),
175 accessible(nullptr) {
176 sci = sci_;
177 wMain = GTK_WIDGET(sci);
178
180
181#if PLAT_GTK_WIN32
182 // There does not seem to be a real standard for indicating that the clipboard
183 // contains a rectangular selection, so copy Developer Studio.
184 cfColumnSelect = static_cast<CLIPFORMAT>(
185 ::RegisterClipboardFormat("MSDEVColumnSelect"));
186
187 // Get intellimouse parameters when running on win32; otherwise use
188 // reasonable default
189#ifndef SPI_GETWHEELSCROLLLINES
190#define SPI_GETWHEELSCROLLLINES 104
191#endif
192 ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &linesPerScroll, 0);
193#else
194 linesPerScroll = 4;
195#endif
196
197 Init();
198}
199
201 if (styleIdleID) {
202 g_source_remove(styleIdleID);
203 styleIdleID = 0;
204 }
205 if (evbtn) {
206 gdk_event_free(evbtn);
207 evbtn = nullptr;
208 }
210}
211
212static void UnRefCursor(GdkCursor *cursor) noexcept {
213#if GTK_CHECK_VERSION(3,0,0)
214 g_object_unref(cursor);
215#else
216 gdk_cursor_unref(cursor);
217#endif
218}
219
220void ScintillaGTK::RealizeThis(GtkWidget *widget) {
221 //Platform::DebugPrintf("ScintillaGTK::realize this\n");
222 gtk_widget_set_realized(widget, TRUE);
223 GdkWindowAttr attrs;
224 attrs.window_type = GDK_WINDOW_CHILD;
225 GtkAllocation allocation;
226 gtk_widget_get_allocation(widget, &allocation);
227 attrs.x = allocation.x;
228 attrs.y = allocation.y;
229 attrs.width = allocation.width;
230 attrs.height = allocation.height;
231 attrs.wclass = GDK_INPUT_OUTPUT;
232 attrs.visual = gtk_widget_get_visual(widget);
233#if !GTK_CHECK_VERSION(3,0,0)
234 attrs.colormap = gtk_widget_get_colormap(widget);
235#endif
236 attrs.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK;
237 GdkDisplay *pdisplay = gtk_widget_get_display(widget);
238 GdkCursor *cursor = gdk_cursor_new_for_display(pdisplay, GDK_XTERM);
239 attrs.cursor = cursor;
240#if GTK_CHECK_VERSION(3,0,0)
241 gtk_widget_set_window(widget, gdk_window_new(gtk_widget_get_parent_window(widget), &attrs,
242 GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_CURSOR));
243#if GTK_CHECK_VERSION(3,8,0)
244 gtk_widget_register_window(widget, gtk_widget_get_window(widget));
245#else
246 gdk_window_set_user_data(gtk_widget_get_window(widget), widget);
247#endif
248#if !GTK_CHECK_VERSION(3,18,0)
249 gtk_style_context_set_background(gtk_widget_get_style_context(widget),
250 gtk_widget_get_window(widget));
251#endif
252 gdk_window_show(gtk_widget_get_window(widget));
253 UnRefCursor(cursor);
254#else
255 widget->window = gdk_window_new(gtk_widget_get_parent_window(widget), &attrs,
256 GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_CURSOR);
257 gdk_window_set_user_data(widget->window, widget);
258 widget->style = gtk_style_attach(widget->style, widget->window);
259 gdk_window_set_background(widget->window, &widget->style->bg[GTK_STATE_NORMAL]);
260 gdk_window_show(widget->window);
261 UnRefCursor(cursor);
262#endif
263
264 preeditInitialized = false;
265 gtk_widget_realize(PWidget(wPreedit));
266 gtk_widget_realize(PWidget(wPreeditDraw));
267
268 im_context = gtk_im_multicontext_new();
269 g_signal_connect(G_OBJECT(im_context), "commit",
270 G_CALLBACK(Commit), this);
271 g_signal_connect(G_OBJECT(im_context), "preedit_changed",
272 G_CALLBACK(PreeditChanged), this);
273 gtk_im_context_set_client_window(im_context, WindowFromWidget(widget));
274
275 GtkWidget *widtxt = PWidget(wText); // // No code inside the G_OBJECT macro
276 g_signal_connect_after(G_OBJECT(widtxt), "style_set",
277 G_CALLBACK(ScintillaGTK::StyleSetText), nullptr);
278 g_signal_connect_after(G_OBJECT(widtxt), "realize",
279 G_CALLBACK(ScintillaGTK::RealizeText), nullptr);
280 gtk_widget_realize(widtxt);
281 gtk_widget_realize(PWidget(scrollbarv));
282 gtk_widget_realize(PWidget(scrollbarh));
283
284 cursor = gdk_cursor_new_for_display(pdisplay, GDK_XTERM);
285 gdk_window_set_cursor(PWindow(wText), cursor);
286 UnRefCursor(cursor);
287
288 cursor = gdk_cursor_new_for_display(pdisplay, GDK_LEFT_PTR);
289 gdk_window_set_cursor(PWindow(scrollbarv), cursor);
290 UnRefCursor(cursor);
291
292 cursor = gdk_cursor_new_for_display(pdisplay, GDK_LEFT_PTR);
293 gdk_window_set_cursor(PWindow(scrollbarh), cursor);
294 UnRefCursor(cursor);
295
296 wSelection = gtk_invisible_new();
297 g_signal_connect(PWidget(wSelection), "selection_get", G_CALLBACK(PrimarySelection), (gpointer) this);
298 g_signal_connect(PWidget(wSelection), "selection_clear_event", G_CALLBACK(PrimaryClear), (gpointer) this);
299 gtk_selection_add_targets(PWidget(wSelection), GDK_SELECTION_PRIMARY,
301}
302
303void ScintillaGTK::Realize(GtkWidget *widget) {
304 ScintillaGTK *sciThis = FromWidget(widget);
305 sciThis->RealizeThis(widget);
306}
307
308void ScintillaGTK::UnRealizeThis(GtkWidget *widget) {
309 try {
310 gtk_selection_clear_targets(PWidget(wSelection), GDK_SELECTION_PRIMARY);
312
313 if (IS_WIDGET_MAPPED(widget)) {
314 gtk_widget_unmap(widget);
315 }
316 gtk_widget_set_realized(widget, FALSE);
317 gtk_widget_unrealize(PWidget(wText));
318 if (PWidget(scrollbarv))
319 gtk_widget_unrealize(PWidget(scrollbarv));
320 if (PWidget(scrollbarh))
321 gtk_widget_unrealize(PWidget(scrollbarh));
322 gtk_widget_unrealize(PWidget(wPreedit));
323 gtk_widget_unrealize(PWidget(wPreeditDraw));
324 g_object_unref(im_context);
325 im_context = nullptr;
326 if (GTK_WIDGET_CLASS(parentClass)->unrealize)
327 GTK_WIDGET_CLASS(parentClass)->unrealize(widget);
328
329 Finalise();
330 } catch (...) {
332 }
333}
334
335void ScintillaGTK::UnRealize(GtkWidget *widget) {
336 ScintillaGTK *sciThis = FromWidget(widget);
337 sciThis->UnRealizeThis(widget);
338}
339
340static void MapWidget(GtkWidget *widget) noexcept {
341 if (widget &&
342 gtk_widget_get_visible(GTK_WIDGET(widget)) &&
343 !IS_WIDGET_MAPPED(widget)) {
344 gtk_widget_map(widget);
345 }
346}
347
349 try {
350 //Platform::DebugPrintf("ScintillaGTK::map this\n");
351 gtk_widget_set_mapped(PWidget(wMain), TRUE);
358 ChangeSize();
359 gdk_window_show(PWindow(wMain));
360 } catch (...) {
362 }
363}
364
365void ScintillaGTK::Map(GtkWidget *widget) {
366 ScintillaGTK *sciThis = FromWidget(widget);
367 sciThis->MapThis();
368}
369
371 try {
372 //Platform::DebugPrintf("ScintillaGTK::unmap this\n");
373 gtk_widget_set_mapped(PWidget(wMain), FALSE);
374 DropGraphics(false);
375 gdk_window_hide(PWindow(wMain));
376 gtk_widget_unmap(PWidget(wText));
377 if (PWidget(scrollbarh))
378 gtk_widget_unmap(PWidget(scrollbarh));
379 if (PWidget(scrollbarv))
380 gtk_widget_unmap(PWidget(scrollbarv));
381 } catch (...) {
383 }
384}
385
386void ScintillaGTK::UnMap(GtkWidget *widget) {
387 ScintillaGTK *sciThis = FromWidget(widget);
388 sciThis->UnMapThis();
389}
390
391void ScintillaGTK::ForAll(GtkCallback callback, gpointer callback_data) {
392 try {
393 (*callback)(PWidget(wText), callback_data);
394 if (PWidget(scrollbarv))
395 (*callback)(PWidget(scrollbarv), callback_data);
396 if (PWidget(scrollbarh))
397 (*callback)(PWidget(scrollbarh), callback_data);
398 } catch (...) {
400 }
401}
402
403void ScintillaGTK::MainForAll(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data) {
404 ScintillaGTK *sciThis = FromWidget((GtkWidget *)container);
405
406 if (callback && include_internals) {
407 sciThis->ForAll(callback, callback_data);
408 }
409}
410
411namespace {
412
413class PreEditString {
414public:
415 gchar *str;
416 gint cursor_pos;
417 PangoAttrList *attrs;
418 gboolean validUTF8;
419 glong uniStrLen;
420 gunichar *uniStr;
421 GUnicodeScript pscript;
422
423 explicit PreEditString(GtkIMContext *im_context) noexcept {
424 gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos);
425 validUTF8 = g_utf8_validate(str, strlen(str), nullptr);
426 uniStr = g_utf8_to_ucs4_fast(str, strlen(str), &uniStrLen);
427 pscript = g_unichar_get_script(uniStr[0]);
428 }
429 // Deleted so PreEditString objects can not be copied.
430 PreEditString(const PreEditString&) = delete;
431 PreEditString(PreEditString&&) = delete;
432 PreEditString&operator=(const PreEditString&) = delete;
433 PreEditString&operator=(PreEditString&&) = delete;
434 ~PreEditString() {
435 g_free(str);
436 g_free(uniStr);
437 pango_attr_list_unref(attrs);
438 }
439};
440
441}
442
443gint ScintillaGTK::FocusInThis(GtkWidget *) {
444 try {
445 SetFocusState(true);
446
447 if (im_context) {
448 gtk_im_context_focus_in(im_context);
449 PreEditString pes(im_context);
450 if (PWidget(wPreedit)) {
451 if (!preeditInitialized) {
452 GtkWidget *top = gtk_widget_get_toplevel(PWidget(wMain));
453 gtk_window_set_transient_for(GTK_WINDOW(PWidget(wPreedit)), GTK_WINDOW(top));
454 preeditInitialized = true;
455 }
456
457 if (strlen(pes.str) > 0) {
458 gtk_widget_show(PWidget(wPreedit));
459 } else {
460 gtk_widget_hide(PWidget(wPreedit));
461 }
462 }
463 }
464 } catch (...) {
466 }
467 return FALSE;
468}
469
470gint ScintillaGTK::FocusIn(GtkWidget *widget, GdkEventFocus * /*event*/) {
471 ScintillaGTK *sciThis = FromWidget(widget);
472 return sciThis->FocusInThis(widget);
473}
474
475gint ScintillaGTK::FocusOutThis(GtkWidget *) {
476 try {
477 SetFocusState(false);
478
479 if (PWidget(wPreedit))
480 gtk_widget_hide(PWidget(wPreedit));
481 if (im_context)
482 gtk_im_context_focus_out(im_context);
483
484 } catch (...) {
486 }
487 return FALSE;
488}
489
490gint ScintillaGTK::FocusOut(GtkWidget *widget, GdkEventFocus * /*event*/) {
491 ScintillaGTK *sciThis = FromWidget(widget);
492 return sciThis->FocusOutThis(widget);
493}
494
495void ScintillaGTK::SizeRequest(GtkWidget *widget, GtkRequisition *requisition) {
496 ScintillaGTK *sciThis = FromWidget(widget);
497 requisition->width = 1;
498 requisition->height = 1;
499 GtkRequisition child_requisition;
500#if GTK_CHECK_VERSION(3,0,0)
501 gtk_widget_get_preferred_size(PWidget(sciThis->scrollbarh), nullptr, &child_requisition);
502 gtk_widget_get_preferred_size(PWidget(sciThis->scrollbarv), nullptr, &child_requisition);
503#else
504 gtk_widget_size_request(PWidget(sciThis->scrollbarh), &child_requisition);
505 gtk_widget_size_request(PWidget(sciThis->scrollbarv), &child_requisition);
506#endif
507}
508
509#if GTK_CHECK_VERSION(3,0,0)
510
511void ScintillaGTK::GetPreferredWidth(GtkWidget *widget, gint *minimalWidth, gint *naturalWidth) {
512 GtkRequisition requisition;
513 SizeRequest(widget, &requisition);
514 *minimalWidth = *naturalWidth = requisition.width;
515}
516
517void ScintillaGTK::GetPreferredHeight(GtkWidget *widget, gint *minimalHeight, gint *naturalHeight) {
518 GtkRequisition requisition;
519 SizeRequest(widget, &requisition);
520 *minimalHeight = *naturalHeight = requisition.height;
521}
522
523#endif
524
525void ScintillaGTK::SizeAllocate(GtkWidget *widget, GtkAllocation *allocation) {
526 ScintillaGTK *sciThis = FromWidget(widget);
527 try {
528 gtk_widget_set_allocation(widget, allocation);
529 if (IS_WIDGET_REALIZED(widget))
530 gdk_window_move_resize(WindowFromWidget(widget),
531 allocation->x,
532 allocation->y,
533 allocation->width,
534 allocation->height);
535
536 sciThis->Resize(allocation->width, allocation->height);
537
538 } catch (...) {
540 }
541}
542
544 parentClass = static_cast<GtkWidgetClass *>(
545 g_type_class_ref(gtk_container_get_type()));
546
547 gint maskSmooth = 0;
548#if defined(GDK_WINDOWING_WAYLAND)
549 GdkDisplay *pdisplay = gdk_display_get_default();
550 if (GDK_IS_WAYLAND_DISPLAY(pdisplay)) {
551 // On Wayland, touch pads only produce smooth scroll events
552 maskSmooth = GDK_SMOOTH_SCROLL_MASK;
553 }
554#endif
555
556 gtk_widget_set_can_focus(PWidget(wMain), TRUE);
557 gtk_widget_set_sensitive(PWidget(wMain), TRUE);
558 gtk_widget_set_events(PWidget(wMain),
559 GDK_EXPOSURE_MASK
560 | GDK_SCROLL_MASK
561 | maskSmooth
562 | GDK_STRUCTURE_MASK
563 | GDK_KEY_PRESS_MASK
564 | GDK_KEY_RELEASE_MASK
565 | GDK_FOCUS_CHANGE_MASK
566 | GDK_LEAVE_NOTIFY_MASK
567 | GDK_BUTTON_PRESS_MASK
568 | GDK_BUTTON_RELEASE_MASK
569 | GDK_POINTER_MOTION_MASK
570 | GDK_POINTER_MOTION_HINT_MASK);
571
572 wText = gtk_drawing_area_new();
573 gtk_widget_set_parent(PWidget(wText), PWidget(wMain));
574 GtkWidget *widtxt = PWidget(wText); // No code inside the G_OBJECT macro
575 gtk_widget_show(widtxt);
576#if GTK_CHECK_VERSION(3,0,0)
577 g_signal_connect(G_OBJECT(widtxt), "draw",
578 G_CALLBACK(ScintillaGTK::DrawText), this);
579#else
580 g_signal_connect(G_OBJECT(widtxt), "expose_event",
581 G_CALLBACK(ScintillaGTK::ExposeText), this);
582#endif
583#if GTK_CHECK_VERSION(3,0,0)
584 // we need a runtime check because we don't want double buffering when
585 // running on >= 3.9.2
586 if (gtk_check_version(3, 9, 2) != nullptr /* on < 3.9.2 */)
587#endif
588 {
589#if !GTK_CHECK_VERSION(3,14,0)
590 // Avoid background drawing flash/missing redraws
591 gtk_widget_set_double_buffered(widtxt, FALSE);
592#endif
593 }
594 gtk_widget_set_events(widtxt, GDK_EXPOSURE_MASK);
595 gtk_widget_set_size_request(widtxt, 100, 100);
596 adjustmentv = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 201.0, 1.0, 20.0, 20.0));
597#if GTK_CHECK_VERSION(3,0,0)
598 scrollbarv = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, GTK_ADJUSTMENT(adjustmentv));
599#else
600 scrollbarv = gtk_vscrollbar_new(GTK_ADJUSTMENT(adjustmentv));
601#endif
602 gtk_widget_set_can_focus(PWidget(scrollbarv), FALSE);
603 g_signal_connect(G_OBJECT(adjustmentv), "value_changed",
604 G_CALLBACK(ScrollSignal), this);
605 gtk_widget_set_parent(PWidget(scrollbarv), PWidget(wMain));
606 gtk_widget_show(PWidget(scrollbarv));
607
608 adjustmenth = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 101.0, 1.0, 20.0, 20.0));
609#if GTK_CHECK_VERSION(3,0,0)
610 scrollbarh = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT(adjustmenth));
611#else
612 scrollbarh = gtk_hscrollbar_new(GTK_ADJUSTMENT(adjustmenth));
613#endif
614 gtk_widget_set_can_focus(PWidget(scrollbarh), FALSE);
615 g_signal_connect(G_OBJECT(adjustmenth), "value_changed",
616 G_CALLBACK(ScrollHSignal), this);
617 gtk_widget_set_parent(PWidget(scrollbarh), PWidget(wMain));
618 gtk_widget_show(PWidget(scrollbarh));
619
620 gtk_widget_grab_focus(PWidget(wMain));
621
622 gtk_drag_dest_set(GTK_WIDGET(PWidget(wMain)),
623 GTK_DEST_DEFAULT_ALL, clipboardPasteTargets, nClipboardPasteTargets,
625
626 /* create pre-edit window */
627 wPreedit = gtk_window_new(GTK_WINDOW_POPUP);
628 wPreeditDraw = gtk_drawing_area_new();
629 GtkWidget *predrw = PWidget(wPreeditDraw); // No code inside the G_OBJECT macro
630#if GTK_CHECK_VERSION(3,0,0)
631 g_signal_connect(G_OBJECT(predrw), "draw",
632 G_CALLBACK(DrawPreedit), this);
633#else
634 g_signal_connect(G_OBJECT(predrw), "expose_event",
635 G_CALLBACK(ExposePreedit), this);
636#endif
637 gtk_container_add(GTK_CONTAINER(PWidget(wPreedit)), predrw);
638 gtk_widget_show(predrw);
639
640 // Set caret period based on GTK settings
641 gboolean blinkOn = false;
642 if (g_object_class_find_property(G_OBJECT_GET_CLASS(
643 G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink")) {
644 g_object_get(G_OBJECT(
645 gtk_settings_get_default()), "gtk-cursor-blink", &blinkOn, nullptr);
646 }
647 if (blinkOn &&
648 g_object_class_find_property(G_OBJECT_GET_CLASS(
649 G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink-time")) {
650 gint value;
651 g_object_get(G_OBJECT(
652 gtk_settings_get_default()), "gtk-cursor-blink-time", &value, nullptr);
653 caret.period = static_cast<int>(value / 1.75);
654 } else {
655 caret.period = 0;
656 }
657
658 for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) {
659 timers[tr].reason = tr;
660 timers[tr].scintilla = this;
661 }
666}
667
669 for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) {
671 }
672 if (accessible) {
673 gtk_accessible_set_widget(GTK_ACCESSIBLE(accessible), nullptr);
674 g_object_unref(accessible);
675 accessible = nullptr;
676 }
677
679}
680
682 if ((paintState == painting) && !paintingAllText) {
683 repaintFullWindow = true;
684 }
685 return false;
686}
687
690 wText.SetCursor(c);
691 else
693}
694
696 return gtk_drag_check_threshold(GTK_WIDGET(PWidget(wMain)),
697 ptStart.x, ptStart.y, ptNow.x, ptNow.y);
698}
699
702 dragWasDropped = false;
704 GtkTargetList *tl = gtk_target_list_new(clipboardCopyTargets, nClipboardCopyTargets);
705#if GTK_CHECK_VERSION(3,10,0)
706 gtk_drag_begin_with_coordinates(GTK_WIDGET(PWidget(wMain)),
707 tl,
710 evbtn,
711 -1, -1);
712#else
713 gtk_drag_begin(GTK_WIDGET(PWidget(wMain)),
714 tl,
717 evbtn);
718#endif
719}
720
721namespace Scintilla {
722std::string ConvertText(const char *s, size_t len, const char *charSetDest,
723 const char *charSetSource, bool transliterations, bool silent) {
724 // s is not const because of different versions of iconv disagreeing about const
725 std::string destForm;
726 Converter conv(charSetDest, charSetSource, transliterations);
727 if (conv) {
728 gsize outLeft = len*3+1;
729 destForm = std::string(outLeft, '\0');
730 // g_iconv does not actually write to its input argument so safe to cast away const
731 char *pin = const_cast<char *>(s);
732 gsize inLeft = len;
733 char *putf = &destForm[0];
734 char *pout = putf;
735 const gsize conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
736 if (conversions == sizeFailure) {
737 if (!silent) {
738 if (len == 1)
739 fprintf(stderr, "iconv %s->%s failed for %0x '%s'\n",
740 charSetSource, charSetDest, (unsigned char)(*s), s);
741 else
742 fprintf(stderr, "iconv %s->%s failed for %s\n",
743 charSetSource, charSetDest, s);
744 }
745 destForm = std::string();
746 } else {
747 destForm.resize(pout - putf);
748 }
749 } else {
750 fprintf(stderr, "Can not iconv %s %s\n", charSetDest, charSetSource);
751 }
752 return destForm;
753}
754}
755
756// Returns the target converted to UTF8.
757// Return the length in bytes.
759 const Sci::Position targetLength = targetRange.Length();
760 if (IsUnicodeMode()) {
761 if (text) {
762 pdoc->GetCharRange(text, targetRange.start.Position(), targetLength);
763 }
764 } else {
765 // Need to convert
766 const char *charSetBuffer = CharacterSetID();
767 if (*charSetBuffer) {
769 std::string tmputf = ConvertText(&s[0], targetLength, "UTF-8", charSetBuffer, false);
770 if (text) {
771 memcpy(text, tmputf.c_str(), tmputf.length());
772 }
773 return tmputf.length();
774 } else {
775 if (text) {
776 pdoc->GetCharRange(text, targetRange.start.Position(), targetLength);
777 }
778 }
779 }
780 return targetLength;
781}
782
783// Translates a nul terminated UTF8 string into the document encoding.
784// Return the length of the result in bytes.
785Sci::Position ScintillaGTK::EncodedFromUTF8(const char *utf8, char *encoded) const {
786 const Sci::Position inputLength = (lengthForEncode >= 0) ? lengthForEncode : strlen(utf8);
787 if (IsUnicodeMode()) {
788 if (encoded) {
789 memcpy(encoded, utf8, inputLength);
790 }
791 return inputLength;
792 } else {
793 // Need to convert
794 const char *charSetBuffer = CharacterSetID();
795 if (*charSetBuffer) {
796 std::string tmpEncoded = ConvertText(utf8, inputLength, charSetBuffer, "UTF-8", true);
797 if (encoded) {
798 memcpy(encoded, tmpEncoded.c_str(), tmpEncoded.length());
799 }
800 return tmpEncoded.length();
801 } else {
802 if (encoded) {
803 memcpy(encoded, utf8, inputLength);
804 }
805 return inputLength;
806 }
807 }
808 // Fail
809 return 0;
810}
811
812bool ScintillaGTK::ValidCodePage(int codePage) const {
813 return codePage == 0
814 || codePage == SC_CP_UTF8
815 || codePage == 932
816 || codePage == 936
817 || codePage == 949
818 || codePage == 950
819 || codePage == 1361;
820}
821
822sptr_t ScintillaGTK::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
823 try {
824 switch (iMessage) {
825
826 case SCI_GRABFOCUS:
827 gtk_widget_grab_focus(PWidget(wMain));
828 break;
829
831 return reinterpret_cast<sptr_t>(DirectFunction);
832
834 return reinterpret_cast<sptr_t>(this);
835
836 case SCI_TARGETASUTF8:
837 return TargetAsUTF8(CharPtrFromSPtr(lParam));
838
841 CharPtrFromSPtr(lParam));
842
845 break;
846
849
850 case SCI_SETREADONLY: {
851 const sptr_t ret = ScintillaBase::WndProc(iMessage, wParam, lParam);
852 if (accessible) {
854 if (sciAccessible) {
855 sciAccessible->NotifyReadOnly();
856 }
857 }
858 return ret;
859 }
860
863
865 accessibilityEnabled = wParam;
866 if (accessible) {
868 if (sciAccessible) {
870 }
871 }
872 break;
873
874 default:
875 return ScintillaBase::WndProc(iMessage, wParam, lParam);
876 }
877 } catch (std::bad_alloc &) {
879 } catch (...) {
881 }
882 return 0;
883}
884
886 return 0;
887}
888
890 return timers[reason].timer != 0;
891}
892
893void ScintillaGTK::FineTickerStart(TickReason reason, int millis, int /* tolerance */) {
894 FineTickerCancel(reason);
895 timers[reason].timer = gdk_threads_add_timeout(millis, TimeOut, &timers[reason]);
896}
897
899 if (timers[reason].timer) {
900 g_source_remove(timers[reason].timer);
901 timers[reason].timer = 0;
902 }
903}
904
906 if (on) {
907 // Start idler, if it's not running.
908 if (!idler.state) {
909 idler.state = true;
910 idler.idlerID = GUINT_TO_POINTER(
911 gdk_threads_add_idle_full(G_PRIORITY_DEFAULT_IDLE, IdleCallback, this, nullptr));
912 }
913 } else {
914 // Stop idler, if it's running
915 if (idler.state) {
916 idler.state = false;
917 g_source_remove(GPOINTER_TO_UINT(idler.idlerID));
918 }
919 }
920 return true;
921}
922
924 if (mouseDownCaptures) {
925 if (on) {
926 gtk_grab_add(GTK_WIDGET(PWidget(wMain)));
927 } else {
928 gtk_grab_remove(GTK_WIDGET(PWidget(wMain)));
929 }
930 }
931 capturedMouse = on;
932}
933
935 return capturedMouse;
936}
937
938#if GTK_CHECK_VERSION(3,0,0)
939
940// Is crcTest completely in crcContainer?
941static bool CRectContains(const cairo_rectangle_t &crcContainer, const cairo_rectangle_t &crcTest) {
942 return
943 (crcTest.x >= crcContainer.x) && ((crcTest.x + crcTest.width) <= (crcContainer.x + crcContainer.width)) &&
944 (crcTest.y >= crcContainer.y) && ((crcTest.y + crcTest.height) <= (crcContainer.y + crcContainer.height));
945}
946
947// Is crcTest completely in crcListContainer?
948// May incorrectly return false if complex shape
949static bool CRectListContains(const cairo_rectangle_list_t *crcListContainer, const cairo_rectangle_t &crcTest) {
950 for (int r=0; r<crcListContainer->num_rectangles; r++) {
951 if (CRectContains(crcListContainer->rectangles[r], crcTest))
952 return true;
953 }
954 return false;
955}
956
957#endif
958
960 // This allows optimization when a rectangle is completely in the update region.
961 // It is OK to return false when too difficult to determine as that just performs extra drawing
962 bool contains = true;
963 if (paintState == painting) {
964 if (!rcPaint.Contains(rc)) {
965 contains = false;
966 } else if (rgnUpdate) {
967#if GTK_CHECK_VERSION(3,0,0)
968 cairo_rectangle_t grc = {rc.left, rc.top,
969 rc.right - rc.left, rc.bottom - rc.top
970 };
971 contains = CRectListContains(rgnUpdate, grc);
972#else
973 GdkRectangle grc = {static_cast<gint>(rc.left), static_cast<gint>(rc.top),
974 static_cast<gint>(rc.right - rc.left), static_cast<gint>(rc.bottom - rc.top)
975 };
976 if (gdk_region_rect_in(rgnUpdate, &grc) != GDK_OVERLAP_RECTANGLE_IN) {
977 contains = false;
978 }
979#endif
980 }
981 }
982 return contains;
983}
984
985// Redraw all of text area. This paint will not be abandoned.
988}
989
996 // Move to origin
997 rc.right -= rc.left;
998 rc.bottom -= rc.top;
999 if (rc.bottom < 0)
1000 rc.bottom = 0;
1001 if (rc.right < 0)
1002 rc.right = 0;
1003 rc.left = 0;
1004 rc.top = 0;
1005 return rc;
1006}
1007
1010
1011#if GTK_CHECK_VERSION(3,22,0)
1012 Redraw();
1013#else
1014 GtkWidget *wi = PWidget(wText);
1015 if (IS_WIDGET_REALIZED(wi)) {
1016 const int diff = vs.lineHeight * -linesToMove;
1017 gdk_window_scroll(WindowFromWidget(wi), 0, -diff);
1018 gdk_window_process_updates(WindowFromWidget(wi), FALSE);
1019 }
1020#endif
1021}
1022
1024 DwellEnd(true);
1025 gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmentv), topLine);
1026}
1027
1029 DwellEnd(true);
1030 gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmenth), xOffset);
1031}
1032
1034 bool modified = false;
1035 const int pageScroll = LinesToScroll();
1036
1037 if (gtk_adjustment_get_upper(adjustmentv) != (nMax + 1) ||
1038 gtk_adjustment_get_page_size(adjustmentv) != nPage ||
1039 gtk_adjustment_get_page_increment(adjustmentv) != pageScroll) {
1040 gtk_adjustment_set_upper(adjustmentv, nMax + 1);
1041 gtk_adjustment_set_page_size(adjustmentv, nPage);
1042 gtk_adjustment_set_page_increment(adjustmentv, pageScroll);
1043#if !GTK_CHECK_VERSION(3,18,0)
1044 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv));
1045#endif
1046 modified = true;
1047 }
1048
1049 const PRectangle rcText = GetTextRectangle();
1050 int horizEndPreferred = scrollWidth;
1051 if (horizEndPreferred < 0)
1052 horizEndPreferred = 0;
1053 const unsigned int pageWidth = static_cast<unsigned int>(rcText.Width());
1054 const unsigned int pageIncrement = pageWidth / 3;
1055 const unsigned int charWidth = vs.styles[STYLE_DEFAULT].aveCharWidth;
1056 if (gtk_adjustment_get_upper(adjustmenth) != horizEndPreferred ||
1057 gtk_adjustment_get_page_size(adjustmenth) != pageWidth ||
1058 gtk_adjustment_get_page_increment(adjustmenth) != pageIncrement ||
1059 gtk_adjustment_get_step_increment(adjustmenth) != charWidth) {
1060 gtk_adjustment_set_upper(adjustmenth, horizEndPreferred);
1061 gtk_adjustment_set_page_size(adjustmenth, pageWidth);
1062 gtk_adjustment_set_page_increment(adjustmenth, pageIncrement);
1063 gtk_adjustment_set_step_increment(adjustmenth, charWidth);
1064#if !GTK_CHECK_VERSION(3,18,0)
1065 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth));
1066#endif
1067 modified = true;
1068 }
1069 if (modified && (paintState == painting)) {
1070 repaintFullWindow = true;
1071 }
1072
1073 return modified;
1074}
1075
1077 const PRectangle rc = wMain.GetClientPosition();
1078 Resize(static_cast<int>(rc.Width()), static_cast<int>(rc.Height()));
1079}
1080
1082 g_signal_emit(G_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL], 0,
1084}
1085
1087 if (commandEvents)
1088 g_signal_emit(G_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL], 0,
1091 Editor::NotifyFocus(focus);
1092}
1093
1095 scn.nmhdr.hwndFrom = PWidget(wMain);
1096 scn.nmhdr.idFrom = GetCtrlID();
1097 g_signal_emit(G_OBJECT(sci), scintilla_signals[NOTIFY_SIGNAL], 0,
1098 GetCtrlID(), &scn);
1099}
1100
1101void ScintillaGTK::NotifyKey(int key, int modifiers) {
1102 SCNotification scn = {};
1103 scn.nmhdr.code = SCN_KEY;
1104 scn.ch = key;
1105 scn.modifiers = modifiers;
1106
1107 NotifyParent(scn);
1108}
1109
1111 SCNotification scn = {};
1113 scn.text = list;
1114
1115 NotifyParent(scn);
1116}
1117
1118const char *CharacterSetID(int characterSet);
1119
1120const char *ScintillaGTK::CharacterSetID() const {
1122}
1123
1125 const char *charSet;
1126public:
1127 explicit CaseFolderDBCS(const char *charSet_) : charSet(charSet_) {
1128 StandardASCII();
1129 }
1130 size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) override {
1131 if ((lenMixed == 1) && (sizeFolded > 0)) {
1132 folded[0] = mapping[static_cast<unsigned char>(mixed[0])];
1133 return 1;
1134 } else if (*charSet) {
1135 std::string sUTF8 = ConvertText(mixed, lenMixed,
1136 "UTF-8", charSet, false);
1137 if (!sUTF8.empty()) {
1138 gchar *mapped = g_utf8_casefold(sUTF8.c_str(), sUTF8.length());
1139 size_t lenMapped = strlen(mapped);
1140 if (lenMapped < sizeFolded) {
1141 memcpy(folded, mapped, lenMapped);
1142 } else {
1143 folded[0] = '\0';
1144 lenMapped = 1;
1145 }
1146 g_free(mapped);
1147 return lenMapped;
1148 }
1149 }
1150 // Something failed so return a single NUL byte
1151 folded[0] = '\0';
1152 return 1;
1153 }
1154};
1155
1157 if (pdoc->dbcsCodePage == SC_CP_UTF8) {
1158 return new CaseFolderUnicode();
1159 } else {
1160 const char *charSetBuffer = CharacterSetID();
1161 if (charSetBuffer) {
1162 if (pdoc->dbcsCodePage == 0) {
1163 CaseFolderTable *pcf = new CaseFolderTable();
1164 pcf->StandardASCII();
1165 // Only for single byte encodings
1166 for (int i=0x80; i<0x100; i++) {
1167 char sCharacter[2] = "A";
1168 sCharacter[0] = i;
1169 // Silent as some bytes have no assigned character
1170 std::string sUTF8 = ConvertText(sCharacter, 1,
1171 "UTF-8", charSetBuffer, false, true);
1172 if (!sUTF8.empty()) {
1173 gchar *mapped = g_utf8_casefold(sUTF8.c_str(), sUTF8.length());
1174 if (mapped) {
1175 std::string mappedBack = ConvertText(mapped, strlen(mapped),
1176 charSetBuffer, "UTF-8", false, true);
1177 if ((mappedBack.length() == 1) && (mappedBack[0] != sCharacter[0])) {
1178 pcf->SetTranslation(sCharacter[0], mappedBack[0]);
1179 }
1180 g_free(mapped);
1181 }
1182 }
1183 }
1184 return pcf;
1185 } else {
1186 return new CaseFolderDBCS(charSetBuffer);
1187 }
1188 }
1189 return nullptr;
1190 }
1191}
1192
1193namespace {
1194
1195struct CaseMapper {
1196 gchar *mapped; // Must be freed with g_free
1197 CaseMapper(const std::string &sUTF8, bool toUpperCase) {
1198 if (toUpperCase) {
1199 mapped = g_utf8_strup(sUTF8.c_str(), sUTF8.length());
1200 } else {
1201 mapped = g_utf8_strdown(sUTF8.c_str(), sUTF8.length());
1202 }
1203 }
1204 // Deleted so CaseMapper objects can not be copied.
1205 CaseMapper(const CaseMapper&) = delete;
1206 CaseMapper(CaseMapper&&) = delete;
1207 CaseMapper&operator=(const CaseMapper&) = delete;
1208 CaseMapper&operator=(CaseMapper&&) = delete;
1209 ~CaseMapper() {
1210 g_free(mapped);
1211 }
1212};
1213
1214}
1215
1216std::string ScintillaGTK::CaseMapString(const std::string &s, int caseMapping) {
1217 if ((s.size() == 0) || (caseMapping == cmSame))
1218 return s;
1219
1220 if (IsUnicodeMode()) {
1221 std::string retMapped(s.length() * maxExpansionCaseConversion, 0);
1222 const size_t lenMapped = CaseConvertString(&retMapped[0], retMapped.length(), s.c_str(), s.length(),
1223 (caseMapping == cmUpper) ? CaseConversionUpper : CaseConversionLower);
1224 retMapped.resize(lenMapped);
1225 return retMapped;
1226 }
1227
1228 const char *charSetBuffer = CharacterSetID();
1229
1230 if (!*charSetBuffer) {
1231 CaseMapper mapper(s, caseMapping == cmUpper);
1232 return std::string(mapper.mapped, strlen(mapper.mapped));
1233 } else {
1234 // Change text to UTF-8
1235 std::string sUTF8 = ConvertText(s.c_str(), s.length(),
1236 "UTF-8", charSetBuffer, false);
1237 CaseMapper mapper(sUTF8, caseMapping == cmUpper);
1238 return ConvertText(mapper.mapped, strlen(mapper.mapped), charSetBuffer, "UTF-8", false);
1239 }
1240}
1241
1242int ScintillaGTK::KeyDefault(int key, int modifiers) {
1243 // Pass up to container in case it is an accelerator
1244 NotifyKey(key, modifiers);
1245 return 0;
1246}
1247
1249 SelectionText *clipText = new SelectionText();
1250 clipText->Copy(selectedText);
1251 StoreOnClipboard(clipText);
1252}
1253
1255 if (!sel.Empty()) {
1256 SelectionText *clipText = new SelectionText();
1257 CopySelectionRange(clipText);
1258 StoreOnClipboard(clipText);
1259#if PLAT_GTK_WIN32
1260 if (sel.IsRectangular()) {
1261 ::OpenClipboard(NULL);
1262 ::SetClipboardData(cfColumnSelect, 0);
1263 ::CloseClipboard();
1264 }
1265#endif
1266 }
1267}
1268
1269namespace {
1270
1271// Helper class for the asynchronous paste not to risk calling in a destroyed ScintillaGTK
1272
1273class SelectionReceiver : GObjectWatcher {
1275
1276 void Destroyed() noexcept override {
1277 sci = nullptr;
1278 }
1279
1280public:
1281 SelectionReceiver(ScintillaGTK *sci_) :
1282 GObjectWatcher(G_OBJECT(sci_->MainObject())),
1283 sci(sci_) {
1284 }
1285
1286 static void ClipboardReceived(GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data) {
1287 SelectionReceiver *self = static_cast<SelectionReceiver *>(data);
1288 if (self->sci) {
1289 self->sci->ReceivedClipboard(clipboard, selection_data);
1290 }
1291 delete self;
1292 }
1293};
1294
1295}
1296
1297void ScintillaGTK::RequestSelection(GdkAtom atomSelection) {
1299 GtkClipboard *clipBoard =
1300 gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain)), atomSelection);
1301 if (clipBoard) {
1302 gtk_clipboard_request_contents(clipBoard, atomSought,
1303 SelectionReceiver::ClipboardReceived,
1304 new SelectionReceiver(this));
1305 }
1306}
1307
1309 RequestSelection(GDK_SELECTION_CLIPBOARD);
1310}
1311
1313 if (!ct.wCallTip.Created()) {
1314 ct.wCallTip = gtk_window_new(GTK_WINDOW_POPUP);
1315 ct.wDraw = gtk_drawing_area_new();
1316 GtkWidget *widcdrw = PWidget(ct.wDraw); // // No code inside the G_OBJECT macro
1317 gtk_container_add(GTK_CONTAINER(PWidget(ct.wCallTip)), widcdrw);
1318#if GTK_CHECK_VERSION(3,0,0)
1319 g_signal_connect(G_OBJECT(widcdrw), "draw",
1320 G_CALLBACK(ScintillaGTK::DrawCT), &ct);
1321#else
1322 g_signal_connect(G_OBJECT(widcdrw), "expose_event",
1323 G_CALLBACK(ScintillaGTK::ExposeCT), &ct);
1324#endif
1325 g_signal_connect(G_OBJECT(widcdrw), "button_press_event",
1326 G_CALLBACK(ScintillaGTK::PressCT), this);
1327 gtk_widget_set_events(widcdrw,
1328 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
1329 GtkWidget *top = gtk_widget_get_toplevel(PWidget(wMain));
1330 gtk_window_set_transient_for(GTK_WINDOW(PWidget(ct.wCallTip)), GTK_WINDOW(top));
1331 }
1332 const int width = static_cast<int>(rc.Width());
1333 const int height = static_cast<int>(rc.Height());
1334 gtk_widget_set_size_request(PWidget(ct.wDraw), width, height);
1335 ct.wDraw.Show();
1336 if (PWindow(ct.wCallTip)) {
1337 gdk_window_resize(PWindow(ct.wCallTip), width, height);
1338 }
1339}
1340
1341void ScintillaGTK::AddToPopUp(const char *label, int cmd, bool enabled) {
1342 GtkWidget *menuItem;
1343 if (label[0])
1344 menuItem = gtk_menu_item_new_with_label(label);
1345 else
1346 menuItem = gtk_separator_menu_item_new();
1347 gtk_menu_shell_append(GTK_MENU_SHELL(popup.GetID()), menuItem);
1348 g_object_set_data(G_OBJECT(menuItem), "CmdNum", GINT_TO_POINTER(cmd));
1349 g_signal_connect(G_OBJECT(menuItem), "activate", G_CALLBACK(PopUpCB), this);
1350
1351 if (cmd) {
1352 if (menuItem)
1353 gtk_widget_set_sensitive(menuItem, enabled);
1354 }
1355}
1356
1358 return (wSelection.Created() &&
1359 (gdk_selection_owner_get(GDK_SELECTION_PRIMARY) == PWindow(wSelection)) &&
1360 (PWindow(wSelection) != nullptr));
1361}
1362
1364 // X Windows has a 'primary selection' as well as the clipboard.
1365 // Whenever the user selects some text, we become the primary selection
1366 if (!sel.Empty() && wSelection.Created() && IS_WIDGET_REALIZED(GTK_WIDGET(PWidget(wSelection)))) {
1367 primarySelection = true;
1368 gtk_selection_owner_set(GTK_WIDGET(PWidget(wSelection)),
1369 GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
1370 primary.Clear();
1371 } else if (OwnPrimarySelection()) {
1372 primarySelection = true;
1373 if (primary.Empty())
1374 gtk_selection_owner_set(nullptr, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
1375 } else {
1376 primarySelection = false;
1377 primary.Clear();
1378 }
1379}
1380
1381bool ScintillaGTK::IsStringAtom(GdkAtom type) {
1382 return (type == GDK_TARGET_STRING) || (type == atomUTF8) || (type == atomUTF8Mime);
1383}
1384
1385static const guchar *DataOfGSD(GtkSelectionData *sd) noexcept { return gtk_selection_data_get_data(sd); }
1386static gint LengthOfGSD(GtkSelectionData *sd) noexcept { return gtk_selection_data_get_length(sd); }
1387static GdkAtom TypeOfGSD(GtkSelectionData *sd) noexcept { return gtk_selection_data_get_data_type(sd); }
1388static GdkAtom SelectionOfGSD(GtkSelectionData *sd) noexcept { return gtk_selection_data_get_selection(sd); }
1389
1390// Detect rectangular text, convert line ends to current mode, convert from or to UTF-8
1391void ScintillaGTK::GetGtkSelectionText(GtkSelectionData *selectionData, SelectionText &selText) {
1392 const char *data = reinterpret_cast<const char *>(DataOfGSD(selectionData));
1393 int len = LengthOfGSD(selectionData);
1394 GdkAtom selectionTypeData = TypeOfGSD(selectionData);
1395
1396 // Return empty string if selection is not a string
1397 if (!IsStringAtom(selectionTypeData)) {
1398 selText.Clear();
1399 return;
1400 }
1401
1402 // Check for "\n\0" ending to string indicating that selection is rectangular
1403 bool isRectangular;
1404#if PLAT_GTK_WIN32
1405 isRectangular = ::IsClipboardFormatAvailable(cfColumnSelect) != 0;
1406#else
1407 isRectangular = ((len > 2) && (data[len - 1] == 0 && data[len - 2] == '\n'));
1408 if (isRectangular)
1409 len--; // Forget the extra '\0'
1410#endif
1411
1412#if PLAT_GTK_WIN32
1413 // Win32 includes an ending '\0' byte in 'len' for clipboard text from
1414 // external applications; ignore it.
1415 if ((len > 0) && (data[len - 1] == '\0'))
1416 len--;
1417#endif
1418
1419 std::string dest(data, len);
1420 if (selectionTypeData == GDK_TARGET_STRING) {
1421 if (IsUnicodeMode()) {
1422 // Unknown encoding so assume in Latin1
1423 dest = UTF8FromLatin1(dest.c_str(), dest.length());
1424 selText.Copy(dest, SC_CP_UTF8, 0, isRectangular, false);
1425 } else {
1426 // Assume buffer is in same encoding as selection
1427 selText.Copy(dest, pdoc->dbcsCodePage,
1428 vs.styles[STYLE_DEFAULT].characterSet, isRectangular, false);
1429 }
1430 } else { // UTF-8
1431 const char *charSetBuffer = CharacterSetID();
1432 if (!IsUnicodeMode() && *charSetBuffer) {
1433 // Convert to locale
1434 dest = ConvertText(dest.c_str(), dest.length(), charSetBuffer, "UTF-8", true);
1435 selText.Copy(dest, pdoc->dbcsCodePage,
1436 vs.styles[STYLE_DEFAULT].characterSet, isRectangular, false);
1437 } else {
1438 selText.Copy(dest, SC_CP_UTF8, 0, isRectangular, false);
1439 }
1440 }
1441}
1442
1443void ScintillaGTK::InsertSelection(GtkClipboard *clipBoard, GtkSelectionData *selectionData) {
1444 const gint length = gtk_selection_data_get_length(selectionData);
1445 if (length >= 0) {
1446 GdkAtom selection = gtk_selection_data_get_selection(selectionData);
1447 SelectionText selText;
1448 GetGtkSelectionText(selectionData, selText);
1449
1450 UndoGroup ug(pdoc);
1451 if (selection == GDK_SELECTION_CLIPBOARD) {
1453 }
1454
1455 InsertPasteShape(selText.Data(), selText.Length(),
1458 } else {
1459 GdkAtom target = gtk_selection_data_get_target(selectionData);
1460 if (target == atomUTF8) {
1461 // In case data is actually only stored as text/plain;charset=utf-8 not UTF8_STRING
1462 gtk_clipboard_request_contents(clipBoard, atomUTF8Mime,
1463 SelectionReceiver::ClipboardReceived,
1464 new SelectionReceiver(this)
1465 );
1466 }
1467 }
1468 Redraw();
1469}
1470
1471GObject *ScintillaGTK::MainObject() const noexcept {
1472 return G_OBJECT(PWidget(wMain));
1473}
1474
1475void ScintillaGTK::ReceivedClipboard(GtkClipboard *clipBoard, GtkSelectionData *selection_data) noexcept {
1476 try {
1477 InsertSelection(clipBoard, selection_data);
1478 } catch (...) {
1479 errorStatus = SC_STATUS_FAILURE;
1480 }
1481}
1482
1483void ScintillaGTK::ReceivedSelection(GtkSelectionData *selection_data) {
1484 try {
1485 if ((SelectionOfGSD(selection_data) == GDK_SELECTION_CLIPBOARD) ||
1486 (SelectionOfGSD(selection_data) == GDK_SELECTION_PRIMARY)) {
1487 if ((atomSought == atomUTF8) && (LengthOfGSD(selection_data) <= 0)) {
1489 gtk_selection_convert(GTK_WIDGET(PWidget(wMain)),
1490 SelectionOfGSD(selection_data), atomSought, GDK_CURRENT_TIME);
1491 } else if ((LengthOfGSD(selection_data) > 0) && IsStringAtom(TypeOfGSD(selection_data))) {
1492 GtkClipboard *clipBoard = gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain)), SelectionOfGSD(selection_data));
1493 InsertSelection(clipBoard, selection_data);
1494 }
1495 }
1496// else fprintf(stderr, "Target non string %d %d\n", (int)(selection_data->type),
1497// (int)(atomUTF8));
1498 } catch (...) {
1500 }
1501}
1502
1503void ScintillaGTK::ReceivedDrop(GtkSelectionData *selection_data) {
1504 dragWasDropped = true;
1505 if (TypeOfGSD(selection_data) == atomUriList || TypeOfGSD(selection_data) == atomDROPFILES_DND) {
1506 const char *data = reinterpret_cast<const char *>(DataOfGSD(selection_data));
1507 std::vector<char> drop(data, data + LengthOfGSD(selection_data));
1508 drop.push_back('\0');
1509 NotifyURIDropped(&drop[0]);
1510 } else if (IsStringAtom(TypeOfGSD(selection_data))) {
1511 if (LengthOfGSD(selection_data) > 0) {
1512 SelectionText selText;
1513 GetGtkSelectionText(selection_data, selText);
1514 DropAt(posDrop, selText.Data(), selText.Length(), false, selText.rectangular);
1515 }
1516 } else if (LengthOfGSD(selection_data) > 0) {
1517 //~ fprintf(stderr, "ReceivedDrop other %p\n", static_cast<void *>(selection_data->type));
1518 }
1519 Redraw();
1520}
1521
1522
1523
1524void ScintillaGTK::GetSelection(GtkSelectionData *selection_data, guint info, SelectionText *text) {
1525#if PLAT_GTK_WIN32
1526 // GDK on Win32 expands any \n into \r\n, so make a copy of
1527 // the clip text now with newlines converted to \n. Use { } to hide symbols
1528 // from code below
1529 std::unique_ptr<SelectionText> newline_normalized;
1530 {
1531 std::string tmpstr = Document::TransformLineEnds(text->Data(), text->Length(), SC_EOL_LF);
1532 newline_normalized.reset(new SelectionText());
1533 newline_normalized->Copy(tmpstr, SC_CP_UTF8, 0, text->rectangular, false);
1534 text = newline_normalized.get();
1535 }
1536#endif
1537
1538 // Convert text to utf8 if it isn't already
1539 std::unique_ptr<SelectionText> converted;
1540 if ((text->codePage != SC_CP_UTF8) && (info == TARGET_UTF8_STRING)) {
1541 const char *charSet = ::CharacterSetID(text->characterSet);
1542 if (*charSet) {
1543 std::string tmputf = ConvertText(text->Data(), text->Length(), "UTF-8", charSet, false);
1544 converted = Sci::make_unique<SelectionText>();
1545 converted->Copy(tmputf, SC_CP_UTF8, 0, text->rectangular, false);
1546 text = converted.get();
1547 }
1548 }
1549
1550 // Here is a somewhat evil kludge.
1551 // As I can not work out how to store data on the clipboard in multiple formats
1552 // and need some way to mark the clipping as being stream or rectangular,
1553 // the terminating \0 is included in the length for rectangular clippings.
1554 // All other tested applications behave benignly by ignoring the \0.
1555 // The #if is here because on Windows cfColumnSelect clip entry is used
1556 // instead as standard indicator of rectangularness (so no need to kludge)
1557 const char *textData = text->Data();
1558 int len = text->Length();
1559#if PLAT_GTK_WIN32 == 0
1560 if (text->rectangular)
1561 len++;
1562#endif
1563
1564 if (info == TARGET_UTF8_STRING) {
1565 gtk_selection_data_set_text(selection_data, textData, len);
1566 } else {
1567 gtk_selection_data_set(selection_data,
1568 static_cast<GdkAtom>(GDK_SELECTION_TYPE_STRING),
1569 8, reinterpret_cast<const guchar *>(textData), len);
1570 }
1571}
1572
1574 GtkClipboard *clipBoard =
1575 gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain)), GDK_SELECTION_CLIPBOARD);
1576 if (clipBoard == nullptr) // Occurs if widget isn't in a toplevel
1577 return;
1578
1579 if (gtk_clipboard_set_with_data(clipBoard, clipboardCopyTargets, nClipboardCopyTargets,
1581 gtk_clipboard_set_can_store(clipBoard, clipboardCopyTargets, nClipboardCopyTargets);
1582 }
1583}
1584
1585void ScintillaGTK::ClipboardGetSelection(GtkClipboard *, GtkSelectionData *selection_data, guint info, void *data) {
1586 GetSelection(selection_data, info, static_cast<SelectionText *>(data));
1587}
1588
1589void ScintillaGTK::ClipboardClearSelection(GtkClipboard *, void *data) {
1590 SelectionText *obj = static_cast<SelectionText *>(data);
1591 delete obj;
1592}
1593
1594void ScintillaGTK::UnclaimSelection(GdkEventSelection *selection_event) {
1595 try {
1596 //Platform::DebugPrintf("UnclaimSelection\n");
1597 if (selection_event->selection == GDK_SELECTION_PRIMARY) {
1598 //Platform::DebugPrintf("UnclaimPrimarySelection\n");
1599 if (!OwnPrimarySelection()) {
1600 primary.Clear();
1601 primarySelection = false;
1602 FullPaint();
1603 }
1604 }
1605 } catch (...) {
1607 }
1608}
1609
1610void ScintillaGTK::PrimarySelection(GtkWidget *, GtkSelectionData *selection_data, guint info, guint, ScintillaGTK *sciThis) {
1611 try {
1612 if (SelectionOfGSD(selection_data) == GDK_SELECTION_PRIMARY) {
1613 if (sciThis->primary.Empty()) {
1614 sciThis->CopySelectionRange(&sciThis->primary);
1615 }
1616 sciThis->GetSelection(selection_data, info, &sciThis->primary);
1617 }
1618 } catch (...) {
1619 sciThis->errorStatus = SC_STATUS_FAILURE;
1620 }
1621}
1622
1623gboolean ScintillaGTK::PrimaryClear(GtkWidget *widget, GdkEventSelection *event, ScintillaGTK *sciThis) {
1624 sciThis->UnclaimSelection(event);
1625 if (GTK_WIDGET_CLASS(sciThis->parentClass)->selection_clear_event) {
1626 return GTK_WIDGET_CLASS(sciThis->parentClass)->selection_clear_event(widget, event);
1627 }
1628 return TRUE;
1629}
1630
1631void ScintillaGTK::Resize(int width, int height) {
1632 //Platform::DebugPrintf("Resize %d %d\n", width, height);
1633 //printf("Resize %d %d\n", width, height);
1634
1635 // GTK+ 3 warns when we allocate smaller than the minimum allocation,
1636 // so we use these variables to store the minimum scrollbar lengths.
1637 int minVScrollBarHeight, minHScrollBarWidth;
1638
1639 // Not always needed, but some themes can have different sizes of scrollbars
1640#if GTK_CHECK_VERSION(3,0,0)
1641 GtkRequisition minimum, requisition;
1642 gtk_widget_get_preferred_size(PWidget(scrollbarv), &minimum, &requisition);
1643 minVScrollBarHeight = minimum.height;
1644 verticalScrollBarWidth = requisition.width;
1645 gtk_widget_get_preferred_size(PWidget(scrollbarh), &minimum, &requisition);
1646 minHScrollBarWidth = minimum.width;
1647 horizontalScrollBarHeight = requisition.height;
1648#else
1649 minVScrollBarHeight = minHScrollBarWidth = 1;
1650 verticalScrollBarWidth = GTK_WIDGET(PWidget(scrollbarv))->requisition.width;
1651 horizontalScrollBarHeight = GTK_WIDGET(PWidget(scrollbarh))->requisition.height;
1652#endif
1653
1654 // These allocations should never produce negative sizes as they would wrap around to huge
1655 // unsigned numbers inside GTK+ causing warnings.
1656 const bool showSBHorizontal = horizontalScrollBarVisible && !Wrapping();
1657
1658 GtkAllocation alloc = {};
1659 if (showSBHorizontal) {
1660 gtk_widget_show(GTK_WIDGET(PWidget(scrollbarh)));
1661 alloc.x = 0;
1662 alloc.y = height - horizontalScrollBarHeight;
1663 alloc.width = std::max(minHScrollBarWidth, width - verticalScrollBarWidth);
1664 alloc.height = horizontalScrollBarHeight;
1665 gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarh)), &alloc);
1666 } else {
1667 gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarh)));
1668 horizontalScrollBarHeight = 0; // in case horizontalScrollBarVisible is true.
1669 }
1670
1672 gtk_widget_show(GTK_WIDGET(PWidget(scrollbarv)));
1673 alloc.x = width - verticalScrollBarWidth;
1674 alloc.y = 0;
1675 alloc.width = verticalScrollBarWidth;
1676 alloc.height = std::max(minVScrollBarHeight, height - horizontalScrollBarHeight);
1677 gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarv)), &alloc);
1678 } else {
1679 gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarv)));
1681 }
1683 ChangeSize();
1684 }
1685
1686 alloc.x = 0;
1687 alloc.y = 0;
1688 alloc.width = 1;
1689 alloc.height = 1;
1690#if GTK_CHECK_VERSION(3, 0, 0)
1691 // please GTK 3.20 and ask wText what size it wants, although we know it doesn't really need
1692 // anything special as it's ours.
1693 gtk_widget_get_preferred_size(PWidget(wText), &requisition, nullptr);
1694 alloc.width = requisition.width;
1695 alloc.height = requisition.height;
1696#endif
1697 alloc.width = std::max(alloc.width, width - verticalScrollBarWidth);
1698 alloc.height = std::max(alloc.height, height - horizontalScrollBarHeight);
1699 gtk_widget_size_allocate(GTK_WIDGET(PWidget(wText)), &alloc);
1700}
1701
1702namespace {
1703
1704void SetAdjustmentValue(GtkAdjustment *object, int value) noexcept {
1705 GtkAdjustment *adjustment = GTK_ADJUSTMENT(object);
1706 const int maxValue = static_cast<int>(
1707 gtk_adjustment_get_upper(adjustment) - gtk_adjustment_get_page_size(adjustment));
1708
1709 if (value > maxValue)
1710 value = maxValue;
1711 if (value < 0)
1712 value = 0;
1713 gtk_adjustment_set_value(adjustment, value);
1714}
1715
1716int modifierTranslated(int sciModifier) noexcept {
1717 switch (sciModifier) {
1718 case SCMOD_SHIFT:
1719 return GDK_SHIFT_MASK;
1720 case SCMOD_CTRL:
1721 return GDK_CONTROL_MASK;
1722 case SCMOD_ALT:
1723 return GDK_MOD1_MASK;
1724 case SCMOD_SUPER:
1725 return GDK_MOD4_MASK;
1726 default:
1727 return 0;
1728 }
1729}
1730
1731Point PointOfEvent(const GdkEventButton *event) noexcept {
1732 // Use floor as want to round in the same direction (-infinity) so
1733 // there is no stickiness crossing 0.0.
1734 return Point(static_cast<XYPOSITION>(std::floor(event->x)), static_cast<XYPOSITION>(std::floor(event->y)));
1735}
1736
1737}
1738
1739gint ScintillaGTK::PressThis(GdkEventButton *event) {
1740 try {
1741 //Platform::DebugPrintf("Press %x time=%d state = %x button = %x\n",this,event->time, event->state, event->button);
1742 // Do not use GTK+ double click events as Scintilla has its own double click detection
1743 if (event->type != GDK_BUTTON_PRESS)
1744 return FALSE;
1745
1746 if (evbtn) {
1747 gdk_event_free(evbtn);
1748 }
1749 evbtn = gdk_event_copy(reinterpret_cast<GdkEvent *>(event));
1750 buttonMouse = event->button;
1751 const Point pt = PointOfEvent(event);
1752 const PRectangle rcClient = GetClientRectangle();
1753 //Platform::DebugPrintf("Press %0d,%0d in %0d,%0d %0d,%0d\n",
1754 // pt.x, pt.y, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1755 if ((pt.x > rcClient.right) || (pt.y > rcClient.bottom)) {
1756 Platform::DebugPrintf("Bad location\n");
1757 return FALSE;
1758 }
1759
1760 const bool shift = (event->state & GDK_SHIFT_MASK) != 0;
1761 bool ctrl = (event->state & GDK_CONTROL_MASK) != 0;
1762 // On X, instead of sending literal modifiers use the user specified
1763 // modifier, defaulting to control instead of alt.
1764 // This is because most X window managers grab alt + click for moving
1765 const bool alt = (event->state & modifierTranslated(rectangularSelectionModifier)) != 0;
1766
1767 gtk_widget_grab_focus(PWidget(wMain));
1768 if (event->button == 1) {
1769#if PLAT_GTK_MACOSX
1770 const bool meta = ctrl;
1771 // GDK reports the Command modifier key as GDK_MOD2_MASK for button events,
1772 // not GDK_META_MASK like in key events.
1773 ctrl = (event->state & GDK_MOD2_MASK) != 0;
1774#else
1775 const bool meta = false;
1776#endif
1777 ButtonDownWithModifiers(pt, event->time, ModifierFlags(shift, ctrl, alt, meta));
1778 } else if (event->button == 2) {
1779 // Grab the primary selection if it exists
1780 const SelectionPosition pos = SPositionFromLocation(pt, false, false, UserVirtualSpace());
1783
1784 sel.Clear();
1786 RequestSelection(GDK_SELECTION_PRIMARY);
1787 } else if (event->button == 3) {
1788 if (!PointInSelection(pt))
1790 if (ShouldDisplayPopup(pt)) {
1791 // PopUp menu
1792 // Convert to screen
1793 int ox = 0;
1794 int oy = 0;
1795 gdk_window_get_origin(PWindow(wMain), &ox, &oy);
1796 ContextMenu(Point(pt.x + ox, pt.y + oy));
1797 } else {
1798#if PLAT_GTK_MACOSX
1799 const bool meta = ctrl;
1800 // GDK reports the Command modifier key as GDK_MOD2_MASK for button events,
1801 // not GDK_META_MASK like in key events.
1802 ctrl = (event->state & GDK_MOD2_MASK) != 0;
1803#else
1804 const bool meta = false;
1805#endif
1806 RightButtonDownWithModifiers(pt, event->time, ModifierFlags(shift, ctrl, alt, meta));
1807 return FALSE;
1808 }
1809 } else if (event->button == 4) {
1810 // Wheel scrolling up (only GTK 1.x does it this way)
1811 if (ctrl)
1812 SetAdjustmentValue(adjustmenth, xOffset - 6);
1813 else
1814 SetAdjustmentValue(adjustmentv, topLine - 3);
1815 } else if (event->button == 5) {
1816 // Wheel scrolling down (only GTK 1.x does it this way)
1817 if (ctrl)
1818 SetAdjustmentValue(adjustmenth, xOffset + 6);
1819 else
1820 SetAdjustmentValue(adjustmentv, topLine + 3);
1821 }
1822 } catch (...) {
1824 }
1825 return TRUE;
1826}
1827
1828gint ScintillaGTK::Press(GtkWidget *widget, GdkEventButton *event) {
1829 if (event->window != WindowFromWidget(widget))
1830 return FALSE;
1831 ScintillaGTK *sciThis = FromWidget(widget);
1832 return sciThis->PressThis(event);
1833}
1834
1835gint ScintillaGTK::MouseRelease(GtkWidget *widget, GdkEventButton *event) {
1836 ScintillaGTK *sciThis = FromWidget(widget);
1837 try {
1838 //Platform::DebugPrintf("Release %x %d %d\n",sciThis,event->time,event->state);
1839 if (!sciThis->HaveMouseCapture())
1840 return FALSE;
1841 if (event->button == 1) {
1842 Point pt = PointOfEvent(event);
1843 //Platform::DebugPrintf("Up %x %x %d %d %d\n",
1844 // sciThis,event->window,event->time, pt.x, pt.y);
1845 if (event->window != PWindow(sciThis->wMain))
1846 // If mouse released on scroll bar then the position is relative to the
1847 // scrollbar, not the drawing window so just repeat the most recent point.
1848 pt = sciThis->ptMouseLast;
1849 const int modifiers = ModifierFlags(
1850 (event->state & GDK_SHIFT_MASK) != 0,
1851 (event->state & GDK_CONTROL_MASK) != 0,
1852 (event->state & modifierTranslated(sciThis->rectangularSelectionModifier)) != 0);
1853 sciThis->ButtonUpWithModifiers(pt, event->time, modifiers);
1854 }
1855 } catch (...) {
1856 sciThis->errorStatus = SC_STATUS_FAILURE;
1857 }
1858 return FALSE;
1859}
1860
1861// win32gtk and GTK >= 2 use SCROLL_* events instead of passing the
1862// button4/5/6/7 events to the GTK app
1863gint ScintillaGTK::ScrollEvent(GtkWidget *widget, GdkEventScroll *event) {
1864 ScintillaGTK *sciThis = FromWidget(widget);
1865 try {
1866
1867 if (widget == nullptr || event == nullptr)
1868 return FALSE;
1869
1870#if defined(GDK_WINDOWING_WAYLAND)
1871 if (event->direction == GDK_SCROLL_SMOOTH && GDK_IS_WAYLAND_WINDOW(event->window)) {
1872 const int smoothScrollFactor = 4;
1873 sciThis->smoothScrollY += event->delta_y * smoothScrollFactor;
1874 sciThis->smoothScrollX += event->delta_x * smoothScrollFactor;;
1875 if (ABS(sciThis->smoothScrollY) >= 1.0) {
1876 const int scrollLines = std::trunc(sciThis->smoothScrollY);
1877 sciThis->ScrollTo(sciThis->topLine + scrollLines);
1878 sciThis->smoothScrollY -= scrollLines;
1879 }
1880 if (ABS(sciThis->smoothScrollX) >= 1.0) {
1881 const int scrollPixels = std::trunc(sciThis->smoothScrollX);
1882 sciThis->HorizontalScrollTo(sciThis->xOffset + scrollPixels);
1883 sciThis->smoothScrollX -= scrollPixels;
1884 }
1885 return TRUE;
1886 }
1887#endif
1888
1889 // Compute amount and direction to scroll (even tho on win32 there is
1890 // intensity of scrolling info in the native message, gtk doesn't
1891 // support this so we simulate similarly adaptive scrolling)
1892 // Note that this is disabled on OS X (Darwin) with the X11 backend
1893 // where the X11 server already has an adaptive scrolling algorithm
1894 // that fights with this one
1895 int cLineScroll;
1896#if defined(__APPLE__) && !defined(GDK_WINDOWING_QUARTZ)
1897 cLineScroll = sciThis->linesPerScroll;
1898 if (cLineScroll == 0)
1899 cLineScroll = 4;
1900 sciThis->wheelMouseIntensity = cLineScroll;
1901#else
1902 const gint64 curTime = g_get_monotonic_time();
1903 const gint64 timeDelta = curTime - sciThis->lastWheelMouseTime;
1904 if ((event->direction == sciThis->lastWheelMouseDirection) && (timeDelta < 250000)) {
1905 if (sciThis->wheelMouseIntensity < 12)
1906 sciThis->wheelMouseIntensity++;
1907 cLineScroll = sciThis->wheelMouseIntensity;
1908 } else {
1909 cLineScroll = sciThis->linesPerScroll;
1910 if (cLineScroll == 0)
1911 cLineScroll = 4;
1912 sciThis->wheelMouseIntensity = cLineScroll;
1913 }
1914 sciThis->lastWheelMouseTime = curTime;
1915#endif
1916 if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_LEFT) {
1917 cLineScroll *= -1;
1918 }
1919 sciThis->lastWheelMouseDirection = event->direction;
1920
1921 // Note: Unpatched versions of win32gtk don't set the 'state' value so
1922 // only regular scrolling is supported there. Also, unpatched win32gtk
1923 // issues spurious button 2 mouse events during wheeling, which can cause
1924 // problems (a patch for both was submitted by archaeopteryx.com on 13Jun2001)
1925
1926 // Data zoom not supported
1927 if (event->state & GDK_SHIFT_MASK) {
1928 return FALSE;
1929 }
1930
1931#if GTK_CHECK_VERSION(3,4,0)
1932 // Smooth scrolling not supported
1933 if (event->direction == GDK_SCROLL_SMOOTH) {
1934 return FALSE;
1935 }
1936#endif
1937
1938 // Horizontal scrolling
1939 if (event->direction == GDK_SCROLL_LEFT || event->direction == GDK_SCROLL_RIGHT) {
1940 sciThis->HorizontalScrollTo(sciThis->xOffset + cLineScroll);
1941
1942 // Text font size zoom
1943 } else if (event->state & GDK_CONTROL_MASK) {
1944 if (cLineScroll < 0) {
1945 sciThis->KeyCommand(SCI_ZOOMIN);
1946 } else {
1947 sciThis->KeyCommand(SCI_ZOOMOUT);
1948 }
1949
1950 // Regular scrolling
1951 } else {
1952 sciThis->ScrollTo(sciThis->topLine + cLineScroll);
1953 }
1954 return TRUE;
1955 } catch (...) {
1956 sciThis->errorStatus = SC_STATUS_FAILURE;
1957 }
1958 return FALSE;
1959}
1960
1961gint ScintillaGTK::Motion(GtkWidget *widget, GdkEventMotion *event) {
1962 ScintillaGTK *sciThis = FromWidget(widget);
1963 try {
1964 //Platform::DebugPrintf("Motion %x %d\n",sciThis,event->time);
1965 if (event->window != WindowFromWidget(widget))
1966 return FALSE;
1967 int x = 0;
1968 int y = 0;
1969 GdkModifierType state {};
1970 if (event->is_hint) {
1971#if GTK_CHECK_VERSION(3,0,0)
1972 gdk_window_get_device_position(event->window,
1973 event->device, &x, &y, &state);
1974#else
1975 gdk_window_get_pointer(event->window, &x, &y, &state);
1976#endif
1977 } else {
1978 x = static_cast<int>(event->x);
1979 y = static_cast<int>(event->y);
1980 state = static_cast<GdkModifierType>(event->state);
1981 }
1982 //Platform::DebugPrintf("Move %x %x %d %c %d %d\n",
1983 // sciThis,event->window,event->time,event->is_hint? 'h' :'.', x, y);
1984 const Point pt(static_cast<XYPOSITION>(x), static_cast<XYPOSITION>(y));
1985 const int modifiers = ModifierFlags(
1986 (event->state & GDK_SHIFT_MASK) != 0,
1987 (event->state & GDK_CONTROL_MASK) != 0,
1988 (event->state & modifierTranslated(sciThis->rectangularSelectionModifier)) != 0);
1989 sciThis->ButtonMoveWithModifiers(pt, event->time, modifiers);
1990 } catch (...) {
1991 sciThis->errorStatus = SC_STATUS_FAILURE;
1992 }
1993 return FALSE;
1994}
1995
1996// Map the keypad keys to their equivalent functions
1997static int KeyTranslate(int keyIn) noexcept {
1998 switch (keyIn) {
1999#if GTK_CHECK_VERSION(3,0,0)
2000 case GDK_KEY_ISO_Left_Tab:
2001 return SCK_TAB;
2002 case GDK_KEY_KP_Down:
2003 return SCK_DOWN;
2004 case GDK_KEY_KP_Up:
2005 return SCK_UP;
2006 case GDK_KEY_KP_Left:
2007 return SCK_LEFT;
2008 case GDK_KEY_KP_Right:
2009 return SCK_RIGHT;
2010 case GDK_KEY_KP_Home:
2011 return SCK_HOME;
2012 case GDK_KEY_KP_End:
2013 return SCK_END;
2014 case GDK_KEY_KP_Page_Up:
2015 return SCK_PRIOR;
2016 case GDK_KEY_KP_Page_Down:
2017 return SCK_NEXT;
2018 case GDK_KEY_KP_Delete:
2019 return SCK_DELETE;
2020 case GDK_KEY_KP_Insert:
2021 return SCK_INSERT;
2022 case GDK_KEY_KP_Enter:
2023 return SCK_RETURN;
2024
2025 case GDK_KEY_Down:
2026 return SCK_DOWN;
2027 case GDK_KEY_Up:
2028 return SCK_UP;
2029 case GDK_KEY_Left:
2030 return SCK_LEFT;
2031 case GDK_KEY_Right:
2032 return SCK_RIGHT;
2033 case GDK_KEY_Home:
2034 return SCK_HOME;
2035 case GDK_KEY_End:
2036 return SCK_END;
2037 case GDK_KEY_Page_Up:
2038 return SCK_PRIOR;
2039 case GDK_KEY_Page_Down:
2040 return SCK_NEXT;
2041 case GDK_KEY_Delete:
2042 return SCK_DELETE;
2043 case GDK_KEY_Insert:
2044 return SCK_INSERT;
2045 case GDK_KEY_Escape:
2046 return SCK_ESCAPE;
2047 case GDK_KEY_BackSpace:
2048 return SCK_BACK;
2049 case GDK_KEY_Tab:
2050 return SCK_TAB;
2051 case GDK_KEY_Return:
2052 return SCK_RETURN;
2053 case GDK_KEY_KP_Add:
2054 return SCK_ADD;
2055 case GDK_KEY_KP_Subtract:
2056 return SCK_SUBTRACT;
2057 case GDK_KEY_KP_Divide:
2058 return SCK_DIVIDE;
2059 case GDK_KEY_Super_L:
2060 return SCK_WIN;
2061 case GDK_KEY_Super_R:
2062 return SCK_RWIN;
2063 case GDK_KEY_Menu:
2064 return SCK_MENU;
2065
2066#else
2067
2068 case GDK_ISO_Left_Tab:
2069 return SCK_TAB;
2070 case GDK_KP_Down:
2071 return SCK_DOWN;
2072 case GDK_KP_Up:
2073 return SCK_UP;
2074 case GDK_KP_Left:
2075 return SCK_LEFT;
2076 case GDK_KP_Right:
2077 return SCK_RIGHT;
2078 case GDK_KP_Home:
2079 return SCK_HOME;
2080 case GDK_KP_End:
2081 return SCK_END;
2082 case GDK_KP_Page_Up:
2083 return SCK_PRIOR;
2084 case GDK_KP_Page_Down:
2085 return SCK_NEXT;
2086 case GDK_KP_Delete:
2087 return SCK_DELETE;
2088 case GDK_KP_Insert:
2089 return SCK_INSERT;
2090 case GDK_KP_Enter:
2091 return SCK_RETURN;
2092
2093 case GDK_Down:
2094 return SCK_DOWN;
2095 case GDK_Up:
2096 return SCK_UP;
2097 case GDK_Left:
2098 return SCK_LEFT;
2099 case GDK_Right:
2100 return SCK_RIGHT;
2101 case GDK_Home:
2102 return SCK_HOME;
2103 case GDK_End:
2104 return SCK_END;
2105 case GDK_Page_Up:
2106 return SCK_PRIOR;
2107 case GDK_Page_Down:
2108 return SCK_NEXT;
2109 case GDK_Delete:
2110 return SCK_DELETE;
2111 case GDK_Insert:
2112 return SCK_INSERT;
2113 case GDK_Escape:
2114 return SCK_ESCAPE;
2115 case GDK_BackSpace:
2116 return SCK_BACK;
2117 case GDK_Tab:
2118 return SCK_TAB;
2119 case GDK_Return:
2120 return SCK_RETURN;
2121 case GDK_KP_Add:
2122 return SCK_ADD;
2123 case GDK_KP_Subtract:
2124 return SCK_SUBTRACT;
2125 case GDK_KP_Divide:
2126 return SCK_DIVIDE;
2127 case GDK_Super_L:
2128 return SCK_WIN;
2129 case GDK_Super_R:
2130 return SCK_RWIN;
2131 case GDK_Menu:
2132 return SCK_MENU;
2133#endif
2134 default:
2135 return keyIn;
2136 }
2137}
2138
2139gboolean ScintillaGTK::KeyThis(GdkEventKey *event) {
2140 try {
2141 //fprintf(stderr, "SC-key: %d %x [%s]\n",
2142 // event->keyval, event->state, (event->length > 0) ? event->string : "empty");
2143 if (gtk_im_context_filter_keypress(im_context, event)) {
2144 return 1;
2145 }
2146 if (!event->keyval) {
2147 return true;
2148 }
2149
2150 const bool shift = (event->state & GDK_SHIFT_MASK) != 0;
2151 bool ctrl = (event->state & GDK_CONTROL_MASK) != 0;
2152 const bool alt = (event->state & GDK_MOD1_MASK) != 0;
2153 const bool super = (event->state & GDK_MOD4_MASK) != 0;
2154 guint key = event->keyval;
2155 if ((ctrl || alt) && (key < 128))
2156 key = toupper(key);
2157#if GTK_CHECK_VERSION(3,0,0)
2158 else if (!ctrl && (key >= GDK_KEY_KP_Multiply && key <= GDK_KEY_KP_9))
2159#else
2160 else if (!ctrl && (key >= GDK_KP_Multiply && key <= GDK_KP_9))
2161#endif
2162 key &= 0x7F;
2163 // Hack for keys over 256 and below command keys but makes Hungarian work.
2164 // This will have to change for Unicode
2165 else if (key >= 0xFE00)
2166 key = KeyTranslate(key);
2167
2168 bool consumed = false;
2169#if !(PLAT_GTK_MACOSX)
2170 const bool meta = false;
2171#else
2172 const bool meta = ctrl;
2173 ctrl = (event->state & GDK_META_MASK) != 0;
2174#endif
2175 const bool added = KeyDownWithModifiers(key, ModifierFlags(shift, ctrl, alt, meta, super), &consumed) != 0;
2176 if (!consumed)
2177 consumed = added;
2178 //fprintf(stderr, "SK-key: %d %x %x\n",event->keyval, event->state, consumed);
2179 if (event->keyval == 0xffffff && event->length > 0) {
2181 const int lengthInserted = pdoc->InsertString(CurrentPosition(), event->string, strlen(event->string));
2182 if (lengthInserted > 0) {
2183 MovePositionTo(CurrentPosition() + lengthInserted);
2184 }
2185 }
2186 return consumed;
2187 } catch (...) {
2189 }
2190 return FALSE;
2191}
2192
2193gboolean ScintillaGTK::KeyPress(GtkWidget *widget, GdkEventKey *event) {
2194 ScintillaGTK *sciThis = FromWidget(widget);
2195 return sciThis->KeyThis(event);
2196}
2197
2198gboolean ScintillaGTK::KeyRelease(GtkWidget *widget, GdkEventKey *event) {
2199 //Platform::DebugPrintf("SC-keyrel: %d %x %3s\n",event->keyval, event->state, event->string);
2200 ScintillaGTK *sciThis = FromWidget(widget);
2201 if (gtk_im_context_filter_keypress(sciThis->im_context, event)) {
2202 return TRUE;
2203 }
2204 return FALSE;
2205}
2206
2207#if GTK_CHECK_VERSION(3,0,0)
2208
2209gboolean ScintillaGTK::DrawPreeditThis(GtkWidget *, cairo_t *cr) {
2210 try {
2211 PreEditString pes(im_context);
2212 PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), pes.str);
2213 pango_layout_set_attributes(layout, pes.attrs);
2214
2215 cairo_move_to(cr, 0, 0);
2216 pango_cairo_show_layout(cr, layout);
2217
2218 g_object_unref(layout);
2219 } catch (...) {
2221 }
2222 return TRUE;
2223}
2224
2225gboolean ScintillaGTK::DrawPreedit(GtkWidget *widget, cairo_t *cr, ScintillaGTK *sciThis) {
2226 return sciThis->DrawPreeditThis(widget, cr);
2227}
2228
2229#else
2230
2231gboolean ScintillaGTK::ExposePreeditThis(GtkWidget *widget, GdkEventExpose *) {
2232 try {
2233 PreEditString pes(im_context);
2234 PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), pes.str);
2235 pango_layout_set_attributes(layout, pes.attrs);
2236
2237 cairo_t *context = gdk_cairo_create(reinterpret_cast<GdkDrawable *>(WindowFromWidget(widget)));
2238 cairo_move_to(context, 0, 0);
2239 pango_cairo_show_layout(context, layout);
2240 cairo_destroy(context);
2241 g_object_unref(layout);
2242 } catch (...) {
2244 }
2245 return TRUE;
2246}
2247
2248gboolean ScintillaGTK::ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis) {
2249 return sciThis->ExposePreeditThis(widget, ose);
2250}
2251
2252#endif
2253
2255 PreEditString pes(im_context);
2256 if (pes.pscript != G_UNICODE_SCRIPT_COMMON)
2257 lastNonCommonScript = pes.pscript;
2258 return lastNonCommonScript == G_UNICODE_SCRIPT_HANGUL;
2259}
2260
2262 // Move carets relatively by bytes
2263 for (size_t r=0; r<sel.Count(); r++) {
2264 const Sci::Position positionInsert = sel.Range(r).Start().Position();
2265 sel.Range(r).caret.SetPosition(positionInsert + pos);
2266 sel.Range(r).anchor.SetPosition(positionInsert + pos);
2267 }
2268}
2269
2270void ScintillaGTK::DrawImeIndicator(int indicator, int len) {
2271 // Emulate the visual style of IME characters with indicators.
2272 // Draw an indicator on the character before caret by the character bytes of len
2273 // so it should be called after InsertCharacter().
2274 // It does not affect caret positions.
2275 if (indicator < 8 || indicator > INDICATOR_MAX) {
2276 return;
2277 }
2279 for (size_t r=0; r<sel.Count(); r++) {
2280 const Sci::Position positionInsert = sel.Range(r).Start().Position();
2281 pdoc->DecorationFillRange(positionInsert - len, 1, len);
2282 }
2283}
2284
2285static std::vector<int> MapImeIndicators(PangoAttrList *attrs, const char *u8Str) {
2286 // Map input style to scintilla ime indicator.
2287 // Attrs position points between UTF-8 bytes.
2288 // Indicator index to be returned is character based though.
2289 const glong charactersLen = g_utf8_strlen(u8Str, strlen(u8Str));
2290 std::vector<int> indicator(charactersLen, SC_INDICATOR_UNKNOWN);
2291
2292 PangoAttrIterator *iterunderline = pango_attr_list_get_iterator(attrs);
2293 if (iterunderline) {
2294 do {
2295 PangoAttribute *attrunderline = pango_attr_iterator_get(iterunderline, PANGO_ATTR_UNDERLINE);
2296 if (attrunderline) {
2297 const glong start = g_utf8_strlen(u8Str, attrunderline->start_index);
2298 const glong end = g_utf8_strlen(u8Str, attrunderline->end_index);
2299 const PangoUnderline uline = (PangoUnderline)((PangoAttrInt *)attrunderline)->value;
2300 for (glong i=start; i < end; ++i) {
2301 switch (uline) {
2302 case PANGO_UNDERLINE_NONE:
2303 indicator[i] = SC_INDICATOR_UNKNOWN;
2304 break;
2305 case PANGO_UNDERLINE_SINGLE: // normal input
2306 indicator[i] = SC_INDICATOR_INPUT;
2307 break;
2308 case PANGO_UNDERLINE_DOUBLE:
2309 case PANGO_UNDERLINE_LOW:
2310 case PANGO_UNDERLINE_ERROR:
2311 break;
2312 }
2313 }
2314 }
2315 } while (pango_attr_iterator_next(iterunderline));
2316 pango_attr_iterator_destroy(iterunderline);
2317 }
2318
2319 PangoAttrIterator *itercolor = pango_attr_list_get_iterator(attrs);
2320 if (itercolor) {
2321 do {
2322 const PangoAttribute *backcolor = pango_attr_iterator_get(itercolor, PANGO_ATTR_BACKGROUND);
2323 if (backcolor) {
2324 const glong start = g_utf8_strlen(u8Str, backcolor->start_index);
2325 const glong end = g_utf8_strlen(u8Str, backcolor->end_index);
2326 for (glong i=start; i < end; ++i) {
2327 indicator[i] = SC_INDICATOR_TARGET; // target converted
2328 }
2329 }
2330 } while (pango_attr_iterator_next(itercolor));
2331 pango_attr_iterator_destroy(itercolor);
2332 }
2333 return indicator;
2334}
2335
2337 // Composition box accompanies candidate box.
2338 const Point pt = PointMainCaret();
2339 GdkRectangle imeBox = {0}; // No need to set width
2340 imeBox.x = static_cast<gint>(pt.x);
2341 imeBox.y = static_cast<gint>(pt.y + std::max(4, vs.lineHeight/4));
2342 // prevent overlapping with current line
2343 imeBox.height = vs.lineHeight;
2344 gtk_im_context_set_cursor_location(im_context, &imeBox);
2345}
2346
2347void ScintillaGTK::CommitThis(char *commitStr) {
2348 try {
2349 //~ fprintf(stderr, "Commit '%s'\n", commitStr);
2351
2352 if (pdoc->TentativeActive()) {
2354 }
2355
2356 const char *charSetSource = CharacterSetID();
2357
2358 glong uniStrLen = 0;
2359 gunichar *uniStr = g_utf8_to_ucs4_fast(commitStr, strlen(commitStr), &uniStrLen);
2360 for (glong i = 0; i < uniStrLen; i++) {
2361 gchar u8Char[UTF8MaxBytes+2] = {0};
2362 const gint u8CharLen = g_unichar_to_utf8(uniStr[i], u8Char);
2363 std::string docChar = u8Char;
2364 if (!IsUnicodeMode())
2365 docChar = ConvertText(u8Char, u8CharLen, charSetSource, "UTF-8", true);
2366
2367 InsertCharacter(docChar.c_str(), docChar.size(), CharacterSource::directInput);
2368 }
2369 g_free(uniStr);
2371 } catch (...) {
2373 }
2374}
2375
2376void ScintillaGTK::Commit(GtkIMContext *, char *str, ScintillaGTK *sciThis) {
2377 sciThis->CommitThis(str);
2378}
2379
2381 // Copy & paste by johnsonj with a lot of helps of Neil
2382 // Great thanks for my foreruners, jiniya and BLUEnLIVE
2383 try {
2385 gtk_im_context_reset(im_context);
2386 return;
2387 }
2388
2389 view.imeCaretBlockOverride = false; // If backspace.
2390
2391 bool initialCompose = false;
2392 if (pdoc->TentativeActive()) {
2394 } else {
2395 // No tentative undo means start of this composition so
2396 // fill in any virtual spaces.
2397 initialCompose = true;
2398 }
2399
2400 PreEditString preeditStr(im_context);
2401 const char *charSetSource = CharacterSetID();
2402
2403 if (!preeditStr.validUTF8 || (charSetSource == nullptr)) {
2405 return;
2406 }
2407
2408 if (preeditStr.uniStrLen == 0 || preeditStr.uniStrLen > maxLenInputIME) {
2409 //fprintf(stderr, "Do not allow over 200 chars: %i\n", preeditStr.uniStrLen);
2411 return;
2412 }
2413
2414 if (initialCompose) {
2416 }
2417
2419 pdoc->TentativeStart(); // TentativeActive() from now on
2420
2421 std::vector<int> indicator = MapImeIndicators(preeditStr.attrs, preeditStr.str);
2422
2423 for (glong i = 0; i < preeditStr.uniStrLen; i++) {
2424 gchar u8Char[UTF8MaxBytes+2] = {0};
2425 const gint u8CharLen = g_unichar_to_utf8(preeditStr.uniStr[i], u8Char);
2426 std::string docChar = u8Char;
2427 if (!IsUnicodeMode())
2428 docChar = ConvertText(u8Char, u8CharLen, charSetSource, "UTF-8", true);
2429
2430 InsertCharacter(docChar.c_str(), docChar.size(), CharacterSource::tentativeInput);
2431
2432 DrawImeIndicator(indicator[i], docChar.size());
2433 }
2434
2435 // Move caret to ime cursor position.
2436 const int imeEndToImeCaretU32 = preeditStr.cursor_pos - preeditStr.uniStrLen;
2437 const int imeCaretPosDoc = pdoc->GetRelativePosition(CurrentPosition(), imeEndToImeCaretU32);
2438
2439 MoveImeCarets(- CurrentPosition() + imeCaretPosDoc);
2440
2441 if (KoreanIME()) {
2442#if !PLAT_GTK_WIN32
2443 if (preeditStr.cursor_pos > 0) {
2444 int oneCharBefore = pdoc->GetRelativePosition(CurrentPosition(), -1);
2445 MoveImeCarets(- CurrentPosition() + oneCharBefore);
2446 }
2447#endif
2449 }
2450
2453 } catch (...) {
2455 }
2456}
2457
2459 try {
2460 PreEditString pes(im_context);
2461 if (strlen(pes.str) > 0) {
2463
2464 PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), pes.str);
2465 pango_layout_set_attributes(layout, pes.attrs);
2466
2467 gint w, h;
2468 pango_layout_get_pixel_size(layout, &w, &h);
2469 g_object_unref(layout);
2470
2471 gint x, y;
2472 gdk_window_get_origin(PWindow(wText), &x, &y);
2473
2474 Point pt = PointMainCaret();
2475 if (pt.x < 0)
2476 pt.x = 0;
2477 if (pt.y < 0)
2478 pt.y = 0;
2479
2480 gtk_window_move(GTK_WINDOW(PWidget(wPreedit)), x + pt.x, y + pt.y);
2481 gtk_window_resize(GTK_WINDOW(PWidget(wPreedit)), w, h);
2482 gtk_widget_show(PWidget(wPreedit));
2483 gtk_widget_queue_draw_area(PWidget(wPreeditDraw), 0, 0, w, h);
2484 } else {
2485 gtk_widget_hide(PWidget(wPreedit));
2486 }
2487 } catch (...) {
2489 }
2490}
2491
2492void ScintillaGTK::PreeditChanged(GtkIMContext *, ScintillaGTK *sciThis) {
2493 if ((sciThis->imeInteraction == imeInline) || (sciThis->KoreanIME())) {
2494 sciThis->PreeditChangedInlineThis();
2495 } else {
2496 sciThis->PreeditChangedWindowedThis();
2497 }
2498}
2499
2500void ScintillaGTK::StyleSetText(GtkWidget *widget, GtkStyle *, void *) {
2501 RealizeText(widget, nullptr);
2502}
2503
2504void ScintillaGTK::RealizeText(GtkWidget *widget, void *) {
2505 // Set NULL background to avoid automatic clearing so Scintilla responsible for all drawing
2506 if (WindowFromWidget(widget)) {
2507#if GTK_CHECK_VERSION(3,22,0)
2508 // Appears unnecessary
2509#elif GTK_CHECK_VERSION(3,0,0)
2510 gdk_window_set_background_pattern(WindowFromWidget(widget), nullptr);
2511#else
2512 gdk_window_set_back_pixmap(WindowFromWidget(widget), nullptr, FALSE);
2513#endif
2514 }
2515}
2516
2517static GObjectClass *scintilla_class_parent_class;
2518
2519void ScintillaGTK::Dispose(GObject *object) {
2520 try {
2521 ScintillaObject *scio = SCINTILLA(object);
2522 ScintillaGTK *sciThis = static_cast<ScintillaGTK *>(scio->pscin);
2523
2524 if (PWidget(sciThis->scrollbarv)) {
2525 gtk_widget_unparent(PWidget(sciThis->scrollbarv));
2526 sciThis->scrollbarv = nullptr;
2527 }
2528
2529 if (PWidget(sciThis->scrollbarh)) {
2530 gtk_widget_unparent(PWidget(sciThis->scrollbarh));
2531 sciThis->scrollbarh = nullptr;
2532 }
2533
2534 scintilla_class_parent_class->dispose(object);
2535 } catch (...) {
2536 // Its dying so nowhere to save the status
2537 }
2538}
2539
2540void ScintillaGTK::Destroy(GObject *object) {
2541 try {
2542 ScintillaObject *scio = SCINTILLA(object);
2543
2544 // This avoids a double destruction
2545 if (!scio->pscin)
2546 return;
2547 ScintillaGTK *sciThis = static_cast<ScintillaGTK *>(scio->pscin);
2548 //Platform::DebugPrintf("Destroying %x %x\n", sciThis, object);
2549 sciThis->Finalise();
2550
2551 delete sciThis;
2552 scio->pscin = nullptr;
2553 scintilla_class_parent_class->finalize(object);
2554 } catch (...) {
2555 // Its dead so nowhere to save the status
2556 }
2557}
2558
2559#if GTK_CHECK_VERSION(3,0,0)
2560
2561gboolean ScintillaGTK::DrawTextThis(cairo_t *cr) {
2562 try {
2564 repaintFullWindow = false;
2565
2567
2568 PLATFORM_ASSERT(rgnUpdate == nullptr);
2569 rgnUpdate = cairo_copy_clip_rectangle_list(cr);
2570 if (rgnUpdate && rgnUpdate->status != CAIRO_STATUS_SUCCESS) {
2571 // If not successful then ignore
2572 fprintf(stderr, "DrawTextThis failed to copy update region %d [%d]\n", rgnUpdate->status, rgnUpdate->num_rectangles);
2573 cairo_rectangle_list_destroy(rgnUpdate);
2574 rgnUpdate = 0;
2575 }
2576
2577 double x1, y1, x2, y2;
2578 cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
2579 rcPaint.left = x1;
2580 rcPaint.top = y1;
2581 rcPaint.right = x2;
2582 rcPaint.bottom = y2;
2583 PRectangle rcClient = GetClientRectangle();
2584 paintingAllText = rcPaint.Contains(rcClient);
2585 std::unique_ptr<Surface> surfaceWindow(Surface::Allocate(SC_TECHNOLOGY_DEFAULT));
2586 surfaceWindow->Init(cr, PWidget(wText));
2587 Paint(surfaceWindow.get(), rcPaint);
2588 surfaceWindow->Release();
2590 // Painting area was insufficient to cover new styling or brace highlight positions
2591 FullPaint();
2592 }
2594 repaintFullWindow = false;
2595
2596 if (rgnUpdate) {
2597 cairo_rectangle_list_destroy(rgnUpdate);
2598 }
2599 rgnUpdate = 0;
2601 } catch (...) {
2603 }
2604
2605 return FALSE;
2606}
2607
2608gboolean ScintillaGTK::DrawText(GtkWidget *, cairo_t *cr, ScintillaGTK *sciThis) {
2609 return sciThis->DrawTextThis(cr);
2610}
2611
2612gboolean ScintillaGTK::DrawThis(cairo_t *cr) {
2613 try {
2614#ifdef GTK_STYLE_CLASS_SCROLLBARS_JUNCTION /* GTK >= 3.4 */
2615 // if both scrollbars are visible, paint the little square on the bottom right corner
2617 GtkStyleContext *styleContext = gtk_widget_get_style_context(PWidget(wMain));
2619
2620 gtk_style_context_save(styleContext);
2621 gtk_style_context_add_class(styleContext, GTK_STYLE_CLASS_SCROLLBARS_JUNCTION);
2622
2623 gtk_render_background(styleContext, cr, rc.right, rc.bottom,
2625 gtk_render_frame(styleContext, cr, rc.right, rc.bottom,
2627
2628 gtk_style_context_restore(styleContext);
2629 }
2630#endif
2631
2632 gtk_container_propagate_draw(
2633 GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarh), cr);
2634 gtk_container_propagate_draw(
2635 GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarv), cr);
2636// Starting from the following version, the expose event are not propagated
2637// for double buffered non native windows, so we need to call it ourselves
2638// or keep the default handler
2639#if GTK_CHECK_VERSION(3,0,0)
2640 // we want to forward on any >= 3.9.2 runtime
2641 if (gtk_check_version(3, 9, 2) == nullptr) {
2642 gtk_container_propagate_draw(
2643 GTK_CONTAINER(PWidget(wMain)), PWidget(wText), cr);
2644 }
2645#endif
2646 } catch (...) {
2648 }
2649 return FALSE;
2650}
2651
2652gboolean ScintillaGTK::DrawMain(GtkWidget *widget, cairo_t *cr) {
2653 ScintillaGTK *sciThis = FromWidget(widget);
2654 return sciThis->DrawThis(cr);
2655}
2656
2657#else
2658
2659gboolean ScintillaGTK::ExposeTextThis(GtkWidget * /*widget*/, GdkEventExpose *ose) {
2660 try {
2662
2664 ose->area.x,
2665 ose->area.y,
2666 ose->area.x + ose->area.width,
2667 ose->area.y + ose->area.height);
2668
2669 PLATFORM_ASSERT(rgnUpdate == nullptr);
2670 rgnUpdate = gdk_region_copy(ose->region);
2671 const PRectangle rcClient = GetClientRectangle();
2672 paintingAllText = rcPaint.Contains(rcClient);
2673 std::unique_ptr<Surface> surfaceWindow(Surface::Allocate(SC_TECHNOLOGY_DEFAULT));
2674 cairo_t *cr = gdk_cairo_create(PWindow(wText));
2675 surfaceWindow->Init(cr, PWidget(wText));
2676 Paint(surfaceWindow.get(), rcPaint);
2677 surfaceWindow->Release();
2678 cairo_destroy(cr);
2680 // Painting area was insufficient to cover new styling or brace highlight positions
2681 FullPaint();
2682 }
2684 repaintFullWindow = false;
2685
2686 if (rgnUpdate) {
2687 gdk_region_destroy(rgnUpdate);
2688 }
2689 rgnUpdate = nullptr;
2690 } catch (...) {
2692 }
2693
2694 return FALSE;
2695}
2696
2697gboolean ScintillaGTK::ExposeText(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis) {
2698 return sciThis->ExposeTextThis(widget, ose);
2699}
2700
2701gboolean ScintillaGTK::ExposeMain(GtkWidget *widget, GdkEventExpose *ose) {
2702 ScintillaGTK *sciThis = FromWidget(widget);
2703 //Platform::DebugPrintf("Expose Main %0d,%0d %0d,%0d\n",
2704 //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2705 return sciThis->Expose(widget, ose);
2706}
2707
2708gboolean ScintillaGTK::Expose(GtkWidget *, GdkEventExpose *ose) {
2709 try {
2710 //fprintf(stderr, "Expose %0d,%0d %0d,%0d\n",
2711 //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2712
2713 // The text is painted in ExposeText
2714 gtk_container_propagate_expose(
2715 GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarh), ose);
2716 gtk_container_propagate_expose(
2717 GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarv), ose);
2718
2719 } catch (...) {
2721 }
2722 return FALSE;
2723}
2724
2725#endif
2726
2727void ScintillaGTK::ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) {
2728 try {
2729 sciThis->ScrollTo(static_cast<int>(gtk_adjustment_get_value(adj)), false);
2730 } catch (...) {
2731 sciThis->errorStatus = SC_STATUS_FAILURE;
2732 }
2733}
2734
2735void ScintillaGTK::ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) {
2736 try {
2737 sciThis->HorizontalScrollTo(static_cast<int>(gtk_adjustment_get_value(adj)));
2738 } catch (...) {
2739 sciThis->errorStatus = SC_STATUS_FAILURE;
2740 }
2741}
2742
2743void ScintillaGTK::SelectionReceived(GtkWidget *widget,
2744 GtkSelectionData *selection_data, guint) {
2745 ScintillaGTK *sciThis = FromWidget(widget);
2746 //Platform::DebugPrintf("Selection received\n");
2747 sciThis->ReceivedSelection(selection_data);
2748}
2749
2750void ScintillaGTK::SelectionGet(GtkWidget *widget,
2751 GtkSelectionData *selection_data, guint info, guint) {
2752 ScintillaGTK *sciThis = FromWidget(widget);
2753 try {
2754 //Platform::DebugPrintf("Selection get\n");
2755 if (SelectionOfGSD(selection_data) == GDK_SELECTION_PRIMARY) {
2756 if (sciThis->primary.Empty()) {
2757 sciThis->CopySelectionRange(&sciThis->primary);
2758 }
2759 sciThis->GetSelection(selection_data, info, &sciThis->primary);
2760 }
2761 } catch (...) {
2762 sciThis->errorStatus = SC_STATUS_FAILURE;
2763 }
2764}
2765
2766gint ScintillaGTK::SelectionClear(GtkWidget *widget, GdkEventSelection *selection_event) {
2767 ScintillaGTK *sciThis = FromWidget(widget);
2768 //Platform::DebugPrintf("Selection clear\n");
2769 sciThis->UnclaimSelection(selection_event);
2770 if (GTK_WIDGET_CLASS(sciThis->parentClass)->selection_clear_event) {
2771 return GTK_WIDGET_CLASS(sciThis->parentClass)->selection_clear_event(widget, selection_event);
2772 }
2773 return TRUE;
2774}
2775
2776gboolean ScintillaGTK::DragMotionThis(GdkDragContext *context,
2777 gint x, gint y, guint dragtime) {
2778 try {
2779 const Point npt = Point::FromInts(x, y);
2781 GdkDragAction preferredAction = gdk_drag_context_get_suggested_action(context);
2782 const GdkDragAction actions = gdk_drag_context_get_actions(context);
2784 if ((inDragDrop == ddDragging) && (PositionInSelection(pos.Position()))) {
2785 // Avoid dragging selection onto itself as that produces a move
2786 // with no real effect but which creates undo actions.
2787 preferredAction = static_cast<GdkDragAction>(0);
2788 } else if (actions == actionCopyOrMove) {
2789 preferredAction = GDK_ACTION_MOVE;
2790 }
2791 gdk_drag_status(context, preferredAction, dragtime);
2792 } catch (...) {
2794 }
2795 return FALSE;
2796}
2797
2798gboolean ScintillaGTK::DragMotion(GtkWidget *widget, GdkDragContext *context,
2799 gint x, gint y, guint dragtime) {
2800 ScintillaGTK *sciThis = FromWidget(widget);
2801 return sciThis->DragMotionThis(context, x, y, dragtime);
2802}
2803
2804void ScintillaGTK::DragLeave(GtkWidget *widget, GdkDragContext * /*context*/, guint) {
2805 ScintillaGTK *sciThis = FromWidget(widget);
2806 try {
2808 //Platform::DebugPrintf("DragLeave %x\n", sciThis);
2809 } catch (...) {
2810 sciThis->errorStatus = SC_STATUS_FAILURE;
2811 }
2812}
2813
2814void ScintillaGTK::DragEnd(GtkWidget *widget, GdkDragContext * /*context*/) {
2815 ScintillaGTK *sciThis = FromWidget(widget);
2816 try {
2817 // If drag did not result in drop here or elsewhere
2818 if (!sciThis->dragWasDropped)
2819 sciThis->SetEmptySelection(sciThis->posDrag);
2821 //Platform::DebugPrintf("DragEnd %x %d\n", sciThis, sciThis->dragWasDropped);
2822 sciThis->inDragDrop = ddNone;
2823 } catch (...) {
2824 sciThis->errorStatus = SC_STATUS_FAILURE;
2825 }
2826}
2827
2828gboolean ScintillaGTK::Drop(GtkWidget *widget, GdkDragContext * /*context*/,
2829 gint, gint, guint) {
2830 ScintillaGTK *sciThis = FromWidget(widget);
2831 try {
2832 //Platform::DebugPrintf("Drop %x\n", sciThis);
2834 } catch (...) {
2835 sciThis->errorStatus = SC_STATUS_FAILURE;
2836 }
2837 return FALSE;
2838}
2839
2840void ScintillaGTK::DragDataReceived(GtkWidget *widget, GdkDragContext * /*context*/,
2841 gint, gint, GtkSelectionData *selection_data, guint /*info*/, guint) {
2842 ScintillaGTK *sciThis = FromWidget(widget);
2843 try {
2844 sciThis->ReceivedDrop(selection_data);
2846 } catch (...) {
2847 sciThis->errorStatus = SC_STATUS_FAILURE;
2848 }
2849}
2850
2851void ScintillaGTK::DragDataGet(GtkWidget *widget, GdkDragContext *context,
2852 GtkSelectionData *selection_data, guint info, guint) {
2853 ScintillaGTK *sciThis = FromWidget(widget);
2854 try {
2855 sciThis->dragWasDropped = true;
2856 if (!sciThis->sel.Empty()) {
2857 sciThis->GetSelection(selection_data, info, &sciThis->drag);
2858 }
2859 const GdkDragAction action = gdk_drag_context_get_selected_action(context);
2860 if (action == GDK_ACTION_MOVE) {
2861 for (size_t r=0; r<sciThis->sel.Count(); r++) {
2862 if (sciThis->posDrop >= sciThis->sel.Range(r).Start()) {
2863 if (sciThis->posDrop > sciThis->sel.Range(r).End()) {
2864 sciThis->posDrop.Add(-sciThis->sel.Range(r).Length());
2865 } else {
2866 sciThis->posDrop.Add(-SelectionRange(sciThis->posDrop, sciThis->sel.Range(r).Start()).Length());
2867 }
2868 }
2869 }
2870 sciThis->ClearSelection();
2871 }
2873 } catch (...) {
2874 sciThis->errorStatus = SC_STATUS_FAILURE;
2875 }
2876}
2877
2878int ScintillaGTK::TimeOut(gpointer ptt) {
2879 TimeThunk *tt = static_cast<TimeThunk *>(ptt);
2880 tt->scintilla->TickFor(tt->reason);
2881 return 1;
2882}
2883
2884gboolean ScintillaGTK::IdleCallback(gpointer pSci) {
2885 ScintillaGTK *sciThis = static_cast<ScintillaGTK *>(pSci);
2886 // Idler will be automatically stopped, if there is nothing
2887 // to do while idle.
2888 const bool ret = sciThis->Idle();
2889 if (ret == false) {
2890 // FIXME: This will remove the idler from GTK, we don't want to
2891 // remove it as it is removed automatically when this function
2892 // returns false (although, it should be harmless).
2893 sciThis->SetIdle(false);
2894 }
2895 return ret;
2896}
2897
2898gboolean ScintillaGTK::StyleIdle(gpointer pSci) {
2899 ScintillaGTK *sciThis = static_cast<ScintillaGTK *>(pSci);
2900 sciThis->IdleWork();
2901 // Idler will be automatically stopped
2902 return FALSE;
2903}
2904
2907 styleIdleID = 0;
2908}
2909
2911 Editor::QueueIdleWork(items, upTo);
2912 if (!styleIdleID) {
2913 // Only allow one style needed to be queued
2914 styleIdleID = gdk_threads_add_idle_full(G_PRIORITY_HIGH_IDLE, StyleIdle, this, nullptr);
2915 }
2916}
2917
2919 Document *oldDoc = nullptr;
2920 ScintillaGTKAccessible *sciAccessible = nullptr;
2921 if (accessible) {
2923 if (sciAccessible && pdoc) {
2924 oldDoc = pdoc;
2925 oldDoc->AddRef();
2926 }
2927 }
2928
2929 Editor::SetDocPointer(document);
2930
2931 if (sciAccessible) {
2932 // the accessible needs have the old Document, but also the new one active
2933 sciAccessible->ChangeDocument(oldDoc, pdoc);
2934 }
2935 if (oldDoc) {
2936 oldDoc->Release();
2937 }
2938}
2939
2940void ScintillaGTK::PopUpCB(GtkMenuItem *menuItem, ScintillaGTK *sciThis) {
2941 guint const action = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(menuItem), "CmdNum"));
2942 if (action) {
2943 sciThis->Command(action);
2944 }
2945}
2946
2947gboolean ScintillaGTK::PressCT(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis) {
2948 try {
2949 if (event->window != WindowFromWidget(widget))
2950 return FALSE;
2951 if (event->type != GDK_BUTTON_PRESS)
2952 return FALSE;
2953 const Point pt = PointOfEvent(event);
2954 sciThis->ct.MouseClick(pt);
2955 sciThis->CallTipClick();
2956 } catch (...) {
2957 }
2958 return TRUE;
2959}
2960
2961#if GTK_CHECK_VERSION(3,0,0)
2962
2963gboolean ScintillaGTK::DrawCT(GtkWidget *widget, cairo_t *cr, CallTip *ctip) {
2964 try {
2965 std::unique_ptr<Surface> surfaceWindow(Surface::Allocate(SC_TECHNOLOGY_DEFAULT));
2966 surfaceWindow->Init(cr, widget);
2967 surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == ctip->codePage);
2968 surfaceWindow->SetDBCSMode(ctip->codePage);
2969 ctip->PaintCT(surfaceWindow.get());
2970 surfaceWindow->Release();
2971 } catch (...) {
2972 // No pointer back to Scintilla to save status
2973 }
2974 return TRUE;
2975}
2976
2977#else
2978
2979gboolean ScintillaGTK::ExposeCT(GtkWidget *widget, GdkEventExpose * /*ose*/, CallTip *ctip) {
2980 try {
2981 std::unique_ptr<Surface> surfaceWindow(Surface::Allocate(SC_TECHNOLOGY_DEFAULT));
2982 cairo_t *cr = gdk_cairo_create(WindowFromWidget(widget));
2983 surfaceWindow->Init(cr, widget);
2984 surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == ctip->codePage);
2985 surfaceWindow->SetDBCSMode(ctip->codePage);
2986 ctip->PaintCT(surfaceWindow.get());
2987 surfaceWindow->Release();
2988 cairo_destroy(cr);
2989 } catch (...) {
2990 // No pointer back to Scintilla to save status
2991 }
2992 return TRUE;
2993}
2994
2995#endif
2996
2997AtkObject *ScintillaGTK::GetAccessibleThis(GtkWidget *widget) {
2999}
3000
3001AtkObject *ScintillaGTK::GetAccessible(GtkWidget *widget) {
3002 return FromWidget(widget)->GetAccessibleThis(widget);
3003}
3004
3006 sptr_t ptr, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
3007 return reinterpret_cast<ScintillaGTK *>(ptr)->WndProc(iMessage, wParam, lParam);
3008}
3009
3010/* legacy name for scintilla_object_send_message */
3011GEANY_API_SYMBOL
3012sptr_t scintilla_send_message(ScintillaObject *sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
3013 ScintillaGTK *psci = static_cast<ScintillaGTK *>(sci->pscin);
3014 return psci->WndProc(iMessage, wParam, lParam);
3015}
3016
3017GEANY_API_SYMBOL
3018gintptr scintilla_object_send_message(ScintillaObject *sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
3019 return scintilla_send_message(sci, iMessage, wParam, lParam);
3020}
3021
3022static void scintilla_class_init(ScintillaClass *klass);
3023static void scintilla_init(ScintillaObject *sci);
3024
3025extern void Platform_Initialise();
3026extern void Platform_Finalise();
3027
3028/* legacy name for scintilla_object_get_type */
3029GEANY_API_SYMBOL
3031 static GType scintilla_type = 0;
3032 try {
3033
3034 if (!scintilla_type) {
3035 scintilla_type = g_type_from_name("ScintillaObject");
3036 if (!scintilla_type) {
3037 static GTypeInfo scintilla_info = {
3038 (guint16) sizeof(ScintillaObjectClass),
3039 nullptr, //(GBaseInitFunc)
3040 nullptr, //(GBaseFinalizeFunc)
3041 (GClassInitFunc) scintilla_class_init,
3042 nullptr, //(GClassFinalizeFunc)
3043 nullptr, //gconstpointer data
3044 (guint16) sizeof(ScintillaObject),
3045 0, //n_preallocs
3046 (GInstanceInitFunc) scintilla_init,
3047 nullptr //(GTypeValueTable*)
3048 };
3049 scintilla_type = g_type_register_static(
3050 GTK_TYPE_CONTAINER, "ScintillaObject", &scintilla_info, (GTypeFlags) 0);
3051 }
3052 }
3053
3054 } catch (...) {
3055 }
3056 return scintilla_type;
3057}
3058
3059GEANY_API_SYMBOL
3061 return scintilla_get_type();
3062}
3063
3064void ScintillaGTK::ClassInit(OBJECT_CLASS *object_class, GtkWidgetClass *widget_class, GtkContainerClass *container_class) {
3066 atomUTF8 = gdk_atom_intern("UTF8_STRING", FALSE);
3067 atomUTF8Mime = gdk_atom_intern("text/plain;charset=utf-8", FALSE);
3068 atomString = GDK_SELECTION_TYPE_STRING;
3069 atomUriList = gdk_atom_intern("text/uri-list", FALSE);
3070 atomDROPFILES_DND = gdk_atom_intern("DROPFILES_DND", FALSE);
3071
3072 // Define default signal handlers for the class: Could move more
3073 // of the signal handlers here (those that currently attached to wDraw
3074 // in Init() may require coordinate translation?)
3075
3076 object_class->dispose = Dispose;
3077 object_class->finalize = Destroy;
3078#if GTK_CHECK_VERSION(3,0,0)
3079 widget_class->get_preferred_width = GetPreferredWidth;
3080 widget_class->get_preferred_height = GetPreferredHeight;
3081#else
3082 widget_class->size_request = SizeRequest;
3083#endif
3084 widget_class->size_allocate = SizeAllocate;
3085#if GTK_CHECK_VERSION(3,0,0)
3086 widget_class->draw = DrawMain;
3087#else
3088 widget_class->expose_event = ExposeMain;
3089#endif
3090 widget_class->motion_notify_event = Motion;
3091 widget_class->button_press_event = Press;
3092 widget_class->button_release_event = MouseRelease;
3093 widget_class->scroll_event = ScrollEvent;
3094 widget_class->key_press_event = KeyPress;
3095 widget_class->key_release_event = KeyRelease;
3096 widget_class->focus_in_event = FocusIn;
3097 widget_class->focus_out_event = FocusOut;
3098 widget_class->selection_received = SelectionReceived;
3099 widget_class->selection_get = SelectionGet;
3100 widget_class->selection_clear_event = SelectionClear;
3101
3102 widget_class->drag_data_received = DragDataReceived;
3103 widget_class->drag_motion = DragMotion;
3104 widget_class->drag_leave = DragLeave;
3105 widget_class->drag_end = DragEnd;
3106 widget_class->drag_drop = Drop;
3107 widget_class->drag_data_get = DragDataGet;
3108
3109 widget_class->realize = Realize;
3110 widget_class->unrealize = UnRealize;
3111 widget_class->map = Map;
3112 widget_class->unmap = UnMap;
3113
3114 widget_class->get_accessible = GetAccessible;
3115
3116 container_class->forall = MainForAll;
3117}
3118
3119static void scintilla_class_init(ScintillaClass *klass) {
3120 try {
3121 OBJECT_CLASS *object_class = (OBJECT_CLASS *) klass;
3122 GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
3123 GtkContainerClass *container_class = (GtkContainerClass *) klass;
3124
3125 const GSignalFlags sigflags = GSignalFlags(G_SIGNAL_ACTION | G_SIGNAL_RUN_LAST);
3126 scintilla_signals[COMMAND_SIGNAL] = g_signal_new(
3127 "command",
3128 G_TYPE_FROM_CLASS(object_class),
3129 sigflags,
3130 G_STRUCT_OFFSET(ScintillaClass, command),
3131 nullptr, //(GSignalAccumulator)
3132 nullptr, //(gpointer)
3134 G_TYPE_NONE,
3135 2, G_TYPE_INT, GTK_TYPE_WIDGET);
3136
3137 scintilla_signals[NOTIFY_SIGNAL] = g_signal_new(
3138 SCINTILLA_NOTIFY,
3139 G_TYPE_FROM_CLASS(object_class),
3140 sigflags,
3141 G_STRUCT_OFFSET(ScintillaClass, notify),
3142 nullptr, //(GSignalAccumulator)
3143 nullptr, //(gpointer)
3145 G_TYPE_NONE,
3146 2, G_TYPE_INT, SCINTILLA_TYPE_NOTIFICATION);
3147
3148 klass->command = nullptr;
3149 klass->notify = nullptr;
3150 scintilla_class_parent_class = G_OBJECT_CLASS(g_type_class_peek_parent(klass));
3151 ScintillaGTK::ClassInit(object_class, widget_class, container_class);
3152 } catch (...) {
3153 }
3154}
3155
3156static void scintilla_init(ScintillaObject *sci) {
3157 try {
3158 gtk_widget_set_can_focus(GTK_WIDGET(sci), TRUE);
3159 sci->pscin = new ScintillaGTK(sci);
3160 } catch (...) {
3161 }
3162}
3163
3164/* legacy name for scintilla_object_new */
3165GEANY_API_SYMBOL
3166GtkWidget *scintilla_new() {
3167 GtkWidget *widget = GTK_WIDGET(g_object_new(scintilla_get_type(), nullptr));
3168 gtk_widget_set_direction(widget, GTK_TEXT_DIR_LTR);
3169
3170 return widget;
3171}
3172
3173GEANY_API_SYMBOL
3175 return scintilla_new();
3176}
3177
3178void scintilla_set_id(ScintillaObject *sci, uptr_t id) {
3179 ScintillaGTK *psci = static_cast<ScintillaGTK *>(sci->pscin);
3180 psci->ctrlID = id;
3181}
3182
3184 try {
3186 } catch (...) {
3187 }
3188}
3189
3190/* Define a dummy boxed type because g-ir-scanner is unable to
3191 * recognize gpointer-derived types. Note that SCNotificaiton
3192 * is always allocated on stack so copying is not appropriate. */
3193static void *copy_(void *src) { return src; }
3194static void free_(void *) { }
3195
3196GEANY_API_SYMBOL
3198 static gsize type_id = 0;
3199 if (g_once_init_enter(&type_id)) {
3200 const gsize id = (gsize) g_boxed_type_register_static(
3201 g_intern_static_string("SCNotification"),
3202 (GBoxedCopyFunc) copy_,
3203 (GBoxedFreeFunc) free_);
3204 g_once_init_leave(&type_id, id);
3205 }
3206 return (GType) type_id;
3207}
Defines the auto completion list box.
Interface to the call tip control.
Performs Unicode case conversions.
Classes for case folding.
Manages the text of the document.
Character classifications used by Document and RESearch.
Returns the Unicode general category of a character.
Manages visibility of lines for folding and wrapping.
Visual elements added over text.
Text document that handles notifications, DBCS, styling, words and end of line.
Defines the editor state that must be visible to EditorView.
Defines the appearance of the main text area of the editor window.
Defines the main editor class.
Interface between Scintilla and lexers.
Interface for loading into a Scintilla document from a background thread.
Defines the style of indicators which are text decorations such as underlining.
Defines a mapping between keystrokes and commands.
Defines the look of a line marker in the margin .
Defines the appearance of the editor margin.
Data structure used to partition an interval.
Interface to platform facilities.
#define PLATFORM_ASSERT(c)
Definition: Platform.h:544
Classes for caching layout information.
Defines global type name Position in the Sci internal namespace.
Data structure used to store sparse styles.
Defines an enhanced subclass of Editor with calltips, autocomplete and context menu.
GType scnotification_get_type(void)
static constexpr gint nClipboardPasteTargets
GtkWidget * scintilla_object_new()
void scintilla_set_id(ScintillaObject *sci, uptr_t id)
const char * CharacterSetID(int characterSet)
Definition: PlatGTK.cxx:204
void Platform_Finalise()
Definition: PlatGTK.cxx:2055
std::string UTF8FromLatin1(const char *s, int len)
Definition: PlatGTK.cxx:624
static GObjectClass * scintilla_class_parent_class
@ TARGET_STRING
@ TARGET_UTF8_STRING
@ TARGET_URI
@ TARGET_TEXT
@ TARGET_COMPOUND_TEXT
static constexpr gint nClipboardCopyTargets
GType scintilla_object_get_type()
static GdkWindow * WindowFromWidget(GtkWidget *w) noexcept
static void * copy_(void *src)
static void UnRefCursor(GdkCursor *cursor) noexcept
static void MapWidget(GtkWidget *widget) noexcept
static const GtkTargetEntry clipboardPasteTargets[]
static GdkAtom SelectionOfGSD(GtkSelectionData *sd) noexcept
gintptr scintilla_object_send_message(ScintillaObject *sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam)
#define IS_WIDGET_MAPPED(w)
#define IS_WIDGET_REALIZED(w)
void Platform_Initialise()
Definition: PlatGTK.cxx:2052
static const GdkDragAction actionCopyOrMove
#define SC_INDICATOR_UNKNOWN
static std::vector< int > MapImeIndicators(PangoAttrList *attrs, const char *u8Str)
#define SC_INDICATOR_TARGET
static gint LengthOfGSD(GtkSelectionData *sd) noexcept
#define SC_INDICATOR_INPUT
static GtkWidget * PWidget(const Window &w) noexcept
sptr_t scintilla_send_message(ScintillaObject *sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam)
GType scintilla_get_type()
static gint scintilla_signals[LAST_SIGNAL]
static const GtkTargetEntry clipboardCopyTargets[]
static const guchar * DataOfGSD(GtkSelectionData *sd) noexcept
#define SC_INDICATOR_CONVERTED
GtkWidget * scintilla_new()
static GdkWindow * PWindow(const Window &w) noexcept
static void free_(void *)
static GdkAtom TypeOfGSD(GtkSelectionData *sd) noexcept
static void scintilla_class_init(ScintillaClass *klass)
static int KeyTranslate(int keyIn) noexcept
@ COMMAND_SIGNAL
@ LAST_SIGNAL
@ NOTIFY_SIGNAL
static void scintilla_init(ScintillaObject *sci)
void scintilla_release_resources(void)
#define OBJECT_CLASS
Definition: ScintillaGTK.h:13
Interface to the edit control.
intptr_t sptr_t
Definition: Scintilla.h:35
#define SCI_GETDIRECTPOINTER
Definition: Scintilla.h:458
#define SCK_PRIOR
Definition: Scintilla.h:1098
#define SCK_MENU
Definition: Scintilla.h:1111
#define SCMOD_SUPER
Definition: Scintilla.h:1116
#define INDICATOR_MAX
Definition: Scintilla.h:316
#define SCK_RWIN
Definition: Scintilla.h:1110
#define SCI_SETACCESSIBILITY
Definition: Scintilla.h:622
#define SCI_SETRECTANGULARSELECTIONMODIFIER
Definition: Scintilla.h:964
#define SCK_INSERT
Definition: Scintilla.h:1101
#define INDIC_COMPOSITIONTHICK
Definition: Scintilla.h:301
#define SCK_BACK
Definition: Scintilla.h:1103
#define SC_ACCESSIBILITY_ENABLED
Definition: Scintilla.h:621
#define SCI_ZOOMIN
Definition: Scintilla.h:657
#define SC_STATUS_BADALLOC
Definition: Scintilla.h:734
#define SCK_ADD
Definition: Scintilla.h:1106
#define SCK_DIVIDE
Definition: Scintilla.h:1108
uintptr_t uptr_t
Definition: Scintilla.h:33
#define SC_TECHNOLOGY_DEFAULT
Definition: Scintilla.h:990
#define SCK_DOWN
Definition: Scintilla.h:1092
#define SCK_WIN
Definition: Scintilla.h:1109
#define SCK_DELETE
Definition: Scintilla.h:1100
#define SC_EOL_LF
Definition: Scintilla.h:90
#define SCN_KEY
Definition: Scintilla.h:1131
#define STYLE_DEFAULT
Definition: Scintilla.h:197
#define SCK_HOME
Definition: Scintilla.h:1096
#define SCK_ESCAPE
Definition: Scintilla.h:1102
#define SCI_TARGETASUTF8
Definition: Scintilla.h:833
#define INDIC_HIDDEN
Definition: Scintilla.h:292
#define INDIC_STRAIGHTBOX
Definition: Scintilla.h:295
#define SCMOD_ALT
Definition: Scintilla.h:1115
#define SCMOD_SHIFT
Definition: Scintilla.h:1113
#define SCK_RETURN
Definition: Scintilla.h:1105
#define SCK_RIGHT
Definition: Scintilla.h:1095
#define SCMOD_CTRL
Definition: Scintilla.h:1114
#define SCEN_CHANGE
Definition: Scintilla.h:1089
#define SCK_TAB
Definition: Scintilla.h:1104
#define SCK_NEXT
Definition: Scintilla.h:1099
#define SCI_GRABFOCUS
Definition: Scintilla.h:759
#define SCK_LEFT
Definition: Scintilla.h:1094
#define SC_CP_UTF8
Definition: Scintilla.h:105
#define SC_STATUS_FAILURE
Definition: Scintilla.h:733
#define SCI_GETRECTANGULARSELECTIONMODIFIER
Definition: Scintilla.h:965
#define INDIC_DOTS
Definition: Scintilla.h:297
#define SCK_UP
Definition: Scintilla.h:1093
#define SCI_GETDIRECTFUNCTION
Definition: Scintilla.h:457
#define SCI_ZOOMOUT
Definition: Scintilla.h:658
#define SCN_URIDROPPED
Definition: Scintilla.h:1140
#define SCK_SUBTRACT
Definition: Scintilla.h:1107
#define SCEN_SETFOCUS
Definition: Scintilla.h:1090
#define SCI_SETREADONLY
Definition: Scintilla.h:444
#define SC_CURSORNORMAL
Definition: Scintilla.h:114
#define SCK_END
Definition: Scintilla.h:1097
#define SCI_GETACCESSIBILITY
Definition: Scintilla.h:623
#define SCEN_KILLFOCUS
Definition: Scintilla.h:1091
#define SCI_ENCODEDFROMUTF8
Definition: Scintilla.h:835
#define SC_MULTIPASTE_EACH
Definition: Scintilla.h:612
Classes maintaining the selection.
Main data structure for holding arrays that handle insertions and deletions efficiently.
Safe string copy function which always NUL terminates.
#define ELEMENTS(a)
Definition: StringCopy.h:28
Defines the font and colour style for a class of text.
Functions to handle UTF-8 and UTF-16 strings.
Define UniqueString, a unique_ptr based string type for storage in containers and an allocator for Un...
Store information on how the document is to be viewed.
GeanyBuildCommand ** ptr
Definition: build.c:2679
const gchar * command
Definition: build.c:2677
const gchar * label
Definition: build.c:2676
const char * charSet
size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) override
CaseFolderDBCS(const char *charSet_)
void PaintCT(Surface *surfaceWindow)
Definition: CallTip.cxx:238
Window wCallTip
Definition: CallTip.h:43
void MouseClick(Point pt) noexcept
Definition: CallTip.cxx:265
void SetTranslation(char ch, char chTranslation) noexcept
Definition: CaseFolder.cxx:40
void StandardASCII() noexcept
Definition: CaseFolder.cxx:44
Encapsulate g_iconv safely.
Definition: Converter.h:16
gsize Convert(char **src, gsize *srcleft, char **dst, gsize *dstleft) const noexcept
Definition: Converter.h:64
int dbcsCodePage
Can also be SC_CP_UTF8 to enable UTF-8 mode.
Definition: Document.h:276
Sci::Position InsertString(Sci::Position position, const char *s, Sci::Position insertLength)
Insert a string with a length.
Definition: Document.cxx:1246
int SCI_METHOD Release() override
Definition: Document.cxx:164
void SCI_METHOD DecorationFillRange(Sci_Position position, int value, Sci_Position fillLength) override
Definition: Document.cxx:2438
void SCI_METHOD DecorationSetCurrentIndicator(int indicator) override
Definition: Document.cxx:2434
static std::string TransformLineEnds(const char *s, size_t len, int eolModeWanted)
Definition: Document.cxx:1632
bool TentativeActive() const noexcept
Definition: Document.h:367
bool IsReadOnly() const noexcept
Definition: Document.h:384
Sci_Position SCI_METHOD GetRelativePosition(Sci_Position positionStart, Sci_Position characterOffset) const override
Definition: Document.cxx:925
void TentativeStart()
Definition: Document.h:364
void SCI_METHOD GetCharRange(char *buffer, Sci_Position position, Sci_Position lengthRetrieve) const override
Definition: Document.h:392
int xOffset
Horizontal scrolled amount in pixels.
Definition: EditModel.h:27
enum Scintilla::EditModel::IMEInteraction imeInteraction
Document * pdoc
Definition: EditModel.h:53
SelectionPosition posDrag
Definition: EditModel.h:32
bool imeCaretBlockOverride
Definition: EditView.h:75
void ClearBeforeTentativeStart()
Definition: Editor.cxx:2009
static int ModifierFlags(bool shift, bool ctrl, bool alt, bool meta=false, bool super=false) noexcept
Definition: Editor.cxx:2313
virtual int GetCtrlID()
Definition: Editor.h:429
bool horizontalScrollBarVisible
Definition: Editor.h:186
Point ptMouseLast
Definition: Editor.h:214
enum Scintilla::Editor::@65 paintState
void DwellEnd(bool mouseMoved)
Definition: Editor.cxx:4492
bool IsUnicodeMode() const noexcept
Definition: Editor.cxx:5628
Sci::Position PositionFromLocation(Point pt, bool canReturnInvalid=false, bool charPosition=false)
Definition: Editor.cxx:416
void ScrollTo(Sci::Line line, bool moveThumb=true)
Definition: Editor.cxx:949
SelectionPosition SPositionFromLocation(Point pt, bool canReturnInvalid=false, bool charPosition=false, bool virtualSpace=true)
Definition: Editor.cxx:396
void InsertPasteShape(const char *text, Sci::Position len, PasteShape shape)
Definition: Editor.cxx:2067
PRectangle GetTextRectangle() const
Definition: Editor.cxx:330
int KeyDownWithModifiers(int key, int modifiers, bool *consumed)
Definition: Editor.cxx:3949
virtual void QueueIdleWork(WorkNeeded::workItems items, Sci::Position upTo=0)
Definition: Editor.cxx:5168
virtual void IdleWork()
Definition: Editor.cxx:5158
void ShowCaretAtCurrentPosition()
Definition: Editor.cxx:1420
ViewStyle vs
Definition: Editor.h:171
SelectionText drag
Definition: Editor.h:245
Sci::Line topLine
Definition: Editor.h:227
bool mouseDownCaptures
Definition: Editor.h:182
void SetEmptySelection(SelectionPosition currentPos_)
Definition: Editor.cxx:713
void ButtonMoveWithModifiers(Point pt, unsigned int curTime, int modifiers)
Definition: Editor.cxx:4773
bool paintingAllText
Definition: Editor.h:236
SelectionPosition posDrop
Definition: Editor.h:217
void SetDragPosition(SelectionPosition newPos)
Definition: Editor.cxx:4260
SelectionSegment targetRange
Definition: Editor.h:225
static const char * ConstCharPtrFromUPtr(uptr_t wParam) noexcept
Definition: Editor.h:603
void ClearSelection(bool retainMultipleSelections=false)
Definition: Editor.cxx:2097
bool NotifyUpdateUI()
Definition: Editor.cxx:2407
void SetSelection(SelectionPosition currentPos_, SelectionPosition anchor_)
Definition: Editor.cxx:657
void EnsureCaretVisible(bool useMargin=true, bool vert=true, bool horiz=true)
Definition: Editor.cxx:1414
int multiPasteMode
Definition: Editor.h:195
bool commandEvents
Definition: Editor.h:243
virtual void NotifyFocus(bool focus)
Definition: Editor.cxx:2322
virtual void Redraw()
Definition: Editor.cxx:484
bool PositionInSelection(Sci::Position pos)
PositionInSelection returns true if position in selection.
Definition: Editor.cxx:4370
bool UserVirtualSpace() const noexcept
Definition: Editor.h:311
virtual void TickFor(TickReason reason)
Definition: Editor.cxx:5012
std::string RangeText(Sci::Position start, Sci::Position end) const
Definition: Editor.cxx:4199
void DropAt(SelectionPosition position, const char *value, size_t lengthValue, bool moving, bool rectangular)
Definition: Editor.cxx:4301
void MovePositionTo(SelectionPosition newPos, Selection::selTypes selt=Selection::noSel, bool ensureVisible=true)
Definition: Editor.cxx:876
void SetFocusState(bool focusState)
Definition: Editor.cxx:5061
Sci::Line LinesToScroll() const
Definition: Editor.cxx:344
void CopySelectionRange(SelectionText *ss, bool allowLineCopy=false)
Definition: Editor.cxx:4209
void HorizontalScrollTo(int xPos)
Definition: Editor.cxx:984
Window wMain
On GTK+, Scintilla is a container widget holding two scroll bars whereas on Windows there is just one...
Definition: Editor.h:165
bool SelectionContainsProtected() const
Definition: Editor.cxx:804
void DropGraphics(bool freeObjects)
Definition: Editor.cxx:261
EditView view
Definition: Editor.h:177
bool Wrapping() const noexcept
Definition: Editor.cxx:1469
void Paint(Surface *surfaceWindow, PRectangle rcArea)
Definition: Editor.cxx:1719
static char * CharPtrFromSPtr(sptr_t lParam) noexcept
Definition: Editor.h:594
Sci::Position CurrentPosition() const
Definition: Editor.cxx:561
Sci::Position lengthForEncode
Definition: Editor.h:229
bool PointInSelection(Point pt)
Definition: Editor.cxx:4379
void ButtonUpWithModifiers(Point pt, unsigned int curTime, int modifiers)
Definition: Editor.cxx:4900
bool verticalScrollBarVisible
Definition: Editor.h:188
PRectangle rcPaint
Definition: Editor.h:235
Point PointMainCaret()
Definition: Editor.cxx:936
enum Scintilla::Editor::@64 inDragDrop
virtual void SetDocPointer(Document *document)
Definition: Editor.cxx:5255
IdlerID idlerID
Definition: Editor.h:30
MenuID GetID() const noexcept
Definition: Platform.h:481
A geometric rectangle class.
Definition: Platform.h:131
static constexpr PRectangle FromInts(int left_, int top_, int right_, int bottom_) noexcept
Definition: Platform.h:142
XYPOSITION right
Definition: Platform.h:135
constexpr XYPOSITION Height() const noexcept
Definition: Platform.h:177
constexpr XYPOSITION Width() const noexcept
Definition: Platform.h:176
XYPOSITION bottom
Definition: Platform.h:136
constexpr bool Contains(Point pt) const noexcept
Definition: Platform.h:153
static void DebugPrintf(const char *format,...)
Definition: PlatGTK.cxx:2032
static constexpr long LongFromTwoShorts(short a, short b) noexcept
Definition: Platform.h:532
A geometric point class.
Definition: Platform.h:99
static constexpr Point FromInts(int x_, int y_) noexcept
Definition: Platform.h:107
XYPOSITION y
Definition: Platform.h:102
XYPOSITION x
Definition: Platform.h:101
void Finalise() override
sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) override
bool ShouldDisplayPopup(Point ptInWindowCoordinates) const
void RightButtonDownWithModifiers(Point pt, unsigned int curTime, int modifiers) override
int KeyCommand(unsigned int iMessage) override
void InsertCharacter(const char *s, unsigned int len, CharacterSource charSource) override
void ButtonDownWithModifiers(Point pt, unsigned int curTime, int modifiers) override
void ChangeDocument(Document *oldDoc, Document *newDoc)
static ScintillaGTKAccessible * FromAccessible(GtkAccessible *accessible)
static AtkObject * WidgetGetAccessibleImpl(GtkWidget *widget, AtkObject **cache, gpointer widget_parent_class)
static void Realize(GtkWidget *widget)
void SetVerticalScrollPos() override
static void PopUpCB(GtkMenuItem *menuItem, ScintillaGTK *sciThis)
sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) override
static gboolean TimeOut(gpointer ptt)
void Finalise() override
bool ModifyScrollBars(Sci::Line nMax, Sci::Line nPage) override
PRectangle GetClientRectangle() const override
void SetMouseCapture(bool on) override
static GdkAtom atomString
Definition: ScintillaGTK.h:41
static gint ScrollEvent(GtkWidget *widget, GdkEventScroll *event)
bool PaintContains(PRectangle rc) override
void ScrollText(Sci::Line linesToMove) override
void FineTickerCancel(TickReason reason) override
static void MainForAll(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data)
static AtkObject * GetAccessible(GtkWidget *widget)
static void ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis)
static gboolean Drop(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time)
static gint FocusIn(GtkWidget *widget, GdkEventFocus *event)
gboolean DragMotionThis(GdkDragContext *context, gint x, gint y, guint dragtime)
static gboolean KeyRelease(GtkWidget *widget, GdkEventKey *event)
static gboolean KeyPress(GtkWidget *widget, GdkEventKey *event)
void CommitThis(char *commitStr)
static void Map(GtkWidget *widget)
gboolean ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose)
CaseFolder * CaseFolderForEncoding() override
void NotifyParent(SCNotification scn) override
static gint Press(GtkWidget *widget, GdkEventButton *event)
void ReceivedSelection(GtkSelectionData *selection_data)
gboolean Expose(GtkWidget *widget, GdkEventExpose *ose)
static void DragEnd(GtkWidget *widget, GdkDragContext *context)
bool AbandonPaint() override
If painting then abandon the painting because a wider redraw is needed.
static gint MouseRelease(GtkWidget *widget, GdkEventButton *event)
void NotifyFocus(bool focus) override
static gint FocusOut(GtkWidget *widget, GdkEventFocus *event)
GtkAdjustment * adjustmenth
Definition: ScintillaGTK.h:23
void UnclaimSelection(GdkEventSelection *selection_event)
static void UnRealize(GtkWidget *widget)
void QueueIdleWork(WorkNeeded::workItems items, Sci::Position upTo) override
static void DragDataGet(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time)
gboolean ExposeTextThis(GtkWidget *widget, GdkEventExpose *ose)
GtkAdjustment * adjustmentv
Definition: ScintillaGTK.h:22
void AddToPopUp(const char *label, int cmd=0, bool enabled=true) override
static gint Motion(GtkWidget *widget, GdkEventMotion *event)
static gboolean StyleIdle(gpointer pSci)
GUnicodeScript lastNonCommonScript
Definition: ScintillaGTK.h:54
void CopyToClipboard(const SelectionText &selectedText) override
void IdleWork() override
bool ValidCodePage(int codePage) const override
static void SizeRequest(GtkWidget *widget, GtkRequisition *requisition)
static void ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis)
_ScintillaObject * sci
Definition: ScintillaGTK.h:18
static void DragDataReceived(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time)
bool FineTickerRunning(TickReason reason) override
int KeyDefault(int key, int modifiers) override
void ReconfigureScrollBars() override
void CreateCallTipWindow(PRectangle rc) override
void ClaimSelection() override
GtkIMContext * im_context
Definition: ScintillaGTK.h:53
static void Commit(GtkIMContext *context, char *str, ScintillaGTK *sciThis)
static void RealizeText(GtkWidget *widget, void *)
void UnRealizeThis(GtkWidget *widget)
static void ClassInit(GObjectClass *object_class, GtkWidgetClass *widget_class, GtkContainerClass *container_class)
GObject * MainObject() const noexcept
static void SelectionGet(GtkWidget *widget, GtkSelectionData *selection_data, guint info, guint time)
static void ClipboardClearSelection(GtkClipboard *clip, void *data)
Sci::Position TargetAsUTF8(char *text) const
static void UnMap(GtkWidget *widget)
void Resize(int width, int height)
static void PrimarySelection(GtkWidget *widget, GtkSelectionData *selection_data, guint info, guint time_stamp, ScintillaGTK *sciThis)
static void DragLeave(GtkWidget *widget, GdkDragContext *context, guint time)
static void PreeditChanged(GtkIMContext *context, ScintillaGTK *sciThis)
void SetHorizontalScrollPos() override
gint FocusInThis(GtkWidget *widget)
bool DragThreshold(Point ptStart, Point ptNow) override
static gboolean DragMotion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint dragtime)
void StoreOnClipboard(SelectionText *clipText)
static void StyleSetText(GtkWidget *widget, GtkStyle *previous, void *)
void ReceivedClipboard(GtkClipboard *clipBoard, GtkSelectionData *selection_data) noexcept
static void ClipboardGetSelection(GtkClipboard *clip, GtkSelectionData *selection_data, guint info, void *data)
GtkWidgetClass * parentClass
Definition: ScintillaGTK.h:37
static gboolean PrimaryClear(GtkWidget *widget, GdkEventSelection *event, ScintillaGTK *sciThis)
unsigned int linesPerScroll
Definition: ScintillaGTK.h:57
static void GetSelection(GtkSelectionData *selection_data, guint info, SelectionText *text)
bool HaveMouseCapture() override
static GdkAtom atomUTF8
Definition: ScintillaGTK.h:39
static gboolean ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis)
TimeThunk timers[tickDwell+1]
Definition: ScintillaGTK.h:105
void StartDrag() override
static gboolean IdleCallback(gpointer pSci)
void NotifyURIDropped(const char *list)
gint PressThis(GdkEventButton *event)
static void Dispose(GObject *object)
static gboolean ExposeMain(GtkWidget *widget, GdkEventExpose *ose)
gboolean KeyThis(GdkEventKey *event)
gint FocusOutThis(GtkWidget *widget)
static gint SelectionClear(GtkWidget *widget, GdkEventSelection *selection_event)
static void Destroy(GObject *object)
static sptr_t DirectFunction(sptr_t ptr, unsigned int iMessage, uptr_t wParam, sptr_t lParam)
static GdkAtom atomUTF8Mime
Definition: ScintillaGTK.h:40
static ScintillaGTK * FromWidget(GtkWidget *widget) noexcept
void NotifyKey(int key, int modifiers)
static gboolean ExposeText(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis)
void InsertSelection(GtkClipboard *clipBoard, GtkSelectionData *selectionData)
void GetGtkSelectionText(GtkSelectionData *selectionData, SelectionText &selText)
void RealizeThis(GtkWidget *widget)
sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) override
SelectionText primary
Definition: ScintillaGTK.h:28
void FineTickerStart(TickReason reason, int millis, int tolerance) override
void RequestSelection(GdkAtom atomSelection)
void DrawImeIndicator(int indicator, int len)
static bool IsStringAtom(GdkAtom type)
static void SizeAllocate(GtkWidget *widget, GtkAllocation *allocation)
void ReceivedDrop(GtkSelectionData *selection_data)
static GdkAtom atomDROPFILES_DND
Definition: ScintillaGTK.h:43
void DisplayCursor(Window::Cursor c) override
static void SelectionReceived(GtkWidget *widget, GtkSelectionData *selection_data, guint time)
const char * CharacterSetID() const
static gboolean PressCT(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis)
std::string CaseMapString(const std::string &s, int caseMapping) override
void ForAll(GtkCallback callback, gpointer callback_data)
bool SetIdle(bool on) override
void SetDocPointer(Document *document) override
static GdkAtom atomUriList
Definition: ScintillaGTK.h:42
Sci::Position EncodedFromUTF8(const char *utf8, char *encoded) const
AtkObject * GetAccessibleThis(GtkWidget *widget)
static gboolean ExposeCT(GtkWidget *widget, GdkEventExpose *ose, CallTip *ctip)
void NotifyChange() override
Sci::Position Position() const noexcept
Definition: Selection.h:34
void Add(Sci::Position increment) noexcept
Definition: Selection.h:49
void SetPosition(Sci::Position position_) noexcept
Definition: Selection.h:37
Hold a piece of text selected for copying or dragging, along with encoding and selection format infor...
Definition: Editor.h:65
void Clear() noexcept
Definition: Editor.h:73
void Copy(const std::string &s_, int codePage_, int characterSet_, bool rectangular_, bool lineCopy_)
Definition: Editor.h:80
size_t Length() const noexcept
Definition: Editor.h:94
bool Empty() const noexcept
Definition: Editor.h:100
const char * Data() const noexcept
Definition: Editor.h:91
bool IsRectangular() const noexcept
Definition: Selection.cxx:200
size_t Count() const noexcept
Definition: Selection.cxx:237
SelectionRange & Range(size_t r) noexcept
Definition: Selection.cxx:250
bool Empty() const noexcept
Definition: Selection.cxx:282
static Surface * Allocate(int technology)
Definition: PlatGTK.cxx:964
std::vector< Style > styles
Definition: ViewStyle.h:84
std::vector< Indicator > indicators
Definition: ViewStyle.h:88
Class to hide the details of window manipulation.
Definition: Platform.h:396
bool Created() const noexcept
Definition: Platform.h:413
PRectangle GetClientPosition() const
Definition: PlatGTK.cxx:1059
void SetCursor(Cursor curs)
Definition: PlatGTK.cxx:1088
void InvalidateAll()
Definition: PlatGTK.cxx:1069
void Show(bool show=true)
Definition: PlatGTK.cxx:1064
gchar * text
Definition: editor.c:83
ScintillaObject * sci
Definition: editor.c:88
gint pos
Definition: editor.c:87
tokenInfo * list
unsigned int max
ptrdiff_t Position
Definition: Position.h:19
const Position invalidPosition
Definition: Position.h:22
ptrdiff_t Line
Definition: Position.h:20
Styling buffer using one element for each run rather than using a filled buffer.
Definition: Converter.h:9
constexpr int UTF8MaxBytes
Definition: UniConversion.h:13
float XYPOSITION
Definition: Platform.h:81
std::string ConvertText(const char *s, size_t len, const char *charSetDest, const char *charSetSource, bool transliterations, bool silent)
const gsize sizeFailure
Definition: Converter.h:12
size_t CaseConvertString(char *converted, size_t sizeConverted, const char *mixed, size_t lenMixed, enum CaseConversion conversion)
@ CaseConversionUpper
Definition: CaseConvert.h:17
@ CaseConversionLower
Definition: CaseConvert.h:18
constexpr size_t maxExpansionCaseConversion
Definition: CaseConvert.h:34
#define NULL
Definition: rbtree.h:150
void scintilla_marshal_VOID__INT_BOXED(GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
void scintilla_marshal_VOID__INT_OBJECT(GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
gtk_container_add(GTK_CONTAINER(dialog->vbox), check_button)
Sci_NotifyHeader nmhdr
Definition: Scintilla.h:1229
const char * text
Definition: Scintilla.h:1245
unsigned int code
Definition: Scintilla.h:1225
SelectionPosition caret
Definition: Selection.h:87
SelectionPosition Start() const noexcept
Definition: Selection.h:124
SelectionPosition End() const noexcept
Definition: Selection.h:127
SelectionPosition anchor
Definition: Selection.h:88
Sci::Position Length() const noexcept
Definition: Selection.cxx:83
Sci::Position Length() const noexcept
Definition: Selection.h:75
SelectionPosition end
Definition: Selection.h:60
SelectionPosition start
Definition: Selection.h:59