1
// Scintilla source code edit control
2
// ScintillaGTK.cxx - GTK+ specific subclass of ScintillaBase
3
// Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
4
// The License.txt file describes the conditions under which this software may be distributed.
17
#include <gdk/gdkkeysyms.h>
25
#include "Scintilla.h"
26
#include "ScintillaWidget.h"
30
#include "PropSetSimple.h"
35
#include "SplitVector.h"
36
#include "Partitioning.h"
37
#include "RunStyles.h"
38
#include "ContractionState.h"
39
#include "CellBuffer.h"
42
#include "Indicator.h"
44
#include "LineMarker.h"
46
#include "AutoComplete.h"
47
#include "ViewStyle.h"
48
#include "Decoration.h"
49
#include "CharClassify.h"
51
#include "Selection.h"
52
#include "PositionCache.h"
54
#include "ScintillaBase.h"
55
#include "UniConversion.h"
57
#include "gtk/gtksignal.h"
58
#include "gtk/gtkmarshal.h"
59
#include "scintilla-marshal.h"
64
#include "ExternalLexer.h"
67
#include "Converter.h"
70
// Constant conditional expressions are because of GTK+ headers
71
#pragma warning(disable: 4127)
72
// Ignore unreferenced local functions in GTK+ headers
73
#pragma warning(disable: 4505)
76
#if GTK_CHECK_VERSION(2,6,0)
77
#define USE_GTK_CLIPBOARD
80
#define OBJECT_CLASS GObjectClass
83
using namespace Scintilla;
86
extern char *UTF8FromLatin1(const char *s, int &len);
88
class ScintillaGTK : public ScintillaBase {
89
_ScintillaObject *sci;
93
GtkObject *adjustmentv;
94
GtkObject *adjustmenth;
98
// Because clipboard access is asynchronous, copyText is created by Copy
99
#ifndef USE_GTK_CLIPBOARD
100
SelectionText copyText;
103
SelectionText primary;
105
GdkEventButton evbtn;
109
int rectangularSelectionModifier;
111
GtkWidgetClass *parentClass;
113
static GdkAtom atomClipboard;
114
static GdkAtom atomUTF8;
115
static GdkAtom atomString;
116
static GdkAtom atomUriList;
117
static GdkAtom atomDROPFILES_DND;
121
CLIPFORMAT cfColumnSelect;
126
GtkIMContext *im_context;
128
// Wheel mouse support
129
unsigned int linesPerScroll;
130
GTimeVal lastWheelMouseTime;
131
gint lastWheelMouseDirection;
132
gint wheelMouseIntensity;
134
GdkRegion *rgnUpdate;
136
// Private so ScintillaGTK objects can not be copied
137
ScintillaGTK(const ScintillaGTK &);
138
ScintillaGTK &operator=(const ScintillaGTK &);
141
ScintillaGTK(_ScintillaObject *sci_);
142
virtual ~ScintillaGTK();
143
static void ClassInit(OBJECT_CLASS* object_class, GtkWidgetClass *widget_class, GtkContainerClass *container_class);
145
virtual void Initialise();
146
virtual void Finalise();
147
virtual void DisplayCursor(Window::Cursor c);
148
virtual bool DragThreshold(Point ptStart, Point ptNow);
149
virtual void StartDrag();
150
int TargetAsUTF8(char *text);
151
int EncodedFromUTF8(char *utf8, char *encoded);
152
virtual bool ValidCodePage(int codePage) const;
153
public: // Public for scintilla_send_message
154
virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
156
virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
157
virtual void SetTicking(bool on);
158
virtual bool SetIdle(bool on);
159
virtual void SetMouseCapture(bool on);
160
virtual bool HaveMouseCapture();
161
virtual bool PaintContains(PRectangle rc);
163
virtual PRectangle GetClientRectangle();
164
void SyncPaint(PRectangle rc);
165
virtual void ScrollText(int linesToMove);
166
virtual void SetVerticalScrollPos();
167
virtual void SetHorizontalScrollPos();
168
virtual bool ModifyScrollBars(int nMax, int nPage);
169
void ReconfigureScrollBars();
170
virtual void NotifyChange();
171
virtual void NotifyFocus(bool focus);
172
virtual void NotifyParent(SCNotification scn);
173
void NotifyKey(int key, int modifiers);
174
void NotifyURIDropped(const char *list);
175
const char *CharacterSetID() const;
176
virtual CaseFolder *CaseFolderForEncoding();
177
virtual std::string CaseMapString(const std::string &s, int caseMapping);
178
virtual int KeyDefault(int key, int modifiers);
179
virtual void CopyToClipboard(const SelectionText &selectedText);
181
virtual void Paste();
182
virtual void CreateCallTipWindow(PRectangle rc);
183
virtual void AddToPopUp(const char *label, int cmd = 0, bool enabled = true);
184
bool OwnPrimarySelection();
185
virtual void ClaimSelection();
186
void GetGtkSelectionText(GtkSelectionData *selectionData, SelectionText &selText);
187
void ReceivedSelection(GtkSelectionData *selection_data);
188
void ReceivedDrop(GtkSelectionData *selection_data);
189
static void GetSelection(GtkSelectionData *selection_data, guint info, SelectionText *selected);
190
#ifdef USE_GTK_CLIPBOARD
191
void StoreOnClipboard(SelectionText *clipText);
192
static void ClipboardGetSelection(GtkClipboard* clip, GtkSelectionData *selection_data, guint info, void *data);
193
static void ClipboardClearSelection(GtkClipboard* clip, void *data);
196
void UnclaimSelection(GdkEventSelection *selection_event);
197
void Resize(int width, int height);
199
// Callback functions
200
void RealizeThis(GtkWidget *widget);
201
static void Realize(GtkWidget *widget);
202
void UnRealizeThis(GtkWidget *widget);
203
static void UnRealize(GtkWidget *widget);
205
static void Map(GtkWidget *widget);
207
static void UnMap(GtkWidget *widget);
208
static gint CursorMoved(GtkWidget *widget, int xoffset, int yoffset, ScintillaGTK *sciThis);
209
gint FocusInThis(GtkWidget *widget);
210
static gint FocusIn(GtkWidget *widget, GdkEventFocus *event);
211
gint FocusOutThis(GtkWidget *widget);
212
static gint FocusOut(GtkWidget *widget, GdkEventFocus *event);
213
static void SizeRequest(GtkWidget *widget, GtkRequisition *requisition);
214
static void SizeAllocate(GtkWidget *widget, GtkAllocation *allocation);
215
gint Expose(GtkWidget *widget, GdkEventExpose *ose);
216
static gint ExposeMain(GtkWidget *widget, GdkEventExpose *ose);
217
static void Draw(GtkWidget *widget, GdkRectangle *area);
218
void ForAll(GtkCallback callback, gpointer callback_data);
219
static void MainForAll(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data);
221
static void ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis);
222
static void ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis);
223
gint PressThis(GdkEventButton *event);
224
static gint Press(GtkWidget *widget, GdkEventButton *event);
225
static gint MouseRelease(GtkWidget *widget, GdkEventButton *event);
226
static gint ScrollEvent(GtkWidget *widget, GdkEventScroll *event);
227
static gint Motion(GtkWidget *widget, GdkEventMotion *event);
228
gboolean KeyThis(GdkEventKey *event);
229
static gboolean KeyPress(GtkWidget *widget, GdkEventKey *event);
230
static gboolean KeyRelease(GtkWidget *widget, GdkEventKey *event);
231
gboolean ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose);
232
static gboolean ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis);
233
void CommitThis(char *str);
234
static void Commit(GtkIMContext *context, char *str, ScintillaGTK *sciThis);
235
void PreeditChangedThis();
236
static void PreeditChanged(GtkIMContext *context, ScintillaGTK *sciThis);
237
static gint StyleSetText(GtkWidget *widget, GtkStyle *previous, void*);
238
static gint RealizeText(GtkWidget *widget, void*);
239
static void Destroy(GObject *object);
240
static void SelectionReceived(GtkWidget *widget, GtkSelectionData *selection_data,
242
static void SelectionGet(GtkWidget *widget, GtkSelectionData *selection_data,
243
guint info, guint time);
244
static gint SelectionClear(GtkWidget *widget, GdkEventSelection *selection_event);
245
static void DragBegin(GtkWidget *widget, GdkDragContext *context);
246
gboolean DragMotionThis(GdkDragContext *context, gint x, gint y, guint dragtime);
247
static gboolean DragMotion(GtkWidget *widget, GdkDragContext *context,
248
gint x, gint y, guint dragtime);
249
static void DragLeave(GtkWidget *widget, GdkDragContext *context,
251
static void DragEnd(GtkWidget *widget, GdkDragContext *context);
252
static gboolean Drop(GtkWidget *widget, GdkDragContext *context,
253
gint x, gint y, guint time);
254
static void DragDataReceived(GtkWidget *widget, GdkDragContext *context,
255
gint x, gint y, GtkSelectionData *selection_data, guint info, guint time);
256
static void DragDataGet(GtkWidget *widget, GdkDragContext *context,
257
GtkSelectionData *selection_data, guint info, guint time);
258
static gint TimeOut(ScintillaGTK *sciThis);
259
static gboolean IdleCallback(ScintillaGTK *sciThis);
260
static gboolean StyleIdle(ScintillaGTK *sciThis);
261
virtual void QueueStyling(int upTo);
262
static void PopUpCB(ScintillaGTK *sciThis, guint action, GtkWidget *widget);
264
gint ExposeTextThis(GtkWidget *widget, GdkEventExpose *ose);
265
static gint ExposeText(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis);
267
static gint ExposeCT(GtkWidget *widget, GdkEventExpose *ose, CallTip *ct);
268
static gint PressCT(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis);
270
static sptr_t DirectFunction(ScintillaGTK *sciThis,
271
unsigned int iMessage, uptr_t wParam, sptr_t lParam);
280
static gint scintilla_signals[LAST_SIGNAL] = { 0 };
285
TARGET_COMPOUND_TEXT,
290
GdkAtom ScintillaGTK::atomClipboard = 0;
291
GdkAtom ScintillaGTK::atomUTF8 = 0;
292
GdkAtom ScintillaGTK::atomString = 0;
293
GdkAtom ScintillaGTK::atomUriList = 0;
294
GdkAtom ScintillaGTK::atomDROPFILES_DND = 0;
296
static const GtkTargetEntry clipboardCopyTargets[] = {
297
{ (gchar *) "UTF8_STRING", 0, TARGET_UTF8_STRING },
298
{ (gchar *) "STRING", 0, TARGET_STRING },
300
static const gint nClipboardCopyTargets = sizeof(clipboardCopyTargets) / sizeof(clipboardCopyTargets[0]);
302
static const GtkTargetEntry clipboardPasteTargets[] = {
303
{ (gchar *) "text/uri-list", 0, TARGET_URI },
304
{ (gchar *) "UTF8_STRING", 0, TARGET_UTF8_STRING },
305
{ (gchar *) "STRING", 0, TARGET_STRING },
307
static const gint nClipboardPasteTargets = sizeof(clipboardPasteTargets) / sizeof(clipboardPasteTargets[0]);
309
static GtkWidget *PWidget(Window &w) {
310
return reinterpret_cast<GtkWidget *>(w.GetID());
313
static ScintillaGTK *ScintillaFromWidget(GtkWidget *widget) {
314
ScintillaObject *scio = reinterpret_cast<ScintillaObject *>(widget);
315
return reinterpret_cast<ScintillaGTK *>(scio->pscin);
318
ScintillaGTK::ScintillaGTK(_ScintillaObject *sci_) :
319
adjustmentv(0), adjustmenth(0),
320
scrollBarWidth(30), scrollBarHeight(30),
321
capturedMouse(false), dragWasDropped(false),
322
lastKey(0), rectangularSelectionModifier(SCMOD_CTRL), parentClass(0),
324
lastWheelMouseDirection(0),
325
wheelMouseIntensity(0),
328
wMain = GTK_WIDGET(sci);
331
rectangularSelectionModifier = SCMOD_ALT;
333
rectangularSelectionModifier = SCMOD_CTRL;
337
// There does not seem to be a real standard for indicating that the clipboard
338
// contains a rectangular selection, so copy Developer Studio.
339
cfColumnSelect = static_cast<CLIPFORMAT>(
340
::RegisterClipboardFormat("MSDEVColumnSelect"));
342
// Get intellimouse parameters when running on win32; otherwise use
343
// reasonable default
344
#ifndef SPI_GETWHEELSCROLLLINES
345
#define SPI_GETWHEELSCROLLLINES 104
347
::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &linesPerScroll, 0);
351
lastWheelMouseTime.tv_sec = 0;
352
lastWheelMouseTime.tv_usec = 0;
357
ScintillaGTK::~ScintillaGTK() {
358
g_idle_remove_by_data(this);
361
void ScintillaGTK::RealizeThis(GtkWidget *widget) {
362
//Platform::DebugPrintf("ScintillaGTK::realize this\n");
363
GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
365
attrs.window_type = GDK_WINDOW_CHILD;
366
attrs.x = widget->allocation.x;
367
attrs.y = widget->allocation.y;
368
attrs.width = widget->allocation.width;
369
attrs.height = widget->allocation.height;
370
attrs.wclass = GDK_INPUT_OUTPUT;
371
attrs.visual = gtk_widget_get_visual(widget);
372
attrs.colormap = gtk_widget_get_colormap(widget);
373
attrs.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK;
374
GdkCursor *cursor = gdk_cursor_new(GDK_XTERM);
375
attrs.cursor = cursor;
376
widget->window = gdk_window_new(gtk_widget_get_parent_window(widget), &attrs,
377
GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_CURSOR);
378
gdk_window_set_user_data(widget->window, widget);
379
gdk_window_set_background(widget->window, &widget->style->bg[GTK_STATE_NORMAL]);
380
gdk_window_show(widget->window);
381
gdk_cursor_destroy(cursor);
382
widget->style = gtk_style_attach(widget->style, widget->window);
383
wPreedit = gtk_window_new(GTK_WINDOW_POPUP);
384
wPreeditDraw = gtk_drawing_area_new();
385
GtkWidget *predrw = PWidget(wPreeditDraw); // No code inside the G_OBJECT macro
386
g_signal_connect(G_OBJECT(predrw), "expose_event",
387
G_CALLBACK(ExposePreedit), this);
388
gtk_container_add(GTK_CONTAINER(PWidget(wPreedit)), predrw);
389
gtk_widget_realize(PWidget(wPreedit));
390
gtk_widget_realize(predrw);
391
gtk_widget_show(predrw);
393
im_context = gtk_im_multicontext_new();
394
g_signal_connect(G_OBJECT(im_context), "commit",
395
G_CALLBACK(Commit), this);
396
g_signal_connect(G_OBJECT(im_context), "preedit_changed",
397
G_CALLBACK(PreeditChanged), this);
398
gtk_im_context_set_client_window(im_context, widget->window);
399
GtkWidget *widtxt = PWidget(wText); // // No code inside the G_OBJECT macro
400
g_signal_connect_after(G_OBJECT(widtxt), "style_set",
401
G_CALLBACK(ScintillaGTK::StyleSetText), NULL);
402
g_signal_connect_after(G_OBJECT(widtxt), "realize",
403
G_CALLBACK(ScintillaGTK::RealizeText), NULL);
404
gtk_widget_realize(widtxt);
405
gtk_widget_realize(PWidget(scrollbarv));
406
gtk_widget_realize(PWidget(scrollbarh));
409
void ScintillaGTK::Realize(GtkWidget *widget) {
410
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
411
sciThis->RealizeThis(widget);
414
void ScintillaGTK::UnRealizeThis(GtkWidget *widget) {
416
if (GTK_WIDGET_MAPPED(widget)) {
417
gtk_widget_unmap(widget);
419
GTK_WIDGET_UNSET_FLAGS(widget, GTK_REALIZED);
420
gtk_widget_unrealize(PWidget(wText));
421
gtk_widget_unrealize(PWidget(scrollbarv));
422
gtk_widget_unrealize(PWidget(scrollbarh));
423
gtk_widget_unrealize(PWidget(wPreedit));
424
gtk_widget_unrealize(PWidget(wPreeditDraw));
425
g_object_unref(im_context);
427
if (GTK_WIDGET_CLASS(parentClass)->unrealize)
428
GTK_WIDGET_CLASS(parentClass)->unrealize(widget);
432
errorStatus = SC_STATUS_FAILURE;
436
void ScintillaGTK::UnRealize(GtkWidget *widget) {
437
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
438
sciThis->UnRealizeThis(widget);
441
static void MapWidget(GtkWidget *widget) {
443
GTK_WIDGET_VISIBLE(widget) &&
444
!GTK_WIDGET_MAPPED(widget)) {
445
gtk_widget_map(widget);
449
void ScintillaGTK::MapThis() {
451
//Platform::DebugPrintf("ScintillaGTK::map this\n");
452
GTK_WIDGET_SET_FLAGS(PWidget(wMain), GTK_MAPPED);
453
MapWidget(PWidget(wText));
454
MapWidget(PWidget(scrollbarh));
455
MapWidget(PWidget(scrollbarv));
456
wMain.SetCursor(Window::cursorArrow);
457
scrollbarv.SetCursor(Window::cursorArrow);
458
scrollbarh.SetCursor(Window::cursorArrow);
460
gdk_window_show(PWidget(wMain)->window);
462
errorStatus = SC_STATUS_FAILURE;
466
void ScintillaGTK::Map(GtkWidget *widget) {
467
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
471
void ScintillaGTK::UnMapThis() {
473
//Platform::DebugPrintf("ScintillaGTK::unmap this\n");
474
GTK_WIDGET_UNSET_FLAGS(PWidget(wMain), GTK_MAPPED);
476
gdk_window_hide(PWidget(wMain)->window);
477
gtk_widget_unmap(PWidget(wText));
478
gtk_widget_unmap(PWidget(scrollbarh));
479
gtk_widget_unmap(PWidget(scrollbarv));
481
errorStatus = SC_STATUS_FAILURE;
485
void ScintillaGTK::UnMap(GtkWidget *widget) {
486
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
487
sciThis->UnMapThis();
490
void ScintillaGTK::ForAll(GtkCallback callback, gpointer callback_data) {
492
(*callback) (PWidget(wText), callback_data);
493
(*callback) (PWidget(scrollbarv), callback_data);
494
(*callback) (PWidget(scrollbarh), callback_data);
496
errorStatus = SC_STATUS_FAILURE;
500
void ScintillaGTK::MainForAll(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data) {
501
ScintillaGTK *sciThis = ScintillaFromWidget((GtkWidget *)container);
503
if (callback != NULL && include_internals) {
504
sciThis->ForAll(callback, callback_data);
508
gint ScintillaGTK::CursorMoved(GtkWidget *, int xoffset, int yoffset, ScintillaGTK *sciThis) {
514
gtk_im_context_set_cursor_location(sciThis->im_context, &area);
518
gint ScintillaGTK::FocusInThis(GtkWidget *widget) {
520
GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
522
if (im_context != NULL) {
526
gtk_im_context_get_preedit_string(im_context, &str, NULL, &cursor_pos);
527
if (PWidget(wPreedit) != NULL) {
528
if (strlen(str) > 0) {
529
gtk_widget_show(PWidget(wPreedit));
531
gtk_widget_hide(PWidget(wPreedit));
535
gtk_im_context_focus_in(im_context);
539
errorStatus = SC_STATUS_FAILURE;
544
gint ScintillaGTK::FocusIn(GtkWidget *widget, GdkEventFocus * /*event*/) {
545
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
546
return sciThis->FocusInThis(widget);
549
gint ScintillaGTK::FocusOutThis(GtkWidget *widget) {
551
GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
552
SetFocusState(false);
554
if (PWidget(wPreedit) != NULL)
555
gtk_widget_hide(PWidget(wPreedit));
556
if (im_context != NULL)
557
gtk_im_context_focus_out(im_context);
560
errorStatus = SC_STATUS_FAILURE;
565
gint ScintillaGTK::FocusOut(GtkWidget *widget, GdkEventFocus * /*event*/) {
566
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
567
return sciThis->FocusOutThis(widget);
570
void ScintillaGTK::SizeRequest(GtkWidget *widget, GtkRequisition *requisition) {
571
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
572
requisition->width = 600;
573
requisition->height = gdk_screen_height();
574
GtkRequisition child_requisition;
575
gtk_widget_size_request(PWidget(sciThis->scrollbarh), &child_requisition);
576
gtk_widget_size_request(PWidget(sciThis->scrollbarv), &child_requisition);
579
void ScintillaGTK::SizeAllocate(GtkWidget *widget, GtkAllocation *allocation) {
580
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
582
widget->allocation = *allocation;
583
if (GTK_WIDGET_REALIZED(widget))
584
gdk_window_move_resize(widget->window,
585
widget->allocation.x,
586
widget->allocation.y,
587
widget->allocation.width,
588
widget->allocation.height);
590
sciThis->Resize(allocation->width, allocation->height);
593
sciThis->errorStatus = SC_STATUS_FAILURE;
597
void ScintillaGTK::Initialise() {
598
//Platform::DebugPrintf("ScintillaGTK::Initialise\n");
599
parentClass = reinterpret_cast<GtkWidgetClass *>(
600
gtk_type_class(gtk_container_get_type()));
602
GTK_WIDGET_SET_FLAGS(PWidget(wMain), GTK_CAN_FOCUS);
603
GTK_WIDGET_SET_FLAGS(GTK_WIDGET(PWidget(wMain)), GTK_SENSITIVE);
604
gtk_widget_set_events(PWidget(wMain),
608
| GDK_KEY_RELEASE_MASK
609
| GDK_FOCUS_CHANGE_MASK
610
| GDK_LEAVE_NOTIFY_MASK
611
| GDK_BUTTON_PRESS_MASK
612
| GDK_BUTTON_RELEASE_MASK
613
| GDK_POINTER_MOTION_MASK
614
| GDK_POINTER_MOTION_HINT_MASK);
616
wText = gtk_drawing_area_new();
617
gtk_widget_set_parent(PWidget(wText), PWidget(wMain));
618
GtkWidget *widtxt = PWidget(wText); // No code inside the G_OBJECT macro
619
gtk_widget_show(widtxt);
620
g_signal_connect(G_OBJECT(widtxt), "expose_event",
621
G_CALLBACK(ScintillaGTK::ExposeText), this);
622
gtk_widget_set_events(widtxt, GDK_EXPOSURE_MASK);
623
// Avoid background drawing flash
624
gtk_widget_set_double_buffered(widtxt, FALSE);
625
gtk_drawing_area_size(GTK_DRAWING_AREA(widtxt),
627
adjustmentv = gtk_adjustment_new(0.0, 0.0, 201.0, 1.0, 20.0, 20.0);
628
scrollbarv = gtk_vscrollbar_new(GTK_ADJUSTMENT(adjustmentv));
629
GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarv), GTK_CAN_FOCUS);
630
g_signal_connect(G_OBJECT(adjustmentv), "value_changed",
631
G_CALLBACK(ScrollSignal), this);
632
gtk_widget_set_parent(PWidget(scrollbarv), PWidget(wMain));
633
gtk_widget_show(PWidget(scrollbarv));
635
adjustmenth = gtk_adjustment_new(0.0, 0.0, 101.0, 1.0, 20.0, 20.0);
636
scrollbarh = gtk_hscrollbar_new(GTK_ADJUSTMENT(adjustmenth));
637
GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarh), GTK_CAN_FOCUS);
638
g_signal_connect(G_OBJECT(adjustmenth), "value_changed",
639
G_CALLBACK(ScrollHSignal), this);
640
gtk_widget_set_parent(PWidget(scrollbarh), PWidget(wMain));
641
gtk_widget_show(PWidget(scrollbarh));
643
gtk_widget_grab_focus(PWidget(wMain));
645
gtk_selection_add_targets(GTK_WIDGET(PWidget(wMain)), GDK_SELECTION_PRIMARY,
646
clipboardCopyTargets, nClipboardCopyTargets);
648
#ifndef USE_GTK_CLIPBOARD
649
gtk_selection_add_targets(GTK_WIDGET(PWidget(wMain)), atomClipboard,
650
clipboardPasteTargets, nClipboardPasteTargets);
653
gtk_drag_dest_set(GTK_WIDGET(PWidget(wMain)),
654
GTK_DEST_DEFAULT_ALL, clipboardPasteTargets, nClipboardPasteTargets,
655
static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE));
657
// Set caret period based on GTK settings
658
gboolean blinkOn = false;
659
if (g_object_class_find_property(G_OBJECT_GET_CLASS(
660
G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink")) {
661
g_object_get(G_OBJECT(
662
gtk_settings_get_default()), "gtk-cursor-blink", &blinkOn, NULL);
665
g_object_class_find_property(G_OBJECT_GET_CLASS(
666
G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink-time")) {
668
g_object_get(G_OBJECT(
669
gtk_settings_get_default()), "gtk-cursor-blink-time", &value, NULL);
670
caret.period = gint(value / 1.75);
678
void ScintillaGTK::Finalise() {
680
ScintillaBase::Finalise();
683
void ScintillaGTK::DisplayCursor(Window::Cursor c) {
684
if (cursorMode == SC_CURSORNORMAL)
687
wText.SetCursor(static_cast<Window::Cursor>(cursorMode));
690
bool ScintillaGTK::DragThreshold(Point ptStart, Point ptNow) {
691
return gtk_drag_check_threshold(GTK_WIDGET(PWidget(wMain)),
692
ptStart.x, ptStart.y, ptNow.x, ptNow.y);
695
void ScintillaGTK::StartDrag() {
696
dragWasDropped = false;
697
inDragDrop = ddDragging;
698
GtkTargetList *tl = gtk_target_list_new(clipboardCopyTargets, nClipboardCopyTargets);
699
gtk_drag_begin(GTK_WIDGET(PWidget(wMain)),
701
static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE),
703
reinterpret_cast<GdkEvent *>(&evbtn));
706
static char *ConvertText(int *lenResult, char *s, size_t len, const char *charSetDest,
707
const char *charSetSource, bool transliterations, bool silent=false) {
708
// s is not const because of different versions of iconv disagreeing about const
711
Converter conv(charSetDest, charSetSource, transliterations);
713
destForm = new char[len*3+1];
716
char *pout = destForm;
717
size_t outLeft = len*3+1;
718
size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
719
if (conversions == ((size_t)(-1))) {
721
fprintf(stderr, "iconv %s->%s failed for %s\n",
722
charSetSource, charSetDest, static_cast<char *>(s));
726
//fprintf(stderr, "iconv OK %s %d\n", destForm, pout - destForm);
728
*lenResult = pout - destForm;
731
fprintf(stderr, "Can not iconv %s %s\n", charSetDest, charSetSource);
734
destForm = new char[1];
741
// Returns the target converted to UTF8.
742
// Return the length in bytes.
743
int ScintillaGTK::TargetAsUTF8(char *text) {
744
int targetLength = targetEnd - targetStart;
745
if (IsUnicodeMode()) {
747
pdoc->GetCharRange(text, targetStart, targetLength);
751
const char *charSetBuffer = CharacterSetID();
752
if (*charSetBuffer) {
753
//~ fprintf(stderr, "AsUTF8 %s %d %0d-%0d\n", charSetBuffer, targetLength, targetStart, targetEnd);
754
char *s = new char[targetLength];
756
pdoc->GetCharRange(s, targetStart, targetLength);
757
//~ fprintf(stderr, " \"%s\"\n", s);
759
char *tmputf = ConvertText(&targetLength, s, targetLength, "UTF-8", charSetBuffer, false);
760
memcpy(text, tmputf, targetLength);
762
//~ fprintf(stderr, " \"%s\"\n", text);
768
pdoc->GetCharRange(text, targetStart, targetLength);
772
//~ fprintf(stderr, "Length = %d bytes\n", targetLength);
776
// Translates a nul terminated UTF8 string into the document encoding.
777
// Return the length of the result in bytes.
778
int ScintillaGTK::EncodedFromUTF8(char *utf8, char *encoded) {
779
int inputLength = (lengthForEncode >= 0) ? lengthForEncode : strlen(utf8);
780
if (IsUnicodeMode()) {
782
memcpy(encoded, utf8, inputLength);
787
const char *charSetBuffer = CharacterSetID();
788
if (*charSetBuffer) {
790
char *tmpEncoded = ConvertText(&outLength, utf8, inputLength, charSetBuffer, "UTF-8", true);
793
memcpy(encoded, tmpEncoded, outLength);
800
memcpy(encoded, utf8, inputLength);
809
bool ScintillaGTK::ValidCodePage(int codePage) const {
811
|| codePage == SC_CP_UTF8
815
|| codePage == SC_CP_DBCS;
818
sptr_t ScintillaGTK::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
823
gtk_widget_grab_focus(PWidget(wMain));
826
case SCI_GETDIRECTFUNCTION:
827
return reinterpret_cast<sptr_t>(DirectFunction);
829
case SCI_GETDIRECTPOINTER:
830
return reinterpret_cast<sptr_t>(this);
833
case SCI_LOADLEXERLIBRARY:
834
LexerManager::GetInstance()->Load(reinterpret_cast<const char*>(lParam));
837
case SCI_TARGETASUTF8:
838
return TargetAsUTF8(reinterpret_cast<char*>(lParam));
840
case SCI_ENCODEDFROMUTF8:
841
return EncodedFromUTF8(reinterpret_cast<char*>(wParam),
842
reinterpret_cast<char*>(lParam));
844
case SCI_SETRECTANGULARSELECTIONMODIFIER:
845
rectangularSelectionModifier = wParam;
848
case SCI_GETRECTANGULARSELECTIONMODIFIER:
849
return rectangularSelectionModifier;
852
return ScintillaBase::WndProc(iMessage, wParam, lParam);
854
} catch (std::bad_alloc&) {
855
errorStatus = SC_STATUS_BADALLOC;
857
errorStatus = SC_STATUS_FAILURE;
862
sptr_t ScintillaGTK::DefWndProc(unsigned int, uptr_t, sptr_t) {
866
void ScintillaGTK::SetTicking(bool on) {
867
if (timer.ticking != on) {
870
timer.tickerID = reinterpret_cast<TickerID>(gtk_timeout_add(timer.tickSize, (GtkFunction)TimeOut, this));
872
gtk_timeout_remove(GPOINTER_TO_UINT(timer.tickerID));
875
timer.ticksToWait = caret.period;
878
bool ScintillaGTK::SetIdle(bool on) {
880
// Start idler, if it's not running.
883
idler.idlerID = reinterpret_cast<IdlerID>(
884
g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
885
reinterpret_cast<GSourceFunc>(IdleCallback), this, NULL));
888
// Stop idler, if it's running
891
g_source_remove(GPOINTER_TO_UINT(idler.idlerID));
897
void ScintillaGTK::SetMouseCapture(bool on) {
898
if (mouseDownCaptures) {
900
gtk_grab_add(GTK_WIDGET(PWidget(wMain)));
902
gtk_grab_remove(GTK_WIDGET(PWidget(wMain)));
908
bool ScintillaGTK::HaveMouseCapture() {
909
return capturedMouse;
912
bool ScintillaGTK::PaintContains(PRectangle rc) {
913
bool contains = true;
914
if (paintState == painting) {
915
if (!rcPaint.Contains(rc)) {
917
} else if (rgnUpdate) {
918
GdkRectangle grc = {rc.left, rc.top,
919
rc.right - rc.left, rc.bottom - rc.top};
920
if (gdk_region_rect_in(rgnUpdate, &grc) != GDK_OVERLAP_RECTANGLE_IN) {
928
// Redraw all of text area. This paint will not be abandoned.
929
void ScintillaGTK::FullPaint() {
930
wText.InvalidateAll();
933
PRectangle ScintillaGTK::GetClientRectangle() {
934
PRectangle rc = wMain.GetClientPosition();
935
if (verticalScrollBarVisible)
936
rc.right -= scrollBarWidth;
937
if (horizontalScrollBarVisible && (wrapState == eWrapNone))
938
rc.bottom -= scrollBarHeight;
947
// Synchronously paint a rectangle of the window.
948
void ScintillaGTK::SyncPaint(PRectangle rc) {
949
paintState = painting;
951
PRectangle rcClient = GetClientRectangle();
952
paintingAllText = rcPaint.Contains(rcClient);
953
if ((PWidget(wText))->window) {
954
Surface *sw = Surface::Allocate();
956
sw->Init(PWidget(wText)->window, PWidget(wText));
962
if (paintState == paintAbandoned) {
963
// Painting area was insufficient to cover new styling or brace highlight positions
966
paintState = notPainting;
969
void ScintillaGTK::ScrollText(int linesToMove) {
970
int diff = vs.lineHeight * -linesToMove;
971
//Platform::DebugPrintf("ScintillaGTK::ScrollText %d %d %0d,%0d %0d,%0d\n", linesToMove, diff,
972
// rc.left, rc.top, rc.right, rc.bottom);
973
GtkWidget *wi = PWidget(wText);
975
gdk_window_scroll(wi->window, 0, -diff);
976
gdk_window_process_updates(wi->window, FALSE);
979
void ScintillaGTK::SetVerticalScrollPos() {
981
gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmentv), topLine);
984
void ScintillaGTK::SetHorizontalScrollPos() {
986
gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmenth), xOffset / 2);
989
bool ScintillaGTK::ModifyScrollBars(int nMax, int nPage) {
990
bool modified = false;
991
int pageScroll = LinesToScroll();
993
if (GTK_ADJUSTMENT(adjustmentv)->upper != (nMax + 1) ||
994
GTK_ADJUSTMENT(adjustmentv)->page_size != nPage ||
995
GTK_ADJUSTMENT(adjustmentv)->page_increment != pageScroll) {
996
GTK_ADJUSTMENT(adjustmentv)->upper = nMax + 1;
997
GTK_ADJUSTMENT(adjustmentv)->page_size = nPage;
998
GTK_ADJUSTMENT(adjustmentv)->page_increment = pageScroll;
999
gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv));
1003
PRectangle rcText = GetTextRectangle();
1004
int horizEndPreferred = scrollWidth;
1005
if (horizEndPreferred < 0)
1006
horizEndPreferred = 0;
1007
unsigned int pageWidth = rcText.Width();
1008
unsigned int pageIncrement = pageWidth / 3;
1009
unsigned int charWidth = vs.styles[STYLE_DEFAULT].aveCharWidth;
1010
if (GTK_ADJUSTMENT(adjustmenth)->upper != horizEndPreferred ||
1011
GTK_ADJUSTMENT(adjustmenth)->page_size != pageWidth ||
1012
GTK_ADJUSTMENT(adjustmenth)->page_increment != pageIncrement ||
1013
GTK_ADJUSTMENT(adjustmenth)->step_increment != charWidth) {
1014
GTK_ADJUSTMENT(adjustmenth)->upper = horizEndPreferred;
1015
GTK_ADJUSTMENT(adjustmenth)->step_increment = charWidth;
1016
GTK_ADJUSTMENT(adjustmenth)->page_size = pageWidth;
1017
GTK_ADJUSTMENT(adjustmenth)->page_increment = pageIncrement;
1018
gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth));
1024
void ScintillaGTK::ReconfigureScrollBars() {
1025
PRectangle rc = wMain.GetClientPosition();
1026
Resize(rc.Width(), rc.Height());
1029
void ScintillaGTK::NotifyChange() {
1030
g_signal_emit(G_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL], 0,
1031
Platform::LongFromTwoShorts(GetCtrlID(), SCEN_CHANGE), PWidget(wMain));
1034
void ScintillaGTK::NotifyFocus(bool focus) {
1035
g_signal_emit(G_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL], 0,
1036
Platform::LongFromTwoShorts
1037
(GetCtrlID(), focus ? SCEN_SETFOCUS : SCEN_KILLFOCUS), PWidget(wMain));
1040
void ScintillaGTK::NotifyParent(SCNotification scn) {
1041
scn.nmhdr.hwndFrom = PWidget(wMain);
1042
scn.nmhdr.idFrom = GetCtrlID();
1043
g_signal_emit(G_OBJECT(sci), scintilla_signals[NOTIFY_SIGNAL], 0,
1047
void ScintillaGTK::NotifyKey(int key, int modifiers) {
1048
SCNotification scn = {0};
1049
scn.nmhdr.code = SCN_KEY;
1051
scn.modifiers = modifiers;
1056
void ScintillaGTK::NotifyURIDropped(const char *list) {
1057
SCNotification scn = {0};
1058
scn.nmhdr.code = SCN_URIDROPPED;
1064
const char *CharacterSetID(int characterSet);
1066
const char *ScintillaGTK::CharacterSetID() const {
1067
return ::CharacterSetID(vs.styles[STYLE_DEFAULT].characterSet);
1070
class CaseFolderUTF8 : public CaseFolderTable {
1075
virtual size_t Fold(char *folded, size_t sizeFolded, const char *mixed, size_t lenMixed) {
1076
if ((lenMixed == 1) && (sizeFolded > 0)) {
1077
folded[0] = mapping[static_cast<unsigned char>(mixed[0])];
1080
gchar *mapped = g_utf8_casefold(mixed, lenMixed);
1081
size_t lenMapped = strlen(mapped);
1082
if (lenMapped < sizeFolded) {
1083
memcpy(folded, mapped, lenMapped);
1093
CaseFolder *ScintillaGTK::CaseFolderForEncoding() {
1094
if (pdoc->dbcsCodePage == SC_CP_UTF8) {
1095
return new CaseFolderUTF8();
1097
CaseFolderTable *pcf = new CaseFolderTable();
1098
const char *charSetBuffer = CharacterSetID();
1099
if ((pdoc->dbcsCodePage == 0) && charSetBuffer) {
1100
pcf->StandardASCII();
1101
// Only for single byte encodings
1102
for (int i=0x80; i<0x100; i++) {
1103
char sCharacter[2] = "A";
1105
int convertedLength = 1;
1106
const char *sUTF8 = ConvertText(&convertedLength, sCharacter, 1,
1107
"UTF-8", charSetBuffer, false);
1109
gchar *mapped = g_utf8_casefold(sUTF8, strlen(sUTF8));
1111
int mappedLength = strlen(mapped);
1112
const char *mappedBack = ConvertText(&mappedLength, mapped,
1113
mappedLength, charSetBuffer, "UTF-8", false, true);
1114
if (mappedBack && (strlen(mappedBack) == 1) && (mappedBack[0] != sCharacter[0])) {
1115
pcf->SetTranslation(sCharacter[0], mappedBack[0]);
1117
delete []mappedBack;
1128
std::string ScintillaGTK::CaseMapString(const std::string &s, int caseMapping) {
1130
return std::string();
1132
if (caseMapping == cmSame)
1135
const char *needsFree1 = 0; // Must be freed with delete []
1136
const char *charSetBuffer = CharacterSetID();
1137
const char *sUTF8 = s.c_str();
1138
int rangeBytes = s.size();
1140
int convertedLength = rangeBytes;
1141
// Change text to UTF-8
1142
if (!IsUnicodeMode()) {
1144
if (*charSetBuffer) {
1145
sUTF8 = ConvertText(&convertedLength, const_cast<char *>(s.c_str()), rangeBytes,
1146
"UTF-8", charSetBuffer, false);
1150
gchar *mapped; // Must be freed with g_free
1151
if (caseMapping == cmUpper) {
1152
mapped = g_utf8_strup(sUTF8, convertedLength);
1154
mapped = g_utf8_strdown(sUTF8, convertedLength);
1156
int mappedLength = strlen(mapped);
1157
char *mappedBack = mapped;
1159
char *needsFree2 = 0; // Must be freed with delete []
1160
if (!IsUnicodeMode()) {
1161
if (*charSetBuffer) {
1162
mappedBack = ConvertText(&mappedLength, mapped, mappedLength, charSetBuffer, "UTF-8", false);
1163
needsFree2 = mappedBack;
1167
std::string ret(mappedBack, mappedLength);
1169
delete []needsFree1;
1170
delete []needsFree2;
1174
int ScintillaGTK::KeyDefault(int key, int modifiers) {
1175
if (!(modifiers & SCI_CTRL) && !(modifiers & SCI_ALT)) {
1177
NotifyKey(key, modifiers);
1180
// Pass up to container in case it is an accelerator
1181
NotifyKey(key, modifiers);
1185
// Pass up to container in case it is an accelerator
1186
NotifyKey(key, modifiers);
1189
//Platform::DebugPrintf("SK-key: %d %x %x\n",key, modifiers);
1192
void ScintillaGTK::CopyToClipboard(const SelectionText &selectedText) {
1193
#ifndef USE_GTK_CLIPBOARD
1194
copyText.Copy(selectedText);
1195
gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)),
1199
SelectionText *clipText = new SelectionText();
1200
clipText->Copy(selectedText);
1201
StoreOnClipboard(clipText);
1205
void ScintillaGTK::Copy() {
1207
#ifndef USE_GTK_CLIPBOARD
1208
CopySelectionRange(©Text);
1209
gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)),
1213
SelectionText *clipText = new SelectionText();
1214
CopySelectionRange(clipText);
1215
StoreOnClipboard(clipText);
1218
if (sel.IsRectangular()) {
1219
::OpenClipboard(NULL);
1220
::SetClipboardData(cfColumnSelect, 0);
1227
void ScintillaGTK::Paste() {
1228
atomSought = atomUTF8;
1229
gtk_selection_convert(GTK_WIDGET(PWidget(wMain)),
1230
atomClipboard, atomSought, GDK_CURRENT_TIME);
1233
void ScintillaGTK::CreateCallTipWindow(PRectangle rc) {
1234
if (!ct.wCallTip.Created()) {
1235
ct.wCallTip = gtk_window_new(GTK_WINDOW_POPUP);
1236
ct.wDraw = gtk_drawing_area_new();
1237
GtkWidget *widcdrw = PWidget(ct.wDraw); // // No code inside the G_OBJECT macro
1238
gtk_container_add(GTK_CONTAINER(PWidget(ct.wCallTip)), widcdrw);
1239
g_signal_connect(G_OBJECT(widcdrw), "expose_event",
1240
G_CALLBACK(ScintillaGTK::ExposeCT), &ct);
1241
g_signal_connect(G_OBJECT(widcdrw), "button_press_event",
1242
G_CALLBACK(ScintillaGTK::PressCT), static_cast<void *>(this));
1243
gtk_widget_set_events(widcdrw,
1244
GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
1246
gtk_drawing_area_size(GTK_DRAWING_AREA(PWidget(ct.wDraw)),
1247
rc.Width(), rc.Height());
1249
if (PWidget(ct.wCallTip)->window) {
1250
gdk_window_resize(PWidget(ct.wCallTip)->window, rc.Width(), rc.Height());
1254
void ScintillaGTK::AddToPopUp(const char *label, int cmd, bool enabled) {
1255
char fulllabel[200];
1256
strcpy(fulllabel, "/");
1257
strcat(fulllabel, label);
1258
GtkItemFactoryCallback menuSig = GtkItemFactoryCallback(PopUpCB);
1259
GtkItemFactoryEntry itemEntry = {
1263
const_cast<gchar *>(label[0] ? "<Item>" : "<Separator>"),
1266
gtk_item_factory_create_item(GTK_ITEM_FACTORY(popup.GetID()),
1267
&itemEntry, this, 1);
1269
GtkWidget *item = gtk_item_factory_get_widget_by_action(
1270
reinterpret_cast<GtkItemFactory *>(popup.GetID()), cmd);
1272
gtk_widget_set_sensitive(item, enabled);
1276
bool ScintillaGTK::OwnPrimarySelection() {
1277
return ((gdk_selection_owner_get(GDK_SELECTION_PRIMARY)
1278
== GTK_WIDGET(PWidget(wMain))->window) &&
1279
(GTK_WIDGET(PWidget(wMain))->window != NULL));
1282
void ScintillaGTK::ClaimSelection() {
1283
// X Windows has a 'primary selection' as well as the clipboard.
1284
// Whenever the user selects some text, we become the primary selection
1285
if (!sel.Empty() && GTK_WIDGET_REALIZED(GTK_WIDGET(PWidget(wMain)))) {
1286
primarySelection = true;
1287
gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)),
1288
GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
1290
} else if (OwnPrimarySelection()) {
1291
primarySelection = true;
1292
if (primary.s == NULL)
1293
gtk_selection_owner_set(NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
1295
primarySelection = false;
1300
// Detect rectangular text, convert line ends to current mode, convert from or to UTF-8
1301
void ScintillaGTK::GetGtkSelectionText(GtkSelectionData *selectionData, SelectionText &selText) {
1302
char *data = reinterpret_cast<char *>(selectionData->data);
1303
int len = selectionData->length;
1304
GdkAtom selectionTypeData = selectionData->type;
1306
// Return empty string if selection is not a string
1307
if ((selectionTypeData != GDK_TARGET_STRING) && (selectionTypeData != atomUTF8)) {
1308
char *empty = new char[1];
1310
selText.Set(empty, 0, SC_CP_UTF8, 0, false, false);
1314
// Check for "\n\0" ending to string indicating that selection is rectangular
1317
isRectangular = ::IsClipboardFormatAvailable(cfColumnSelect) != 0;
1319
isRectangular = ((len > 2) && (data[len - 1] == 0 && data[len - 2] == '\n'));
1321
len--; // Forget the extra '\0'
1325
if (selectionTypeData == GDK_TARGET_STRING) {
1326
dest = Document::TransformLineEnds(&len, data, len, pdoc->eolMode);
1327
if (IsUnicodeMode()) {
1328
// Unknown encoding so assume in Latin1
1329
char *destPrevious = dest;
1330
dest = UTF8FromLatin1(dest, len);
1331
selText.Set(dest, len, SC_CP_UTF8, 0, selText.rectangular, false);
1332
delete []destPrevious;
1334
// Assume buffer is in same encoding as selection
1335
selText.Set(dest, len, pdoc->dbcsCodePage,
1336
vs.styles[STYLE_DEFAULT].characterSet, isRectangular, false);
1339
dest = Document::TransformLineEnds(&len, data, len, pdoc->eolMode);
1340
selText.Set(dest, len, SC_CP_UTF8, 0, isRectangular, false);
1341
const char *charSetBuffer = CharacterSetID();
1342
if (!IsUnicodeMode() && *charSetBuffer) {
1343
// Convert to locale
1344
dest = ConvertText(&len, selText.s, selText.len, charSetBuffer, "UTF-8", true);
1345
selText.Set(dest, len, pdoc->dbcsCodePage,
1346
vs.styles[STYLE_DEFAULT].characterSet, selText.rectangular, false);
1351
void ScintillaGTK::ReceivedSelection(GtkSelectionData *selection_data) {
1353
if ((selection_data->selection == atomClipboard) ||
1354
(selection_data->selection == GDK_SELECTION_PRIMARY)) {
1355
if ((atomSought == atomUTF8) && (selection_data->length <= 0)) {
1356
atomSought = atomString;
1357
gtk_selection_convert(GTK_WIDGET(PWidget(wMain)),
1358
selection_data->selection, atomSought, GDK_CURRENT_TIME);
1359
} else if ((selection_data->length > 0) &&
1360
((selection_data->type == GDK_TARGET_STRING) || (selection_data->type == atomUTF8))) {
1361
SelectionText selText;
1362
GetGtkSelectionText(selection_data, selText);
1365
if (selection_data->selection != GDK_SELECTION_PRIMARY) {
1368
SelectionPosition selStart = sel.IsRectangular() ?
1369
sel.Rectangular().Start() :
1370
sel.Range(sel.Main()).Start();
1372
if (selText.rectangular) {
1373
PasteRectangular(selStart, selText.s, selText.len);
1375
InsertPaste(selStart, selText.s, selText.len);
1377
EnsureCaretVisible();
1380
// else fprintf(stderr, "Target non string %d %d\n", (int)(selection_data->type),
1381
// (int)(atomUTF8));
1384
errorStatus = SC_STATUS_FAILURE;
1388
void ScintillaGTK::ReceivedDrop(GtkSelectionData *selection_data) {
1389
dragWasDropped = true;
1390
if (selection_data->type == atomUriList || selection_data->type == atomDROPFILES_DND) {
1391
char *ptr = new char[selection_data->length + 1];
1392
ptr[selection_data->length] = '\0';
1393
memcpy(ptr, selection_data->data, selection_data->length);
1394
NotifyURIDropped(ptr);
1396
} else if ((selection_data->type == GDK_TARGET_STRING) || (selection_data->type == atomUTF8)) {
1397
if (selection_data->length > 0) {
1398
SelectionText selText;
1399
GetGtkSelectionText(selection_data, selText);
1400
DropAt(posDrop, selText.s, false, selText.rectangular);
1402
} else if (selection_data->length > 0) {
1403
//~ fprintf(stderr, "ReceivedDrop other %p\n", static_cast<void *>(selection_data->type));
1410
void ScintillaGTK::GetSelection(GtkSelectionData *selection_data, guint info, SelectionText *text) {
1412
// GDK on Win32 expands any \n into \r\n, so make a copy of
1413
// the clip text now with newlines converted to \n. Use { } to hide symbols
1415
SelectionText *newline_normalized = NULL;
1418
char *tmpstr = Document::TransformLineEnds(&tmpstr_len, text->s, text->len, SC_EOL_LF);
1419
newline_normalized = new SelectionText();
1420
newline_normalized->Set(tmpstr, tmpstr_len, SC_CP_UTF8, 0, text->rectangular, false);
1421
text = newline_normalized;
1425
// Convert text to utf8 if it isn't already
1426
SelectionText *converted = 0;
1427
if ((text->codePage != SC_CP_UTF8) && (info == TARGET_UTF8_STRING)) {
1428
const char *charSet = ::CharacterSetID(text->characterSet);
1431
char* tmputf = ConvertText(&new_len, text->s, text->len, "UTF-8", charSet, false);
1432
converted = new SelectionText();
1433
converted->Set(tmputf, new_len, SC_CP_UTF8, 0, text->rectangular, false);
1438
// Here is a somewhat evil kludge.
1439
// As I can not work out how to store data on the clipboard in multiple formats
1440
// and need some way to mark the clipping as being stream or rectangular,
1441
// the terminating \0 is included in the length for rectangular clippings.
1442
// All other tested aplications behave benignly by ignoring the \0.
1443
// The #if is here because on Windows cfColumnSelect clip entry is used
1444
// instead as standard indicator of rectangularness (so no need to kludge)
1445
const char *textData = text->s ? text->s : "";
1446
int len = strlen(textData);
1447
#if PLAT_GTK_WIN32 == 0
1448
if (text->rectangular)
1452
if (info == TARGET_UTF8_STRING) {
1453
gtk_selection_data_set_text(selection_data, textData, len);
1455
gtk_selection_data_set(selection_data,
1456
static_cast<GdkAtom>(GDK_SELECTION_TYPE_STRING),
1457
8, reinterpret_cast<const unsigned char *>(textData), len);
1462
delete newline_normalized;
1466
#ifdef USE_GTK_CLIPBOARD
1467
void ScintillaGTK::StoreOnClipboard(SelectionText *clipText) {
1468
GtkClipboard *clipBoard =
1469
gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain)), atomClipboard);
1470
if (clipBoard == NULL) // Occurs if widget isn't in a toplevel
1473
if (gtk_clipboard_set_with_data(clipBoard, clipboardCopyTargets, nClipboardCopyTargets,
1474
ClipboardGetSelection, ClipboardClearSelection, clipText)) {
1475
gtk_clipboard_set_can_store(clipBoard, clipboardCopyTargets, nClipboardCopyTargets);
1479
void ScintillaGTK::ClipboardGetSelection(GtkClipboard *, GtkSelectionData *selection_data, guint info, void *data) {
1480
GetSelection(selection_data, info, static_cast<SelectionText*>(data));
1483
void ScintillaGTK::ClipboardClearSelection(GtkClipboard *, void *data) {
1484
SelectionText *obj = static_cast<SelectionText*>(data);
1489
void ScintillaGTK::UnclaimSelection(GdkEventSelection *selection_event) {
1491
//Platform::DebugPrintf("UnclaimSelection\n");
1492
if (selection_event->selection == GDK_SELECTION_PRIMARY) {
1493
//Platform::DebugPrintf("UnclaimPrimarySelection\n");
1494
if (!OwnPrimarySelection()) {
1496
primarySelection = false;
1501
errorStatus = SC_STATUS_FAILURE;
1505
void ScintillaGTK::Resize(int width, int height) {
1506
//Platform::DebugPrintf("Resize %d %d\n", width, height);
1507
//printf("Resize %d %d\n", width, height);
1509
// Not always needed, but some themes can have different sizes of scrollbars
1510
scrollBarWidth = GTK_WIDGET(PWidget(scrollbarv))->requisition.width;
1511
scrollBarHeight = GTK_WIDGET(PWidget(scrollbarh))->requisition.height;
1513
// These allocations should never produce negative sizes as they would wrap around to huge
1514
// unsigned numbers inside GTK+ causing warnings.
1515
bool showSBHorizontal = horizontalScrollBarVisible && (wrapState == eWrapNone);
1516
int horizontalScrollBarHeight = scrollBarHeight;
1517
if (!showSBHorizontal)
1518
horizontalScrollBarHeight = 0;
1520
GtkAllocation alloc;
1521
if (showSBHorizontal) {
1522
gtk_widget_show(GTK_WIDGET(PWidget(scrollbarh)));
1524
alloc.y = height - scrollBarHeight;
1525
alloc.width = Platform::Maximum(1, width - scrollBarWidth) + 1;
1526
alloc.height = horizontalScrollBarHeight;
1527
gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarh)), &alloc);
1529
gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarh)));
1532
if (verticalScrollBarVisible) {
1533
gtk_widget_show(GTK_WIDGET(PWidget(scrollbarv)));
1534
alloc.x = width - scrollBarWidth;
1536
alloc.width = scrollBarWidth;
1537
alloc.height = Platform::Maximum(1, height - scrollBarHeight) + 1;
1538
if (!showSBHorizontal)
1539
alloc.height += scrollBarWidth-1;
1540
gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarv)), &alloc);
1542
gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarv)));
1544
if (GTK_WIDGET_MAPPED(PWidget(wMain))) {
1550
alloc.width = Platform::Maximum(1, width - scrollBarWidth);
1551
alloc.height = Platform::Maximum(1, height - scrollBarHeight);
1552
if (!showSBHorizontal)
1553
alloc.height += scrollBarHeight;
1554
if (!verticalScrollBarVisible)
1555
alloc.width += scrollBarWidth;
1556
gtk_widget_size_allocate(GTK_WIDGET(PWidget(wText)), &alloc);
1559
static void SetAdjustmentValue(GtkObject *object, int value) {
1560
GtkAdjustment *adjustment = GTK_ADJUSTMENT(object);
1561
int maxValue = static_cast<int>(
1562
adjustment->upper - adjustment->page_size);
1563
if (value > maxValue)
1567
gtk_adjustment_set_value(adjustment, value);
1570
static int modifierTranslated(int sciModifier) {
1571
switch (sciModifier) {
1573
return GDK_SHIFT_MASK;
1575
return GDK_CONTROL_MASK;
1577
return GDK_MOD1_MASK;
1579
return GDK_MOD4_MASK;
1585
gint ScintillaGTK::PressThis(GdkEventButton *event) {
1587
//Platform::DebugPrintf("Press %x time=%d state = %x button = %x\n",this,event->time, event->state, event->button);
1588
// Do not use GTK+ double click events as Scintilla has its own double click detection
1589
if (event->type != GDK_BUTTON_PRESS)
1594
pt.x = int(event->x);
1595
pt.y = int(event->y);
1596
PRectangle rcClient = GetClientRectangle();
1597
//Platform::DebugPrintf("Press %0d,%0d in %0d,%0d %0d,%0d\n",
1598
// pt.x, pt.y, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1599
if ((pt.x > rcClient.right) || (pt.y > rcClient.bottom)) {
1600
Platform::DebugPrintf("Bad location\n");
1604
bool ctrl = (event->state & GDK_CONTROL_MASK) != 0;
1606
gtk_widget_grab_focus(PWidget(wMain));
1607
if (event->button == 1) {
1608
// On X, instead of sending literal modifiers use the user specified
1609
// modifier, defaulting to control instead of alt.
1610
// This is because most X window managers grab alt + click for moving
1611
ButtonDown(pt, event->time,
1612
(event->state & GDK_SHIFT_MASK) != 0,
1613
(event->state & GDK_CONTROL_MASK) != 0,
1614
(event->state & modifierTranslated(rectangularSelectionModifier)) != 0);
1615
} else if (event->button == 2) {
1616
// Grab the primary selection if it exists
1617
SelectionPosition pos = SPositionFromLocation(pt, false, false, UserVirtualSpace());
1618
if (OwnPrimarySelection() && primary.s == NULL)
1619
CopySelectionRange(&primary);
1622
SetSelection(pos, pos);
1623
atomSought = atomUTF8;
1624
gtk_selection_convert(GTK_WIDGET(PWidget(wMain)), GDK_SELECTION_PRIMARY,
1625
atomSought, event->time);
1626
} else if (event->button == 3) {
1627
if (displayPopupMenu) {
1629
// Convert to screen
1632
gdk_window_get_origin(PWidget(wMain)->window, &ox, &oy);
1633
ContextMenu(Point(pt.x + ox, pt.y + oy));
1637
} else if (event->button == 4) {
1638
// Wheel scrolling up (only GTK 1.x does it this way)
1640
SetAdjustmentValue(adjustmenth, (xOffset / 2) - 6);
1642
SetAdjustmentValue(adjustmentv, topLine - 3);
1643
} else if (event->button == 5) {
1644
// Wheel scrolling down (only GTK 1.x does it this way)
1646
SetAdjustmentValue(adjustmenth, (xOffset / 2) + 6);
1648
SetAdjustmentValue(adjustmentv, topLine + 3);
1651
errorStatus = SC_STATUS_FAILURE;
1656
gint ScintillaGTK::Press(GtkWidget *widget, GdkEventButton *event) {
1657
if (event->window != widget->window)
1659
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
1660
return sciThis->PressThis(event);
1663
gint ScintillaGTK::MouseRelease(GtkWidget *widget, GdkEventButton *event) {
1664
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
1666
//Platform::DebugPrintf("Release %x %d %d\n",sciThis,event->time,event->state);
1667
if (!sciThis->HaveMouseCapture())
1669
if (event->button == 1) {
1671
pt.x = int(event->x);
1672
pt.y = int(event->y);
1673
//Platform::DebugPrintf("Up %x %x %d %d %d\n",
1674
// sciThis,event->window,event->time, pt.x, pt.y);
1675
if (event->window != PWidget(sciThis->wMain)->window)
1676
// If mouse released on scroll bar then the position is relative to the
1677
// scrollbar, not the drawing window so just repeat the most recent point.
1678
pt = sciThis->ptMouseLast;
1679
sciThis->ButtonUp(pt, event->time, (event->state & 4) != 0);
1682
sciThis->errorStatus = SC_STATUS_FAILURE;
1687
// win32gtk and GTK >= 2 use SCROLL_* events instead of passing the
1688
// button4/5/6/7 events to the GTK app
1689
gint ScintillaGTK::ScrollEvent(GtkWidget *widget,
1690
GdkEventScroll *event) {
1691
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
1694
if (widget == NULL || event == NULL)
1697
// Compute amount and direction to scroll (even tho on win32 there is
1698
// intensity of scrolling info in the native message, gtk doesn't
1699
// support this so we simulate similarly adaptive scrolling)
1700
// Note that this is disabled on OS X (Darwin) where the X11 server already has
1701
// and adaptive scrolling algorithm that fights with this one
1703
#if defined(__MWERKS__) || defined(__APPLE_CPP__) || defined(__APPLE_CC__)
1704
cLineScroll = sciThis->linesPerScroll;
1705
if (cLineScroll == 0)
1707
sciThis->wheelMouseIntensity = cLineScroll;
1709
int timeDelta = 1000000;
1711
g_get_current_time(&curTime);
1712
if (curTime.tv_sec == sciThis->lastWheelMouseTime.tv_sec)
1713
timeDelta = curTime.tv_usec - sciThis->lastWheelMouseTime.tv_usec;
1714
else if (curTime.tv_sec == sciThis->lastWheelMouseTime.tv_sec + 1)
1715
timeDelta = 1000000 + (curTime.tv_usec - sciThis->lastWheelMouseTime.tv_usec);
1716
if ((event->direction == sciThis->lastWheelMouseDirection) && (timeDelta < 250000)) {
1717
if (sciThis->wheelMouseIntensity < 12)
1718
sciThis->wheelMouseIntensity++;
1719
cLineScroll = sciThis->wheelMouseIntensity;
1721
cLineScroll = sciThis->linesPerScroll;
1722
if (cLineScroll == 0)
1724
sciThis->wheelMouseIntensity = cLineScroll;
1727
if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_LEFT) {
1730
g_get_current_time(&sciThis->lastWheelMouseTime);
1731
sciThis->lastWheelMouseDirection = event->direction;
1733
// Note: Unpatched versions of win32gtk don't set the 'state' value so
1734
// only regular scrolling is supported there. Also, unpatched win32gtk
1735
// issues spurious button 2 mouse events during wheeling, which can cause
1736
// problems (a patch for both was submitted by archaeopteryx.com on 13Jun2001)
1738
// Data zoom not supported
1739
if (event->state & GDK_SHIFT_MASK) {
1743
// Horizontal scrolling
1744
if (event->direction == GDK_SCROLL_LEFT || event->direction == GDK_SCROLL_RIGHT) {
1745
sciThis->HorizontalScrollTo(sciThis->xOffset + cLineScroll);
1747
// Text font size zoom
1748
} else if (event->state & GDK_CONTROL_MASK) {
1749
if (cLineScroll < 0) {
1750
sciThis->KeyCommand(SCI_ZOOMIN);
1752
sciThis->KeyCommand(SCI_ZOOMOUT);
1755
// Regular scrolling
1757
sciThis->ScrollTo(sciThis->topLine + cLineScroll);
1761
sciThis->errorStatus = SC_STATUS_FAILURE;
1766
gint ScintillaGTK::Motion(GtkWidget *widget, GdkEventMotion *event) {
1767
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
1769
//Platform::DebugPrintf("Motion %x %d\n",sciThis,event->time);
1770
if (event->window != widget->window)
1774
GdkModifierType state;
1775
if (event->is_hint) {
1776
gdk_window_get_pointer(event->window, &x, &y, &state);
1778
x = static_cast<int>(event->x);
1779
y = static_cast<int>(event->y);
1780
state = static_cast<GdkModifierType>(event->state);
1782
//Platform::DebugPrintf("Move %x %x %d %c %d %d\n",
1783
// sciThis,event->window,event->time,event->is_hint? 'h' :'.', x, y);
1785
sciThis->ButtonMove(pt);
1787
sciThis->errorStatus = SC_STATUS_FAILURE;
1792
// Map the keypad keys to their equivalent functions
1793
static int KeyTranslate(int keyIn) {
1795
case GDK_ISO_Left_Tab:
1809
case GDK_KP_Page_Up:
1811
case GDK_KP_Page_Down:
1850
case GDK_KP_Subtract:
1851
return SCK_SUBTRACT;
1865
gboolean ScintillaGTK::KeyThis(GdkEventKey *event) {
1867
//fprintf(stderr, "SC-key: %d %x [%s]\n",
1868
// event->keyval, event->state, (event->length > 0) ? event->string : "empty");
1869
if (gtk_im_context_filter_keypress(im_context, event)) {
1872
if (!event->keyval) {
1876
bool shift = (event->state & GDK_SHIFT_MASK) != 0;
1877
bool ctrl = (event->state & GDK_CONTROL_MASK) != 0;
1878
bool alt = (event->state & GDK_MOD1_MASK) != 0;
1879
guint key = event->keyval;
1880
if (ctrl && (key < 128))
1882
else if (!ctrl && (key >= GDK_KP_Multiply && key <= GDK_KP_9))
1884
// Hack for keys over 256 and below command keys but makes Hungarian work.
1885
// This will have to change for Unicode
1886
else if (key >= 0xFE00)
1887
key = KeyTranslate(key);
1889
bool consumed = false;
1890
bool added = KeyDown(key, shift, ctrl, alt, &consumed) != 0;
1893
//fprintf(stderr, "SK-key: %d %x %x\n",event->keyval, event->state, consumed);
1894
if (event->keyval == 0xffffff && event->length > 0) {
1896
if (pdoc->InsertCString(CurrentPosition(), event->string)) {
1897
MovePositionTo(CurrentPosition() + event->length);
1902
errorStatus = SC_STATUS_FAILURE;
1907
gboolean ScintillaGTK::KeyPress(GtkWidget *widget, GdkEventKey *event) {
1908
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
1909
return sciThis->KeyThis(event);
1912
gboolean ScintillaGTK::KeyRelease(GtkWidget *, GdkEventKey * /*event*/) {
1913
//Platform::DebugPrintf("SC-keyrel: %d %x %3s\n",event->keyval, event->state, event->string);
1917
gboolean ScintillaGTK::ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose) {
1921
PangoAttrList *attrs;
1923
gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos);
1924
PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str);
1925
pango_layout_set_attributes(layout, attrs);
1927
GdkGC *gc = gdk_gc_new(widget->window);
1928
GdkColor color[2] = { {0, 0x0000, 0x0000, 0x0000},
1929
{0, 0xffff, 0xffff, 0xffff}
1931
gdk_color_alloc(gdk_colormap_get_system(), color);
1932
gdk_color_alloc(gdk_colormap_get_system(), color + 1);
1934
gdk_gc_set_foreground(gc, color + 1);
1935
gdk_draw_rectangle(widget->window, gc, TRUE, ose->area.x, ose->area.y,
1936
ose->area.width, ose->area.height);
1938
gdk_gc_set_foreground(gc, color);
1939
gdk_gc_set_background(gc, color + 1);
1940
gdk_draw_layout(widget->window, gc, 0, 0, layout);
1944
pango_attr_list_unref(attrs);
1945
g_object_unref(layout);
1947
errorStatus = SC_STATUS_FAILURE;
1952
gboolean ScintillaGTK::ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis) {
1953
return sciThis->ExposePreeditThis(widget, ose);
1956
void ScintillaGTK::CommitThis(char *utfVal) {
1958
//~ fprintf(stderr, "Commit '%s'\n", utfVal);
1959
if (IsUnicodeMode()) {
1960
AddCharUTF(utfVal, strlen(utfVal));
1962
const char *source = CharacterSetID();
1964
Converter conv(source, "UTF-8", true);
1966
char localeVal[4] = "\0\0\0";
1968
size_t inLeft = strlen(utfVal);
1969
char *pout = localeVal;
1970
size_t outLeft = sizeof(localeVal);
1971
size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
1972
if (conversions != ((size_t)(-1))) {
1974
for (int i = 0; localeVal[i]; i++) {
1975
AddChar(localeVal[i]);
1978
fprintf(stderr, "Conversion failed '%s'\n", utfVal);
1984
errorStatus = SC_STATUS_FAILURE;
1988
void ScintillaGTK::Commit(GtkIMContext *, char *str, ScintillaGTK *sciThis) {
1989
sciThis->CommitThis(str);
1992
void ScintillaGTK::PreeditChangedThis() {
1995
PangoAttrList *attrs;
1997
gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos);
1998
if (strlen(str) > 0) {
1999
PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str);
2000
pango_layout_set_attributes(layout, attrs);
2003
pango_layout_get_pixel_size(layout, &w, &h);
2004
g_object_unref(layout);
2007
gdk_window_get_origin((PWidget(wText))->window, &x, &y);
2009
Point pt = PointMainCaret();
2015
gtk_window_move(GTK_WINDOW(PWidget(wPreedit)), x + pt.x, y + pt.y);
2016
gtk_window_resize(GTK_WINDOW(PWidget(wPreedit)), w, h);
2017
gtk_widget_show(PWidget(wPreedit));
2018
gtk_widget_queue_draw_area(PWidget(wPreeditDraw), 0, 0, w, h);
2020
gtk_widget_hide(PWidget(wPreedit));
2023
pango_attr_list_unref(attrs);
2025
errorStatus = SC_STATUS_FAILURE;
2029
void ScintillaGTK::PreeditChanged(GtkIMContext *, ScintillaGTK *sciThis) {
2030
sciThis->PreeditChangedThis();
2033
gint ScintillaGTK::StyleSetText(GtkWidget *widget, GtkStyle *, void*) {
2034
if (widget->window != NULL)
2035
gdk_window_set_back_pixmap(widget->window, NULL, FALSE);
2039
gint ScintillaGTK::RealizeText(GtkWidget *widget, void*) {
2040
if (widget->window != NULL)
2041
gdk_window_set_back_pixmap(widget->window, NULL, FALSE);
2045
void ScintillaGTK::Destroy(GObject *object) {
2047
ScintillaObject *scio = reinterpret_cast<ScintillaObject *>(object);
2048
// This avoids a double destruction
2051
ScintillaGTK *sciThis = reinterpret_cast<ScintillaGTK *>(scio->pscin);
2052
//Platform::DebugPrintf("Destroying %x %x\n", sciThis, object);
2053
sciThis->Finalise();
2058
// Its dead so nowhere to save the status
2062
static void DrawChild(GtkWidget *widget, GdkRectangle *area) {
2063
GdkRectangle areaIntersect;
2065
GTK_WIDGET_DRAWABLE(widget) &&
2066
gtk_widget_intersect(widget, area, &areaIntersect)) {
2067
gtk_widget_draw(widget, &areaIntersect);
2071
void ScintillaGTK::Draw(GtkWidget *widget, GdkRectangle *area) {
2072
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2074
//Platform::DebugPrintf("Draw %p %0d,%0d %0d,%0d\n", widget, area->x, area->y, area->width, area->height);
2075
PRectangle rcPaint(area->x, area->y, area->x + area->width, area->y + area->height);
2076
sciThis->SyncPaint(rcPaint);
2077
if (GTK_WIDGET_DRAWABLE(PWidget(sciThis->wMain))) {
2078
DrawChild(PWidget(sciThis->scrollbarh), area);
2079
DrawChild(PWidget(sciThis->scrollbarv), area);
2082
Point pt = sciThis->PointMainCaret();
2083
pt.y += sciThis->vs.lineHeight - 2;
2084
if (pt.x < 0) pt.x = 0;
2085
if (pt.y < 0) pt.y = 0;
2086
CursorMoved(widget, pt.x, pt.y, sciThis);
2088
sciThis->errorStatus = SC_STATUS_FAILURE;
2092
gint ScintillaGTK::ExposeTextThis(GtkWidget * /*widget*/, GdkEventExpose *ose) {
2094
paintState = painting;
2096
rcPaint.left = ose->area.x;
2097
rcPaint.top = ose->area.y;
2098
rcPaint.right = ose->area.x + ose->area.width;
2099
rcPaint.bottom = ose->area.y + ose->area.height;
2101
PLATFORM_ASSERT(rgnUpdate == NULL);
2102
rgnUpdate = gdk_region_copy(ose->region);
2103
PRectangle rcClient = GetClientRectangle();
2104
paintingAllText = rcPaint.Contains(rcClient);
2105
Surface *surfaceWindow = Surface::Allocate();
2106
if (surfaceWindow) {
2107
surfaceWindow->Init(PWidget(wText)->window, PWidget(wText));
2108
Paint(surfaceWindow, rcPaint);
2109
surfaceWindow->Release();
2110
delete surfaceWindow;
2112
if (paintState == paintAbandoned) {
2113
// Painting area was insufficient to cover new styling or brace highlight positions
2116
paintState = notPainting;
2119
gdk_region_destroy(rgnUpdate);
2123
errorStatus = SC_STATUS_FAILURE;
2129
gint ScintillaGTK::ExposeText(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis) {
2130
return sciThis->ExposeTextThis(widget, ose);
2133
gint ScintillaGTK::ExposeMain(GtkWidget *widget, GdkEventExpose *ose) {
2134
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2135
//Platform::DebugPrintf("Expose Main %0d,%0d %0d,%0d\n",
2136
//ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2137
return sciThis->Expose(widget, ose);
2140
gint ScintillaGTK::Expose(GtkWidget *, GdkEventExpose *ose) {
2142
//fprintf(stderr, "Expose %0d,%0d %0d,%0d\n",
2143
//ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2145
// The text is painted in ExposeText
2146
gtk_container_propagate_expose(
2147
GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarh), ose);
2148
gtk_container_propagate_expose(
2149
GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarv), ose);
2152
errorStatus = SC_STATUS_FAILURE;
2157
void ScintillaGTK::ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) {
2159
sciThis->ScrollTo(static_cast<int>(adj->value), false);
2161
sciThis->errorStatus = SC_STATUS_FAILURE;
2165
void ScintillaGTK::ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) {
2167
sciThis->HorizontalScrollTo(static_cast<int>(adj->value * 2));
2169
sciThis->errorStatus = SC_STATUS_FAILURE;
2173
void ScintillaGTK::SelectionReceived(GtkWidget *widget,
2174
GtkSelectionData *selection_data, guint) {
2175
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2176
//Platform::DebugPrintf("Selection received\n");
2177
sciThis->ReceivedSelection(selection_data);
2180
void ScintillaGTK::SelectionGet(GtkWidget *widget,
2181
GtkSelectionData *selection_data, guint info, guint) {
2182
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2184
//Platform::DebugPrintf("Selection get\n");
2185
if (selection_data->selection == GDK_SELECTION_PRIMARY) {
2186
if (sciThis->primary.s == NULL) {
2187
sciThis->CopySelectionRange(&sciThis->primary);
2189
sciThis->GetSelection(selection_data, info, &sciThis->primary);
2191
#ifndef USE_GTK_CLIPBOARD
2193
sciThis->GetSelection(selection_data, info, &sciThis->copyText);
2197
sciThis->errorStatus = SC_STATUS_FAILURE;
2201
gint ScintillaGTK::SelectionClear(GtkWidget *widget, GdkEventSelection *selection_event) {
2202
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2203
//Platform::DebugPrintf("Selection clear\n");
2204
sciThis->UnclaimSelection(selection_event);
2205
return gtk_selection_clear(widget, selection_event);
2208
void ScintillaGTK::DragBegin(GtkWidget *, GdkDragContext *) {
2209
//Platform::DebugPrintf("DragBegin\n");
2212
gboolean ScintillaGTK::DragMotionThis(GdkDragContext *context,
2213
gint x, gint y, guint dragtime) {
2216
SetDragPosition(SPositionFromLocation(npt, false, false, UserVirtualSpace()));
2217
GdkDragAction preferredAction = context->suggested_action;
2218
SelectionPosition pos = SPositionFromLocation(npt);
2219
if ((inDragDrop == ddDragging) && (PositionInSelection(pos.Position()))) {
2220
// Avoid dragging selection onto itself as that produces a move
2221
// with no real effect but which creates undo actions.
2222
preferredAction = static_cast<GdkDragAction>(0);
2223
} else if (context->actions == static_cast<GdkDragAction>
2224
(GDK_ACTION_COPY | GDK_ACTION_MOVE)) {
2225
preferredAction = GDK_ACTION_MOVE;
2227
gdk_drag_status(context, preferredAction, dragtime);
2229
errorStatus = SC_STATUS_FAILURE;
2234
gboolean ScintillaGTK::DragMotion(GtkWidget *widget, GdkDragContext *context,
2235
gint x, gint y, guint dragtime) {
2236
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2237
return sciThis->DragMotionThis(context, x, y, dragtime);
2240
void ScintillaGTK::DragLeave(GtkWidget *widget, GdkDragContext * /*context*/, guint) {
2241
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2243
sciThis->SetDragPosition(SelectionPosition(invalidPosition));
2244
//Platform::DebugPrintf("DragLeave %x\n", sciThis);
2246
sciThis->errorStatus = SC_STATUS_FAILURE;
2250
void ScintillaGTK::DragEnd(GtkWidget *widget, GdkDragContext * /*context*/) {
2251
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2253
// If drag did not result in drop here or elsewhere
2254
if (!sciThis->dragWasDropped)
2255
sciThis->SetEmptySelection(sciThis->posDrag);
2256
sciThis->SetDragPosition(SelectionPosition(invalidPosition));
2257
//Platform::DebugPrintf("DragEnd %x %d\n", sciThis, sciThis->dragWasDropped);
2258
sciThis->inDragDrop = ddNone;
2260
sciThis->errorStatus = SC_STATUS_FAILURE;
2264
gboolean ScintillaGTK::Drop(GtkWidget *widget, GdkDragContext * /*context*/,
2265
gint, gint, guint) {
2266
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2268
//Platform::DebugPrintf("Drop %x\n", sciThis);
2269
sciThis->SetDragPosition(SelectionPosition(invalidPosition));
2271
sciThis->errorStatus = SC_STATUS_FAILURE;
2276
void ScintillaGTK::DragDataReceived(GtkWidget *widget, GdkDragContext * /*context*/,
2277
gint, gint, GtkSelectionData *selection_data, guint /*info*/, guint) {
2278
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2280
sciThis->ReceivedDrop(selection_data);
2281
sciThis->SetDragPosition(SelectionPosition(invalidPosition));
2283
sciThis->errorStatus = SC_STATUS_FAILURE;
2287
void ScintillaGTK::DragDataGet(GtkWidget *widget, GdkDragContext *context,
2288
GtkSelectionData *selection_data, guint info, guint) {
2289
ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2291
sciThis->dragWasDropped = true;
2292
if (!sciThis->sel.Empty()) {
2293
sciThis->GetSelection(selection_data, info, &sciThis->drag);
2295
if (context->action == GDK_ACTION_MOVE) {
2296
for (size_t r=0; r<sciThis->sel.Count(); r++) {
2297
if (sciThis->posDrop >= sciThis->sel.Range(r).Start()) {
2298
if (sciThis->posDrop > sciThis->sel.Range(r).End()) {
2299
sciThis->posDrop.Add(-sciThis->sel.Range(r).Length());
2301
sciThis->posDrop.Add(-SelectionRange(sciThis->posDrop, sciThis->sel.Range(r).Start()).Length());
2305
sciThis->ClearSelection();
2307
sciThis->SetDragPosition(SelectionPosition(invalidPosition));
2309
sciThis->errorStatus = SC_STATUS_FAILURE;
2313
int ScintillaGTK::TimeOut(ScintillaGTK *sciThis) {
2318
gboolean ScintillaGTK::IdleCallback(ScintillaGTK *sciThis) {
2319
// Idler will be automatically stopped, if there is nothing
2320
// to do while idle.
2321
bool ret = sciThis->Idle();
2323
// FIXME: This will remove the idler from GTK, we don't want to
2324
// remove it as it is removed automatically when this function
2325
// returns false (although, it should be harmless).
2326
sciThis->SetIdle(false);
2331
gboolean ScintillaGTK::StyleIdle(ScintillaGTK *sciThis) {
2332
sciThis->IdleStyling();
2333
// Idler will be automatically stopped
2337
void ScintillaGTK::QueueStyling(int upTo) {
2338
Editor::QueueStyling(upTo);
2339
if (!styleNeeded.active) {
2340
// Only allow one style needed to be queued
2341
styleNeeded.active = true;
2342
g_idle_add_full(G_PRIORITY_HIGH_IDLE,
2343
reinterpret_cast<GSourceFunc>(StyleIdle), this, NULL);
2347
void ScintillaGTK::PopUpCB(ScintillaGTK *sciThis, guint action, GtkWidget *) {
2349
sciThis->Command(action);
2353
gint ScintillaGTK::PressCT(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis) {
2355
if (event->window != widget->window)
2357
if (event->type != GDK_BUTTON_PRESS)
2360
pt.x = int(event->x);
2361
pt.y = int(event->y);
2362
sciThis->ct.MouseClick(pt);
2363
sciThis->CallTipClick();
2369
gint ScintillaGTK::ExposeCT(GtkWidget *widget, GdkEventExpose * /*ose*/, CallTip *ctip) {
2371
Surface *surfaceWindow = Surface::Allocate();
2372
if (surfaceWindow) {
2373
surfaceWindow->Init(widget->window, widget);
2374
surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == ctip->codePage);
2375
surfaceWindow->SetDBCSMode(ctip->codePage);
2376
ctip->PaintCT(surfaceWindow);
2377
surfaceWindow->Release();
2378
delete surfaceWindow;
2381
// No pointer back to Scintilla to save status
2386
sptr_t ScintillaGTK::DirectFunction(
2387
ScintillaGTK *sciThis, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
2388
return sciThis->WndProc(iMessage, wParam, lParam);
2391
sptr_t scintilla_send_message(ScintillaObject *sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
2392
ScintillaGTK *psci = reinterpret_cast<ScintillaGTK *>(sci->pscin);
2393
return psci->WndProc(iMessage, wParam, lParam);
2396
static void scintilla_class_init(ScintillaClass *klass);
2397
static void scintilla_init(ScintillaObject *sci);
2399
extern void Platform_Initialise();
2400
extern void Platform_Finalise();
2402
GType scintilla_get_type() {
2403
static GType scintilla_type = 0;
2406
if (!scintilla_type) {
2407
scintilla_type = g_type_from_name("Scintilla");
2408
if (!scintilla_type) {
2409
static GTypeInfo scintilla_info = {
2410
(guint16) sizeof (ScintillaClass),
2411
NULL, //(GBaseInitFunc)
2412
NULL, //(GBaseFinalizeFunc)
2413
(GClassInitFunc) scintilla_class_init,
2414
NULL, //(GClassFinalizeFunc)
2415
NULL, //gconstpointer data
2416
(guint16) sizeof (ScintillaObject),
2418
(GInstanceInitFunc) scintilla_init,
2419
NULL //(GTypeValueTable*)
2422
scintilla_type = g_type_register_static(
2423
GTK_TYPE_CONTAINER, "Scintilla", &scintilla_info, (GTypeFlags) 0);
2429
return scintilla_type;
2432
void ScintillaGTK::ClassInit(OBJECT_CLASS* object_class, GtkWidgetClass *widget_class, GtkContainerClass *container_class) {
2433
Platform_Initialise();
2434
atomClipboard = gdk_atom_intern("CLIPBOARD", FALSE);
2435
atomUTF8 = gdk_atom_intern("UTF8_STRING", FALSE);
2436
atomString = GDK_SELECTION_TYPE_STRING;
2437
atomUriList = gdk_atom_intern("text/uri-list", FALSE);
2438
atomDROPFILES_DND = gdk_atom_intern("DROPFILES_DND", FALSE);
2440
// Define default signal handlers for the class: Could move more
2441
// of the signal handlers here (those that currently attached to wDraw
2442
// in Initialise() may require coordinate translation?)
2444
object_class->finalize = Destroy;
2445
widget_class->size_request = SizeRequest;
2446
widget_class->size_allocate = SizeAllocate;
2447
widget_class->expose_event = ExposeMain;
2448
widget_class->motion_notify_event = Motion;
2449
widget_class->button_press_event = Press;
2450
widget_class->button_release_event = MouseRelease;
2451
widget_class->scroll_event = ScrollEvent;
2452
widget_class->key_press_event = KeyPress;
2453
widget_class->key_release_event = KeyRelease;
2454
widget_class->focus_in_event = FocusIn;
2455
widget_class->focus_out_event = FocusOut;
2456
widget_class->selection_received = SelectionReceived;
2457
widget_class->selection_get = SelectionGet;
2458
widget_class->selection_clear_event = SelectionClear;
2460
widget_class->drag_data_received = DragDataReceived;
2461
widget_class->drag_motion = DragMotion;
2462
widget_class->drag_leave = DragLeave;
2463
widget_class->drag_end = DragEnd;
2464
widget_class->drag_drop = Drop;
2465
widget_class->drag_data_get = DragDataGet;
2467
widget_class->realize = Realize;
2468
widget_class->unrealize = UnRealize;
2469
widget_class->map = Map;
2470
widget_class->unmap = UnMap;
2472
container_class->forall = MainForAll;
2475
#define SIG_MARSHAL scintilla_marshal_NONE__INT_POINTER
2476
#define MARSHAL_ARGUMENTS G_TYPE_INT, G_TYPE_POINTER
2478
static void scintilla_class_init(ScintillaClass *klass) {
2480
OBJECT_CLASS *object_class = (OBJECT_CLASS*) klass;
2481
GtkWidgetClass *widget_class = (GtkWidgetClass*) klass;
2482
GtkContainerClass *container_class = (GtkContainerClass*) klass;
2484
GSignalFlags sigflags = GSignalFlags(G_SIGNAL_ACTION | G_SIGNAL_RUN_LAST);
2485
scintilla_signals[COMMAND_SIGNAL] = g_signal_new(
2487
G_TYPE_FROM_CLASS(object_class),
2489
G_STRUCT_OFFSET(ScintillaClass, command),
2490
NULL, //(GSignalAccumulator)
2494
2, MARSHAL_ARGUMENTS);
2496
scintilla_signals[NOTIFY_SIGNAL] = g_signal_new(
2498
G_TYPE_FROM_CLASS(object_class),
2500
G_STRUCT_OFFSET(ScintillaClass, notify),
2505
2, MARSHAL_ARGUMENTS);
2507
klass->command = NULL;
2508
klass->notify = NULL;
2510
ScintillaGTK::ClassInit(object_class, widget_class, container_class);
2515
static void scintilla_init(ScintillaObject *sci) {
2517
GTK_WIDGET_SET_FLAGS(sci, GTK_CAN_FOCUS);
2518
sci->pscin = new ScintillaGTK(sci);
2523
GtkWidget* scintilla_new() {
2524
return GTK_WIDGET(g_object_new(scintilla_get_type(), NULL));
2527
void scintilla_set_id(ScintillaObject *sci, uptr_t id) {
2528
ScintillaGTK *psci = reinterpret_cast<ScintillaGTK *>(sci->pscin);
2532
void scintilla_release_resources(void) {
2534
Platform_Finalise();