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 <stdlib.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <ctype.h>
10 #include <time.h>
11 
12 #include <gtk/gtk.h>
13 #include <gdk/gdkkeysyms.h>
14 
15 #include "Platform.h"
16 
17 #if PLAT_GTK_WIN32
18 #include "Windows.h"
19 #endif
20 
21 #include "Scintilla.h"
22 #include "ScintillaWidget.h"
23 #ifdef SCI_LEXER
24 #include "SciLexer.h"
25 #include "PropSet.h"
26 #include "Accessor.h"
27 #include "KeyWords.h"
28 #endif
29 #include "ContractionState.h"
30 #include "SVector.h"
31 #include "CellBuffer.h"
32 #include "CallTip.h"
33 #include "KeyMap.h"
34 #include "Indicator.h"
35 #include "XPM.h"
36 #include "LineMarker.h"
37 #include "Style.h"
38 #include "AutoComplete.h"
39 #include "ViewStyle.h"
40 #include "Document.h"
41 #include "Editor.h"
42 #include "SString.h"
43 #include "ScintillaBase.h"
44 #include "UniConversion.h"
45 
46 #include "gtk/gtksignal.h"
47 #include "gtk/gtkmarshal.h"
48 #if GTK_MAJOR_VERSION >= 2
49 #include "scintilla-marshal.h"
50 #endif
51 
52 #ifdef SCI_LEXER
53 #include <glib.h>
54 #include <gmodule.h>
55 #include "ExternalLexer.h"
56 #endif
57 
58 #define INTERNATIONAL_INPUT
59 
60 #if !PLAT_GTK_WIN32 || GTK_MAJOR_VERSION >= 2
61 #define USE_CONVERTER
62 #endif
63 
64 #ifdef USE_CONVERTER
65 #include "Converter.h"
66 #endif
67 
68 #ifdef _MSC_VER
69 // Constant conditional expressions are because of GTK+ headers
70 #pragma warning(disable: 4127)
71 // Ignore unreferenced local functions in GTK+ headers
72 #pragma warning(disable: 4505)
73 #endif
74 
75 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 2
76 #define USE_GTK_CLIPBOARD
77 #endif
78 
79 extern char *UTF8FromLatin1(const char *s, int &len);
80 
81 class ScintillaGTK : public ScintillaBase {
82 	_ScintillaObject *sci;
83 	Window wText;
84 	Window scrollbarv;
85 	Window scrollbarh;
86 	GtkObject *adjustmentv;
87 	GtkObject *adjustmenth;
88 	int scrollBarWidth;
89 	int scrollBarHeight;
90 
91 	// Because clipboard access is asynchronous, copyText is created by Copy
92 #ifndef USE_GTK_CLIPBOARD
93 	SelectionText copyText;
94 #endif
95 
96 	SelectionText primary;
97 
98 	GdkEventButton evbtn;
99 	bool capturedMouse;
100 	bool dragWasDropped;
101 	int lastKey;
102 
103 	GtkWidgetClass *parentClass;
104 
105 	static GdkAtom atomClipboard;
106 	static GdkAtom atomUTF8;
107 	static GdkAtom atomString;
108 	GdkAtom atomSought;
109 
110 #if PLAT_GTK_WIN32
111 	CLIPFORMAT cfColumnSelect;
112 #endif
113 
114 #ifdef INTERNATIONAL_INPUT
115 #if GTK_MAJOR_VERSION < 2
116 	// Input context used for supporting internationalized key entry
117 	GdkIC *ic;
118 	GdkICAttr *ic_attr;
119 #else
120 	Window wPreedit;
121 	Window wPreeditDraw;
122 	GtkIMContext *im_context;
123 #endif
124 #endif
125 
126 	// Wheel mouse support
127 	unsigned int linesPerScroll;
128 	GTimeVal lastWheelMouseTime;
129 	gint lastWheelMouseDirection;
130 	gint wheelMouseIntensity;
131 
132 	// Private so ScintillaGTK objects can not be copied
ScintillaGTK(const ScintillaGTK &)133 	ScintillaGTK(const ScintillaGTK &) : ScintillaBase() {}
operator =(const ScintillaGTK &)134 	ScintillaGTK &operator=(const ScintillaGTK &) { return * this; }
135 
136 public:
137 	ScintillaGTK(_ScintillaObject *sci_);
138 	virtual ~ScintillaGTK();
139 	static void ClassInit(GtkObjectClass* object_class, GtkWidgetClass *widget_class, GtkContainerClass *container_class);
140 
141 private:
142 	virtual void Initialise();
143 	virtual void Finalise();
144 	virtual void DisplayCursor(Window::Cursor c);
145 	virtual void StartDrag();
146 	int TargetAsUTF8(char *text);
147 	int EncodedFromUTF8(char *utf8, char *encoded);
148 public: 	// Public for scintilla_send_message
149 	virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
150 private:
151 	virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
152 	virtual void SetTicking(bool on);
153 	virtual bool SetIdle(bool on);
154 	virtual void SetMouseCapture(bool on);
155 	virtual bool HaveMouseCapture();
156 	void FullPaint();
157 	virtual PRectangle GetClientRectangle();
158 	void SyncPaint(PRectangle rc);
159 	virtual void ScrollText(int linesToMove);
160 	virtual void SetVerticalScrollPos();
161 	virtual void SetHorizontalScrollPos();
162 	virtual bool ModifyScrollBars(int nMax, int nPage);
163 	void ReconfigureScrollBars();
164 	virtual void NotifyChange();
165 	virtual void NotifyFocus(bool focus);
166 	virtual void NotifyParent(SCNotification scn);
167 	void NotifyKey(int key, int modifiers);
168 	void NotifyURIDropped(const char *list);
169 	bool UseInputMethod() const;
170 	const char *CharacterSetID() const;
171 	virtual int KeyDefault(int key, int modifiers);
172 	virtual void CopyToClipboard(const SelectionText &selectedText);
173 	virtual void Copy();
174 	virtual void Paste();
175 	virtual void CreateCallTipWindow(PRectangle rc);
176 	virtual void AddToPopUp(const char *label, int cmd = 0, bool enabled = true);
177 	bool OwnPrimarySelection();
178 	virtual void ClaimSelection();
179 	void GetGtkSelectionText(GtkSelectionData *selectionData, SelectionText &selText);
180 	void ReceivedSelection(GtkSelectionData *selection_data);
181 	void ReceivedDrop(GtkSelectionData *selection_data);
182 	static void GetSelection(GtkSelectionData *selection_data, guint info, SelectionText *selected);
183 #ifdef USE_GTK_CLIPBOARD
184 	static void ClipboardGetSelection(GtkClipboard* clip, GtkSelectionData *selection_data, guint info, void *data);
185 	static void ClipboardClearSelection(GtkClipboard* clip, void *data);
186 #endif
187 
188 	void UnclaimSelection(GdkEventSelection *selection_event);
189 	void Resize(int width, int height);
190 
191 	// Callback functions
192 	void RealizeThis(GtkWidget *widget);
193 	static void Realize(GtkWidget *widget);
194 	void UnRealizeThis(GtkWidget *widget);
195 	static void UnRealize(GtkWidget *widget);
196 	void MapThis();
197 	static void Map(GtkWidget *widget);
198 	void UnMapThis();
199 	static void UnMap(GtkWidget *widget);
200 	static gint CursorMoved(GtkWidget *widget, int xoffset, int yoffset, ScintillaGTK *sciThis);
201 	static gint FocusIn(GtkWidget *widget, GdkEventFocus *event);
202 	static gint FocusOut(GtkWidget *widget, GdkEventFocus *event);
203 	static void SizeRequest(GtkWidget *widget, GtkRequisition *requisition);
204 	static void SizeAllocate(GtkWidget *widget, GtkAllocation *allocation);
205 	gint Expose(GtkWidget *widget, GdkEventExpose *ose);
206 	static gint ExposeMain(GtkWidget *widget, GdkEventExpose *ose);
207 	static void Draw(GtkWidget *widget, GdkRectangle *area);
208 	void ForAll(GtkCallback callback, gpointer callback_data);
209 	static void MainForAll(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data);
210 
211 	static void ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis);
212 	static void ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis);
213 	gint PressThis(GdkEventButton *event);
214 	static gint Press(GtkWidget *widget, GdkEventButton *event);
215 	static gint MouseRelease(GtkWidget *widget, GdkEventButton *event);
216 #if PLAT_GTK_WIN32 || (GTK_MAJOR_VERSION >= 2)
217 	static gint ScrollEvent(GtkWidget *widget, GdkEventScroll *event);
218 #endif
219 	static gint Motion(GtkWidget *widget, GdkEventMotion *event);
220 	gint KeyThis(GdkEventKey *event);
221 	static gint KeyPress(GtkWidget *widget, GdkEventKey *event);
222 	static gint KeyRelease(GtkWidget *widget, GdkEventKey *event);
223 #if GTK_MAJOR_VERSION >= 2
224 	static gint ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis);
225 	gint ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose);
226 	static void Commit(GtkIMContext *context, char *str, ScintillaGTK *sciThis);
227 	void CommitThis(char *str);
228 	static void PreeditChanged(GtkIMContext *context, ScintillaGTK *sciThis);
229 	void PreeditChangedThis();
230 #endif
231 	static gint StyleSetText(GtkWidget *widget, GtkStyle *previous, void*);
232 	static gint RealizeText(GtkWidget *widget, void*);
233 	static void Destroy(GtkObject *object);
234 	static void SelectionReceived(GtkWidget *widget, GtkSelectionData *selection_data,
235 	                              guint time);
236 	static void SelectionGet(GtkWidget *widget, GtkSelectionData *selection_data,
237 	                         guint info, guint time);
238 	static gint SelectionClear(GtkWidget *widget, GdkEventSelection *selection_event);
239 #if GTK_MAJOR_VERSION < 2
240 	static gint SelectionNotify(GtkWidget *widget, GdkEventSelection *selection_event);
241 #endif
242 	static void DragBegin(GtkWidget *widget, GdkDragContext *context);
243 	static gboolean DragMotion(GtkWidget *widget, GdkDragContext *context,
244 	                           gint x, gint y, guint time);
245 	static void DragLeave(GtkWidget *widget, GdkDragContext *context,
246 	                      guint time);
247 	static void DragEnd(GtkWidget *widget, GdkDragContext *context);
248 	static gboolean Drop(GtkWidget *widget, GdkDragContext *context,
249 	                     gint x, gint y, guint time);
250 	static void DragDataReceived(GtkWidget *widget, GdkDragContext *context,
251 	                             gint x, gint y, GtkSelectionData *selection_data, guint info, guint time);
252 	static void DragDataGet(GtkWidget *widget, GdkDragContext *context,
253 	                        GtkSelectionData *selection_data, guint info, guint time);
254 	static gint TimeOut(ScintillaGTK *sciThis);
255 	static gint IdleCallback(ScintillaGTK *sciThis);
256 	static void PopUpCB(ScintillaGTK *sciThis, guint action, GtkWidget *widget);
257 
258 	gint ExposeTextThis(GtkWidget *widget, GdkEventExpose *ose);
259 	static gint ExposeText(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis);
260 
261 	static gint ExposeCT(GtkWidget *widget, GdkEventExpose *ose, CallTip *ct);
262 	static gint PressCT(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis);
263 
264 	static sptr_t DirectFunction(ScintillaGTK *sciThis,
265 	                             unsigned int iMessage, uptr_t wParam, sptr_t lParam);
266 };
267 
268 enum {
269     COMMAND_SIGNAL,
270     NOTIFY_SIGNAL,
271     LAST_SIGNAL
272 };
273 
274 static gint scintilla_signals[LAST_SIGNAL] = { 0 };
275 static GtkWidgetClass* parent_class = NULL;
276 
277 enum {
278     TARGET_STRING,
279     TARGET_TEXT,
280     TARGET_COMPOUND_TEXT,
281     TARGET_UTF8_STRING
282 };
283 
284 GdkAtom ScintillaGTK::atomClipboard = 0;
285 GdkAtom ScintillaGTK::atomUTF8 = 0;
286 GdkAtom ScintillaGTK::atomString = 0;
287 
288 static const GtkTargetEntry clipboardTargets[] = {
289 	{ "UTF8_STRING", 0, TARGET_UTF8_STRING },
290 	{ "STRING", 0, TARGET_STRING },
291 //	    { "TEXT", 0, TARGET_TEXT },
292 //	    { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
293 	{ "text/uri-list", 0, 0 },
294 };
295 static const gint nClipboardTargets = sizeof(clipboardTargets) / sizeof(clipboardTargets[0]);
296 
PWidget(Window & w)297 static GtkWidget *PWidget(Window &w) {
298 	return reinterpret_cast<GtkWidget *>(w.GetID());
299 }
300 
ScintillaFromWidget(GtkWidget * widget)301 static ScintillaGTK *ScintillaFromWidget(GtkWidget *widget) {
302 	ScintillaObject *scio = reinterpret_cast<ScintillaObject *>(widget);
303 	return reinterpret_cast<ScintillaGTK *>(scio->pscin);
304 }
305 
ScintillaGTK(_ScintillaObject * sci_)306 ScintillaGTK::ScintillaGTK(_ScintillaObject *sci_) :
307 		adjustmentv(0), adjustmenth(0),
308 		scrollBarWidth(30), scrollBarHeight(30),
309 		capturedMouse(false), dragWasDropped(false),
310 		lastKey(0), parentClass(0),
311 #ifdef INTERNATIONAL_INPUT
312 #if GTK_MAJOR_VERSION < 2
313 		ic(NULL),
314 		ic_attr(NULL),
315 #else
316 		im_context(NULL),
317 #endif
318 #endif
319 		lastWheelMouseDirection(0),
320 		wheelMouseIntensity(0) {
321 	sci = sci_;
322 	wMain = GTK_WIDGET(sci);
323 
324 #if PLAT_GTK_WIN32
325  	// There does not seem to be a real standard for indicating that the clipboard
326 	// contains a rectangular selection, so copy Developer Studio.
327 	cfColumnSelect = static_cast<CLIPFORMAT>(
328 		::RegisterClipboardFormat("MSDEVColumnSelect"));
329 
330   	// Get intellimouse parameters when running on win32; otherwise use
331 	// reasonable default
332 #ifndef SPI_GETWHEELSCROLLLINES
333 #define SPI_GETWHEELSCROLLLINES   104
334 #endif
335 	::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &linesPerScroll, 0);
336 #else
337 	linesPerScroll = 4;
338 #endif
339 	lastWheelMouseTime.tv_sec = 0;
340 	lastWheelMouseTime.tv_usec = 0;
341 
342 	Initialise();
343 }
344 
~ScintillaGTK()345 ScintillaGTK::~ScintillaGTK() {
346 }
347 
RealizeThis(GtkWidget * widget)348 void ScintillaGTK::RealizeThis(GtkWidget *widget) {
349 	//Platform::DebugPrintf("ScintillaGTK::realize this\n");
350 	GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
351 	GdkWindowAttr attrs;
352 	attrs.window_type = GDK_WINDOW_CHILD;
353 	attrs.x = widget->allocation.x;
354 	attrs.y = widget->allocation.y;
355 	attrs.width = widget->allocation.width;
356 	attrs.height = widget->allocation.height;
357 	attrs.wclass = GDK_INPUT_OUTPUT;
358 	attrs.visual = gtk_widget_get_visual(widget);
359 	attrs.colormap = gtk_widget_get_colormap(widget);
360 	attrs.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK;
361 	GdkCursor *cursor = gdk_cursor_new(GDK_XTERM);
362 	attrs.cursor = cursor;
363 	widget->window = gdk_window_new(gtk_widget_get_parent_window(widget), &attrs,
364 	                                GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_CURSOR);
365 	gdk_window_set_user_data(widget->window, widget);
366 	gdk_window_set_background(widget->window, &widget->style->bg[GTK_STATE_NORMAL]);
367 	gdk_window_show(widget->window);
368 	gdk_cursor_destroy(cursor);
369 	widget->style = gtk_style_attach(widget->style, widget->window);
370 #ifdef INTERNATIONAL_INPUT
371 #if GTK_MAJOR_VERSION < 2
372 	if (gdk_im_ready() && (ic_attr = gdk_ic_attr_new()) != NULL) {
373 		gint width, height;
374 		GdkColormap *colormap;
375 		GdkEventMask mask;
376 		GdkICAttr *attr = ic_attr;
377 		GdkICAttributesType attrmask = GDK_IC_ALL_REQ;
378 		GdkIMStyle style;
379 		GdkIMStyle supported_style = (GdkIMStyle) (GDK_IM_PREEDIT_NONE |
380 		                             GDK_IM_PREEDIT_NOTHING |
381 		                             GDK_IM_PREEDIT_POSITION |
382 		                             GDK_IM_STATUS_NONE |
383 		                             GDK_IM_STATUS_NOTHING);
384 
385 		if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
386 			supported_style = (GdkIMStyle) ((int) supported_style & ~GDK_IM_PREEDIT_POSITION);
387 
388 		attr->style = style = gdk_im_decide_style(supported_style);
389 		attr->client_window = widget->window;
390 
391 		if ((colormap = gtk_widget_get_colormap (widget)) != gtk_widget_get_default_colormap ()) {
392 			attrmask = (GdkICAttributesType) ((int) attrmask | GDK_IC_PREEDIT_COLORMAP);
393 			attr->preedit_colormap = colormap;
394 		}
395 
396 		switch (style & GDK_IM_PREEDIT_MASK) {
397 		case GDK_IM_PREEDIT_POSITION:
398 			if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)	{
399 				g_warning("over-the-spot style requires fontset");
400 				break;
401 			}
402 
403 			attrmask = (GdkICAttributesType) ((int) attrmask | GDK_IC_PREEDIT_POSITION_REQ);
404 			gdk_window_get_size(widget->window, &width, &height);
405 			attr->spot_location.x = 0;
406 			attr->spot_location.y = height;
407 			attr->preedit_area.x = 0;
408 			attr->preedit_area.y = 0;
409 			attr->preedit_area.width = width;
410 			attr->preedit_area.height = height;
411 			attr->preedit_fontset = widget->style->font;
412 
413 			break;
414 		}
415 		ic = gdk_ic_new(attr, attrmask);
416 
417 		if (ic == NULL) {
418 			g_warning("Can't create input context.");
419 		} else {
420 			mask = gdk_window_get_events(widget->window);
421 			mask = (GdkEventMask) ((int) mask | gdk_ic_get_events(ic));
422 			gdk_window_set_events(widget->window, mask);
423 
424 			if (GTK_WIDGET_HAS_FOCUS(widget))
425 				gdk_im_begin(ic, widget->window);
426 		}
427 	}
428 #else
429 	wPreedit = gtk_window_new(GTK_WINDOW_POPUP);
430 	wPreeditDraw = gtk_drawing_area_new();
431 	gtk_signal_connect(GTK_OBJECT(PWidget(wPreeditDraw)), "expose_event",
432 			   GtkSignalFunc(ExposePreedit), this);
433 	gtk_container_add(GTK_CONTAINER(PWidget(wPreedit)), PWidget(wPreeditDraw));
434 	gtk_widget_realize(PWidget(wPreedit));
435 	gtk_widget_realize(PWidget(wPreeditDraw));
436 	gtk_widget_show(PWidget(wPreeditDraw));
437 
438 	im_context = gtk_im_multicontext_new();
439 	g_signal_connect(im_context, "commit",
440 			 G_CALLBACK(Commit), this);
441 	g_signal_connect(im_context, "preedit_changed",
442 			 G_CALLBACK(PreeditChanged), this);
443 	gtk_im_context_set_client_window(im_context, widget->window);
444 #endif
445 #endif
446 	gtk_signal_connect_after(GTK_OBJECT(PWidget(wText)), "style_set",
447 				 GtkSignalFunc(ScintillaGTK::StyleSetText), NULL);
448 	gtk_signal_connect_after(GTK_OBJECT(PWidget(wText)), "realize",
449 				 GtkSignalFunc(ScintillaGTK::RealizeText), NULL);
450 	gtk_widget_realize(PWidget(wText));
451 	gtk_widget_realize(PWidget(scrollbarv));
452 	gtk_widget_realize(PWidget(scrollbarh));
453 }
454 
Realize(GtkWidget * widget)455 void ScintillaGTK::Realize(GtkWidget *widget) {
456 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
457 	sciThis->RealizeThis(widget);
458 }
459 
UnRealizeThis(GtkWidget * widget)460 void ScintillaGTK::UnRealizeThis(GtkWidget *widget) {
461 	if (GTK_WIDGET_MAPPED(widget)) {
462 		gtk_widget_unmap(widget);
463 	}
464 	GTK_WIDGET_UNSET_FLAGS(widget, GTK_REALIZED);
465 	gtk_widget_unrealize(PWidget(wText));
466 	gtk_widget_unrealize(PWidget(scrollbarv));
467 	gtk_widget_unrealize(PWidget(scrollbarh));
468 #ifdef INTERNATIONAL_INPUT
469 #if GTK_MAJOR_VERSION < 2
470 	if (ic) {
471 		gdk_ic_destroy(ic);
472 		ic = NULL;
473 	}
474 	if (ic_attr) {
475 		gdk_ic_attr_destroy(ic_attr);
476 		ic_attr = NULL;
477 	}
478 #else
479 	gtk_widget_unrealize(PWidget(wPreedit));
480 	gtk_widget_unrealize(PWidget(wPreeditDraw));
481 	g_object_unref(im_context);
482 	im_context = NULL;
483 #endif
484 #endif
485 	if (GTK_WIDGET_CLASS(parentClass)->unrealize)
486 		GTK_WIDGET_CLASS(parentClass)->unrealize(widget);
487 
488 	Finalise();
489 }
490 
UnRealize(GtkWidget * widget)491 void ScintillaGTK::UnRealize(GtkWidget *widget) {
492 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
493 	sciThis->UnRealizeThis(widget);
494 }
495 
MapWidget(GtkWidget * widget)496 static void MapWidget(GtkWidget *widget) {
497 	if (widget &&
498 	        GTK_WIDGET_VISIBLE(widget) &&
499 	        !GTK_WIDGET_MAPPED(widget)) {
500 		gtk_widget_map(widget);
501 	}
502 }
503 
MapThis()504 void ScintillaGTK::MapThis() {
505 	//Platform::DebugPrintf("ScintillaGTK::map this\n");
506 	GTK_WIDGET_SET_FLAGS(PWidget(wMain), GTK_MAPPED);
507 	MapWidget(PWidget(wText));
508 	MapWidget(PWidget(scrollbarh));
509 	MapWidget(PWidget(scrollbarv));
510 	wMain.SetCursor(Window::cursorArrow);
511 	scrollbarv.SetCursor(Window::cursorArrow);
512 	scrollbarh.SetCursor(Window::cursorArrow);
513 	ChangeSize();
514 	gdk_window_show(PWidget(wMain)->window);
515 }
516 
Map(GtkWidget * widget)517 void ScintillaGTK::Map(GtkWidget *widget) {
518 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
519 	sciThis->MapThis();
520 }
521 
UnMapThis()522 void ScintillaGTK::UnMapThis() {
523 	//Platform::DebugPrintf("ScintillaGTK::unmap this\n");
524 	GTK_WIDGET_UNSET_FLAGS(PWidget(wMain), GTK_MAPPED);
525 	gdk_window_hide(PWidget(wMain)->window);
526 	gtk_widget_unmap(PWidget(wText));
527 	gtk_widget_unmap(PWidget(scrollbarh));
528 	gtk_widget_unmap(PWidget(scrollbarv));
529 }
530 
UnMap(GtkWidget * widget)531 void ScintillaGTK::UnMap(GtkWidget *widget) {
532 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
533 	sciThis->UnMapThis();
534 }
535 
ForAll(GtkCallback callback,gpointer callback_data)536 void ScintillaGTK::ForAll(GtkCallback callback, gpointer callback_data) {
537 	(*callback) (PWidget(wText), callback_data);
538 	(*callback) (PWidget(scrollbarv), callback_data);
539 	(*callback) (PWidget(scrollbarh), callback_data);
540 }
541 
MainForAll(GtkContainer * container,gboolean include_internals,GtkCallback callback,gpointer callback_data)542 void ScintillaGTK::MainForAll(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data) {
543 	ScintillaGTK *sciThis = ScintillaFromWidget((GtkWidget *)container);
544 
545 	if (callback != NULL && include_internals) {
546 		sciThis->ForAll(callback, callback_data);
547 	}
548 }
549 
550 #ifdef INTERNATIONAL_INPUT
551 #if GTK_MAJOR_VERSION < 2
CursorMoved(GtkWidget * widget,int xoffset,int yoffset,ScintillaGTK * sciThis)552 gint ScintillaGTK::CursorMoved(GtkWidget *widget, int xoffset, int yoffset, ScintillaGTK *sciThis) {
553 	if (GTK_WIDGET_HAS_FOCUS(widget) && gdk_im_ready() && sciThis->ic &&
554 	        (gdk_ic_get_style(sciThis->ic) & GDK_IM_PREEDIT_POSITION)) {
555 		sciThis->ic_attr->spot_location.x = xoffset;
556 		sciThis->ic_attr->spot_location.y = yoffset;
557 		gdk_ic_set_attr(sciThis->ic, sciThis->ic_attr, GDK_IC_SPOT_LOCATION);
558 	}
559 	return FALSE;
560 }
561 #else
CursorMoved(GtkWidget *,int xoffset,int yoffset,ScintillaGTK * sciThis)562 gint ScintillaGTK::CursorMoved(GtkWidget *, int xoffset, int yoffset, ScintillaGTK *sciThis) {
563 	GdkRectangle area;
564 	area.x = xoffset;
565 	area.y = yoffset;
566 	area.width = 1;
567 	area.height = 1;
568 	gtk_im_context_set_cursor_location(sciThis->im_context, &area);
569 	return FALSE;
570 }
571 #endif
572 #else
CursorMoved(GtkWidget *,int,int,ScintillaGTK *)573 gint ScintillaGTK::CursorMoved(GtkWidget *, int, int, ScintillaGTK *) {
574 	return FALSE;
575 }
576 #endif
577 
FocusIn(GtkWidget * widget,GdkEventFocus *)578 gint ScintillaGTK::FocusIn(GtkWidget *widget, GdkEventFocus * /*event*/) {
579 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
580 	//Platform::DebugPrintf("ScintillaGTK::focus in %x\n", sciThis);
581 	GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
582 	sciThis->SetFocusState(true);
583 
584 #ifdef INTERNATIONAL_INPUT
585 #if GTK_MAJOR_VERSION < 2
586 	if (sciThis->ic)
587 		gdk_im_begin(sciThis->ic, widget->window);
588 #else
589 	if (sciThis->im_context != NULL) {
590 		gchar *str = NULL;
591 		gint cursor_pos;
592 
593 		gtk_im_context_get_preedit_string(sciThis->im_context, &str, NULL, &cursor_pos);
594 		if (PWidget(sciThis->wPreedit) != NULL) {
595 			if (strlen(str) > 0) {
596 				gtk_widget_show(PWidget(sciThis->wPreedit));
597 			} else {
598 				gtk_widget_hide(PWidget(sciThis->wPreedit));
599 			}
600 		}
601 		g_free(str);
602 		gtk_im_context_focus_in(sciThis->im_context);
603 	}
604 #endif
605 #endif
606 
607 	return FALSE;
608 }
609 
FocusOut(GtkWidget * widget,GdkEventFocus *)610 gint ScintillaGTK::FocusOut(GtkWidget *widget, GdkEventFocus * /*event*/) {
611 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
612 	//Platform::DebugPrintf("ScintillaGTK::focus out %x\n", sciThis);
613 	GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
614 	sciThis->SetFocusState(false);
615 
616 #ifdef INTERNATIONAL_INPUT
617 #if GTK_MAJOR_VERSION < 2
618 	gdk_im_end();
619 #else
620 	if (PWidget(sciThis->wPreedit) != NULL)
621 		gtk_widget_hide(PWidget(sciThis->wPreedit));
622 	if (sciThis->im_context != NULL)
623 		gtk_im_context_focus_out(sciThis->im_context);
624 #endif
625 #endif
626 
627 	return FALSE;
628 }
629 
SizeRequest(GtkWidget * widget,GtkRequisition * requisition)630 void ScintillaGTK::SizeRequest(GtkWidget *widget, GtkRequisition *requisition) {
631 	requisition->width = 600;
632 	requisition->height = gdk_screen_height();
633 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
634 	GtkRequisition child_requisition;
635 	gtk_widget_size_request(PWidget(sciThis->scrollbarh), &child_requisition);
636 	gtk_widget_size_request(PWidget(sciThis->scrollbarv), &child_requisition);
637 }
638 
SizeAllocate(GtkWidget * widget,GtkAllocation * allocation)639 void ScintillaGTK::SizeAllocate(GtkWidget *widget, GtkAllocation *allocation) {
640 	widget->allocation = *allocation;
641 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
642 	if (GTK_WIDGET_REALIZED(widget))
643 		gdk_window_move_resize(widget->window,
644 		                       widget->allocation.x,
645 		                       widget->allocation.y,
646 		                       widget->allocation.width,
647 		                       widget->allocation.height);
648 
649 	sciThis->Resize(allocation->width, allocation->height);
650 
651 #ifdef INTERNATIONAL_INPUT
652 #if GTK_MAJOR_VERSION < 2
653 	if (sciThis->ic && (gdk_ic_get_style(sciThis->ic) & GDK_IM_PREEDIT_POSITION)) {
654 		gint width, height;
655 
656 		gdk_window_get_size(widget->window, &width, &height);
657 		sciThis->ic_attr->preedit_area.width = width;
658 		sciThis->ic_attr->preedit_area.height = height;
659 
660 		gdk_ic_set_attr(sciThis->ic, sciThis->ic_attr, GDK_IC_PREEDIT_AREA);
661 	}
662 #endif
663 #endif
664 }
665 
Initialise()666 void ScintillaGTK::Initialise() {
667 	//Platform::DebugPrintf("ScintillaGTK::Initialise\n");
668 	parentClass = reinterpret_cast<GtkWidgetClass *>(
669 	                  gtk_type_class(gtk_container_get_type()));
670 
671 	GTK_WIDGET_SET_FLAGS(PWidget(wMain), GTK_CAN_FOCUS);
672 	GTK_WIDGET_SET_FLAGS(GTK_WIDGET(PWidget(wMain)), GTK_SENSITIVE);
673 	gtk_widget_set_events(PWidget(wMain),
674 	                      GDK_EXPOSURE_MASK
675 	                      | GDK_STRUCTURE_MASK
676 	                      | GDK_KEY_PRESS_MASK
677 	                      | GDK_KEY_RELEASE_MASK
678 	                      | GDK_FOCUS_CHANGE_MASK
679 	                      | GDK_LEAVE_NOTIFY_MASK
680 	                      | GDK_BUTTON_PRESS_MASK
681 	                      | GDK_BUTTON_RELEASE_MASK
682 	                      | GDK_POINTER_MOTION_MASK
683 	                      | GDK_POINTER_MOTION_HINT_MASK);
684 
685 	wText = gtk_drawing_area_new();
686 	gtk_widget_set_parent(PWidget(wText), PWidget(wMain));
687 	gtk_widget_show(PWidget(wText));
688 	gtk_signal_connect(GTK_OBJECT(PWidget(wText)), "expose_event",
689 			   GtkSignalFunc(ScintillaGTK::ExposeText), this);
690 	gtk_widget_set_events(PWidget(wText), GDK_EXPOSURE_MASK);
691 #if GTK_MAJOR_VERSION >= 2
692 	// Avoid background drawing flash
693 	gtk_widget_set_double_buffered(PWidget(wText), FALSE);
694 #endif
695 	gtk_drawing_area_size(GTK_DRAWING_AREA(PWidget(wText)),
696 	                      100,100);
697 
698 	adjustmentv = gtk_adjustment_new(0.0, 0.0, 201.0, 1.0, 20.0, 20.0);
699 	scrollbarv = gtk_vscrollbar_new(GTK_ADJUSTMENT(adjustmentv));
700 	GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarv), GTK_CAN_FOCUS);
701 	gtk_signal_connect(GTK_OBJECT(adjustmentv), "value_changed",
702 	                   GTK_SIGNAL_FUNC(ScrollSignal), this);
703 	gtk_widget_set_parent(PWidget(scrollbarv), PWidget(wMain));
704 	gtk_widget_show(PWidget(scrollbarv));
705 
706 	adjustmenth = gtk_adjustment_new(0.0, 0.0, 101.0, 1.0, 20.0, 20.0);
707 	scrollbarh = gtk_hscrollbar_new(GTK_ADJUSTMENT(adjustmenth));
708 	GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarh), GTK_CAN_FOCUS);
709 	gtk_signal_connect(GTK_OBJECT(adjustmenth), "value_changed",
710 	                   GTK_SIGNAL_FUNC(ScrollHSignal), this);
711 	gtk_widget_set_parent(PWidget(scrollbarh), PWidget(wMain));
712 	gtk_widget_show(PWidget(scrollbarh));
713 
714 	gtk_widget_grab_focus(PWidget(wMain));
715 
716 	gtk_selection_add_targets(GTK_WIDGET(PWidget(wMain)), GDK_SELECTION_PRIMARY,
717 	                          clipboardTargets, nClipboardTargets);
718 
719 #ifndef USE_GTK_CLIPBOARD
720 	gtk_selection_add_targets(GTK_WIDGET(PWidget(wMain)), atomClipboard,
721 	                          clipboardTargets, nClipboardTargets);
722 #endif
723 
724 	gtk_drag_dest_set(GTK_WIDGET(PWidget(wMain)),
725 	                  GTK_DEST_DEFAULT_ALL, clipboardTargets, nClipboardTargets,
726 	                  static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE));
727 
728 	SetTicking(true);
729 }
730 
Finalise()731 void ScintillaGTK::Finalise() {
732 	SetTicking(false);
733 	ScintillaBase::Finalise();
734 }
735 
DisplayCursor(Window::Cursor c)736 void ScintillaGTK::DisplayCursor(Window::Cursor c) {
737 	if (cursorMode == SC_CURSORNORMAL)
738 		wText.SetCursor(c);
739 	else
740 		wText.SetCursor(static_cast<Window::Cursor>(cursorMode));
741 }
742 
StartDrag()743 void ScintillaGTK::StartDrag() {
744 	dragWasDropped = false;
745 	static const GtkTargetEntry targets[] = {
746 	    { "UTF8_STRING", 0, TARGET_UTF8_STRING },
747 	    { "STRING", 0, TARGET_STRING },
748 	    // { "TEXT", 0, TARGET_TEXT },
749 	    // { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
750 	};
751 	static const gint n_targets = sizeof(targets) / sizeof(targets[0]);
752 	GtkTargetList *tl = gtk_target_list_new(targets, n_targets);
753 	gtk_drag_begin(GTK_WIDGET(PWidget(wMain)),
754 	               tl,
755 	               static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE),
756 	               evbtn.button,
757 	               reinterpret_cast<GdkEvent *>(&evbtn));
758 }
759 
760 #ifdef USE_CONVERTER
ConvertText(int * lenResult,char * s,size_t len,const char * charSetDest,const char * charSetSource)761 static char *ConvertText(int *lenResult, char *s, size_t len, const char *charSetDest, const char *charSetSource) {
762 	*lenResult = 0;
763 	char *destForm = 0;
764 	Converter conv(charSetDest, charSetSource);
765 	if (conv) {
766 		destForm = new char[len*3+1];
767 		char *pin = s;
768 		size_t inLeft = len;
769 		char *pout = destForm;
770 		size_t outLeft = len*3+1;
771 		size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
772 		if (conversions == ((size_t)(-1))) {
773 fprintf(stderr, "iconv %s->%s failed for %s\n", charSetSource, charSetDest, static_cast<char *>(s));
774 			delete []destForm;
775 			destForm = 0;
776 		} else {
777 //fprintf(stderr, "iconv OK %s %d\n", destForm, pout - destForm);
778 			*pout = '\0';
779 			*lenResult = pout - destForm;
780 		}
781 	} else {
782 fprintf(stderr, "Can not iconv %s %s\n", charSetDest, charSetSource);
783 	}
784 	if (!destForm) {
785 		destForm = new char[1];
786 		destForm[0] = '\0';
787 		*lenResult = 0;
788 	}
789 	return destForm;
790 }
791 #endif
792 
793 // Returns the target converted to UTF8.
794 // Return the length in bytes.
TargetAsUTF8(char * text)795 int ScintillaGTK::TargetAsUTF8(char *text) {
796 	int targetLength = targetEnd - targetStart;
797 	if (IsUnicodeMode()) {
798 		if (text) {
799 			pdoc->GetCharRange(text, targetStart, targetLength);
800 		}
801 	} else {
802 		// Need to convert
803 #ifdef USE_CONVERTER
804 		const char *charSetBuffer = CharacterSetID();
805 		if (*charSetBuffer) {
806 //~ fprintf(stderr, "AsUTF8 %s %d  %0d-%0d\n", charSetBuffer, targetLength, targetStart, targetEnd);
807 			char *s = new char[targetLength];
808 			if (s) {
809 				pdoc->GetCharRange(s, targetStart, targetLength);
810 //~ fprintf(stderr, "    \"%s\"\n", s);
811 				if (text) {
812 					char *tmputf = ConvertText(&targetLength, s, targetLength, "UTF-8", charSetBuffer);
813 					memcpy(text, tmputf, targetLength);
814 					delete []tmputf;
815 //~ fprintf(stderr, "    \"%s\"\n", text);
816 				}
817 				delete []s;
818 			}
819 		} else {
820 			if (text) {
821 				pdoc->GetCharRange(text, targetStart, targetLength);
822 			}
823 		}
824 #else
825 		// Fail
826 		return 0;
827 #endif
828 	}
829 //~ fprintf(stderr, "Length = %d bytes\n", targetLength);
830 	return targetLength;
831 }
832 
833 // Translates a nul terminated UTF8 string into the document encoding.
834 // Return the length of the result in bytes.
EncodedFromUTF8(char * utf8,char * encoded)835 int ScintillaGTK::EncodedFromUTF8(char *utf8, char *encoded) {
836 	int inputLength = (lengthForEncode >= 0) ? lengthForEncode : strlen(utf8);
837 	if (IsUnicodeMode()) {
838 		if (encoded) {
839 			memcpy(encoded, utf8, inputLength);
840 		}
841 		return inputLength;
842 	} else {
843 		// Need to convert
844 #ifdef USE_CONVERTER
845 		const char *charSetBuffer = CharacterSetID();
846 		if (*charSetBuffer) {
847 //~ fprintf(stderr, "Encode %s %d\n", charSetBuffer, inputLength);
848 			int outLength = 0;
849 			char *tmpEncoded = ConvertText(&outLength, utf8, inputLength, charSetBuffer, "UTF-8");
850 			if (tmpEncoded) {
851 //~ fprintf(stderr, "    \"%s\"\n", tmpEncoded);
852 				if (encoded) {
853 					memcpy(encoded, tmpEncoded, outLength);
854 				}
855 				delete []tmpEncoded;
856 			}
857 			return outLength;
858 		} else {
859 			if (encoded) {
860 				memcpy(encoded, utf8, inputLength);
861 			}
862 			return inputLength;
863 		}
864 #endif
865 	}
866 	// Fail
867 	return 0;
868 }
869 
WndProc(unsigned int iMessage,uptr_t wParam,sptr_t lParam)870 sptr_t ScintillaGTK::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
871 	switch (iMessage) {
872 
873 	case SCI_GRABFOCUS:
874 		gtk_widget_grab_focus(PWidget(wMain));
875 		break;
876 
877 	case SCI_GETDIRECTFUNCTION:
878 		return reinterpret_cast<sptr_t>(DirectFunction);
879 
880 	case SCI_GETDIRECTPOINTER:
881 		return reinterpret_cast<sptr_t>(this);
882 
883 #ifdef SCI_LEXER
884 	case SCI_LOADLEXERLIBRARY:
885 		LexerManager::GetInstance()->Load(reinterpret_cast<const char*>(wParam));
886 		break;
887 #endif
888 	case SCI_TARGETASUTF8:
889 		return TargetAsUTF8(reinterpret_cast<char*>(lParam));
890 
891 	case SCI_ENCODEDFROMUTF8:
892 		return EncodedFromUTF8(reinterpret_cast<char*>(wParam),
893 			reinterpret_cast<char*>(lParam));
894 
895 	default:
896 		return ScintillaBase::WndProc(iMessage, wParam, lParam);
897 	}
898 	return 0l;
899 }
900 
DefWndProc(unsigned int,uptr_t,sptr_t)901 sptr_t ScintillaGTK::DefWndProc(unsigned int, uptr_t, sptr_t) {
902 	return 0;
903 }
904 
SetTicking(bool on)905 void ScintillaGTK::SetTicking(bool on) {
906 	if (timer.ticking != on) {
907 		timer.ticking = on;
908 		if (timer.ticking) {
909 			timer.tickerID = reinterpret_cast<TickerID>(gtk_timeout_add(timer.tickSize, (GtkFunction)TimeOut, this));
910 		} else {
911 			gtk_timeout_remove(GPOINTER_TO_UINT(timer.tickerID));
912 		}
913 	}
914 	timer.ticksToWait = caret.period;
915 }
916 
SetIdle(bool on)917 bool ScintillaGTK::SetIdle(bool on) {
918 	if (on) {
919 		// Start idler, if it's not running.
920 		if (idler.state == false) {
921 			idler.state = true;
922 			idler.idlerID = reinterpret_cast<IdlerID>
923 				(gtk_idle_add((GtkFunction)IdleCallback, this));
924 		}
925 	} else {
926 		// Stop idler, if it's running
927 		if (idler.state == true) {
928 			idler.state = false;
929 			gtk_idle_remove(GPOINTER_TO_UINT(idler.idlerID));
930 		}
931 	}
932 	return true;
933 }
934 
SetMouseCapture(bool on)935 void ScintillaGTK::SetMouseCapture(bool on) {
936 	if (mouseDownCaptures) {
937 		if (on) {
938 			gtk_grab_add(GTK_WIDGET(PWidget(wMain)));
939 		} else {
940 			gtk_grab_remove(GTK_WIDGET(PWidget(wMain)));
941 		}
942 	}
943 	capturedMouse = on;
944 }
945 
HaveMouseCapture()946 bool ScintillaGTK::HaveMouseCapture() {
947 	return capturedMouse;
948 }
949 
950 // Redraw all of text area. This paint will not be abandoned.
FullPaint()951 void ScintillaGTK::FullPaint() {
952 #if GTK_MAJOR_VERSION < 2
953 	paintState = painting;
954 	rcPaint = GetClientRectangle();
955 	//Platform::DebugPrintf("ScintillaGTK::FullPaint %0d,%0d %0d,%0d\n",
956 	//	rcPaint.left, rcPaint.top, rcPaint.right, rcPaint.bottom);
957 	paintingAllText = true;
958 	if ((PWidget(wText))->window) {
959 		Surface *sw = Surface::Allocate();
960 		if (sw) {
961 			sw->Init(PWidget(wText)->window, PWidget(wText));
962 			Paint(sw, rcPaint);
963 			sw->Release();
964 			delete sw;
965 		}
966 	}
967 	paintState = notPainting;
968 #else
969 	wText.InvalidateAll();
970 #endif
971 }
972 
GetClientRectangle()973 PRectangle ScintillaGTK::GetClientRectangle() {
974 	PRectangle rc = wMain.GetClientPosition();
975 	if (verticalScrollBarVisible)
976 		rc.right -= scrollBarWidth;
977 	if (horizontalScrollBarVisible && (wrapState == eWrapNone))
978 		rc.bottom -= scrollBarHeight;
979 	// Move to origin
980 	rc.right -= rc.left;
981 	rc.bottom -= rc.top;
982 	rc.left = 0;
983 	rc.top = 0;
984 	return rc;
985 }
986 
987 // Synchronously paint a rectangle of the window.
SyncPaint(PRectangle rc)988 void ScintillaGTK::SyncPaint(PRectangle rc) {
989 	paintState = painting;
990 	rcPaint = rc;
991 	PRectangle rcClient = GetClientRectangle();
992 	paintingAllText = rcPaint.Contains(rcClient);
993 	if ((PWidget(wText))->window) {
994 		Surface *sw = Surface::Allocate();
995 		if (sw) {
996 			sw->Init(PWidget(wText)->window, PWidget(wText));
997 			Paint(sw, rc);
998 			sw->Release();
999 			delete sw;
1000 		}
1001 	}
1002 	if (paintState == paintAbandoned) {
1003 		// Painting area was insufficient to cover new styling or brace highlight positions
1004 		FullPaint();
1005 	}
1006 	paintState = notPainting;
1007 }
1008 
ScrollText(int linesToMove)1009 void ScintillaGTK::ScrollText(int linesToMove) {
1010 	int diff = vs.lineHeight * -linesToMove;
1011 	//Platform::DebugPrintf("ScintillaGTK::ScrollText %d %d %0d,%0d %0d,%0d\n", linesToMove, diff,
1012 	//	rc.left, rc.top, rc.right, rc.bottom);
1013 	GtkWidget *wi = PWidget(wText);
1014 
1015 #if GTK_MAJOR_VERSION < 2
1016 	PRectangle rc = GetClientRectangle();
1017 	GdkGC *gc = gdk_gc_new(wi->window);
1018 
1019 	// Set up gc so we get GraphicsExposures from gdk_draw_pixmap
1020 	//  which calls XCopyArea
1021 	gdk_gc_set_exposures(gc, TRUE);
1022 
1023 	// Redraw exposed bit : scrolling upwards
1024 	if (diff > 0) {
1025 		gdk_draw_pixmap(wi->window,
1026 		                gc, wi->window,
1027 		                0, diff,
1028 		                0, 0,
1029 		                rc.Width()-1, rc.Height() - diff);
1030 		SyncPaint(PRectangle(0, rc.Height() - diff,
1031 		                     rc.Width(), rc.Height()+1));
1032 
1033 	// Redraw exposed bit : scrolling downwards
1034 	} else {
1035 		gdk_draw_pixmap(wi->window,
1036 		                gc, wi->window,
1037 		                0, 0,
1038 		                0, -diff,
1039 		                rc.Width()-1, rc.Height() + diff);
1040 		SyncPaint(PRectangle(0, 0, rc.Width(), -diff));
1041 	}
1042 
1043 	// Look for any graphics expose
1044 	GdkEvent* event;
1045 	while ((event = gdk_event_get_graphics_expose(wi->window)) != NULL) {
1046 		gtk_widget_event(wi, event);
1047 		if (event->expose.count == 0) {
1048 			gdk_event_free(event);
1049 			break;
1050 		}
1051 		gdk_event_free(event);
1052 	}
1053 
1054 	gdk_gc_unref(gc);
1055 #else
1056 	gdk_window_scroll(wi->window, 0, -diff);
1057 	gdk_window_process_updates(wi->window, FALSE);
1058 #endif
1059 }
1060 
SetVerticalScrollPos()1061 void ScintillaGTK::SetVerticalScrollPos() {
1062 	DwellEnd(true);
1063 	gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmentv), topLine);
1064 }
1065 
SetHorizontalScrollPos()1066 void ScintillaGTK::SetHorizontalScrollPos() {
1067 	DwellEnd(true);
1068 	gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmenth), xOffset / 2);
1069 }
1070 
ModifyScrollBars(int nMax,int nPage)1071 bool ScintillaGTK::ModifyScrollBars(int nMax, int nPage) {
1072 	bool modified = false;
1073 	int pageScroll = LinesToScroll();
1074 
1075 	if (GTK_ADJUSTMENT(adjustmentv)->upper != (nMax + 1) ||
1076 	        GTK_ADJUSTMENT(adjustmentv)->page_size != nPage ||
1077 	        GTK_ADJUSTMENT(adjustmentv)->page_increment != pageScroll) {
1078 		GTK_ADJUSTMENT(adjustmentv)->upper = nMax + 1;
1079 		GTK_ADJUSTMENT(adjustmentv)->page_size = nPage;
1080 		GTK_ADJUSTMENT(adjustmentv)->page_increment = pageScroll;
1081 		gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv));
1082 		modified = true;
1083 	}
1084 
1085 	PRectangle rcText = GetTextRectangle();
1086 	int horizEndPreferred = scrollWidth;
1087 	if (horizEndPreferred < 0)
1088 		horizEndPreferred = 0;
1089 	unsigned int pageWidth = rcText.Width();
1090 	if (GTK_ADJUSTMENT(adjustmenth)->upper != horizEndPreferred ||
1091 	        GTK_ADJUSTMENT(adjustmenth)->page_size != pageWidth) {
1092 		GTK_ADJUSTMENT(adjustmenth)->upper = horizEndPreferred;
1093 		GTK_ADJUSTMENT(adjustmenth)->page_size = pageWidth;
1094 		gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth));
1095 		modified = true;
1096 	}
1097 	return modified;
1098 }
1099 
ReconfigureScrollBars()1100 void ScintillaGTK::ReconfigureScrollBars() {
1101 	PRectangle rc = wMain.GetClientPosition();
1102 	Resize(rc.Width(), rc.Height());
1103 }
1104 
NotifyChange()1105 void ScintillaGTK::NotifyChange() {
1106 	gtk_signal_emit(GTK_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL],
1107 	                Platform::LongFromTwoShorts(GetCtrlID(), SCEN_CHANGE), PWidget(wMain));
1108 }
1109 
NotifyFocus(bool focus)1110 void ScintillaGTK::NotifyFocus(bool focus) {
1111 	gtk_signal_emit(GTK_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL],
1112 	                Platform::LongFromTwoShorts(GetCtrlID(), focus ? SCEN_SETFOCUS : SCEN_KILLFOCUS), PWidget(wMain));
1113 }
1114 
NotifyParent(SCNotification scn)1115 void ScintillaGTK::NotifyParent(SCNotification scn) {
1116 	scn.nmhdr.hwndFrom = PWidget(wMain);
1117 	scn.nmhdr.idFrom = GetCtrlID();
1118 	gtk_signal_emit(GTK_OBJECT(sci), scintilla_signals[NOTIFY_SIGNAL],
1119 	                GetCtrlID(), &scn);
1120 }
1121 
NotifyKey(int key,int modifiers)1122 void ScintillaGTK::NotifyKey(int key, int modifiers) {
1123 	SCNotification scn = {0};
1124 	scn.nmhdr.code = SCN_KEY;
1125 	scn.ch = key;
1126 	scn.modifiers = modifiers;
1127 
1128 	NotifyParent(scn);
1129 }
1130 
NotifyURIDropped(const char * list)1131 void ScintillaGTK::NotifyURIDropped(const char *list) {
1132 	SCNotification scn = {0};
1133 	scn.nmhdr.code = SCN_URIDROPPED;
1134 	scn.text = list;
1135 
1136 	NotifyParent(scn);
1137 }
1138 
UseInputMethod() const1139 bool ScintillaGTK::UseInputMethod() const {
1140 	switch (vs.styles[STYLE_DEFAULT].characterSet) {
1141 	case SC_CHARSET_CHINESEBIG5:
1142 	case SC_CHARSET_GB2312:
1143 	case SC_CHARSET_HANGUL:
1144 	case SC_CHARSET_SHIFTJIS:
1145 	case SC_CHARSET_JOHAB:
1146 	case SC_CHARSET_HEBREW:
1147 	case SC_CHARSET_ARABIC:
1148 	case SC_CHARSET_VIETNAMESE:
1149 	case SC_CHARSET_THAI:
1150 		return true;
1151 	default:
1152 		return false;
1153 	}
1154 }
1155 
1156 const char *CharacterSetID(int characterSet);
1157 
CharacterSetID() const1158 const char *ScintillaGTK::CharacterSetID() const {
1159 	return ::CharacterSetID(vs.styles[STYLE_DEFAULT].characterSet);
1160 }
1161 
1162 #if GTK_MAJOR_VERSION >= 2
1163 #define IS_ACC(x) \
1164 	((x) >= 65103 && (x) <= 65111)
1165 #define IS_CHAR(x) \
1166 	((x) >= 0 && (x) <= 128)
1167 
1168 #define IS_ACC_OR_CHAR(x) \
1169 	(IS_CHAR(x)) || (IS_ACC(x))
1170 
1171 #define IS_ACC(x) \
1172 	((x) >= 65103 && (x) <= 65111)
1173 #define IS_CHAR(x) \
1174 	((x) >= 0 && (x) <= 128)
1175 
1176 #define IS_ACC_OR_CHAR(x) \
1177 	(IS_CHAR(x)) || (IS_ACC(x))
1178 
MakeAccent(int key,int acc)1179 static int MakeAccent(int key, int acc) {
1180 	const char *conv[] = {
1181 		"aeiounc AEIOUNC",
1182 		"�ei�u�c~�EI�U�C",
1183 		"�����n�'�����N�",
1184 		"�����nc`�����NC",
1185 		"�����nc^�����NC",
1186 		"�����nc������NC"
1187 	};
1188 	int idx;
1189 	for (idx = 0; idx < 15; ++idx) {
1190 		if (char(key) == conv[0][idx]) {
1191 			break;
1192 		}
1193 	}
1194 	if (idx == 15) {
1195 		return key;
1196 	}
1197 	if (acc == GDK_dead_tilde) { // ~
1198 		return int((unsigned char)(conv[1][idx]));
1199 	} else if (acc == GDK_dead_acute) { // '
1200 		return int((unsigned char)(conv[2][idx]));
1201 	} else if (acc == GDK_dead_grave) { // `
1202 		return int((unsigned char)(conv[3][idx]));
1203 	} else if (acc == GDK_dead_circumflex) { // ^
1204 		return int((unsigned char)(conv[4][idx]));
1205 	} else if (acc == GDK_dead_diaeresis) { // "
1206 		return int((unsigned char)(conv[5][idx]));
1207 	}
1208 	return key;
1209 }
1210 #endif
1211 
KeyDefault(int key,int modifiers)1212 int ScintillaGTK::KeyDefault(int key, int modifiers) {
1213 	if (!(modifiers & SCI_CTRL) && !(modifiers & SCI_ALT)) {
1214 #if GTK_MAJOR_VERSION >= 2
1215 		if (!UseInputMethod()) {
1216 			char utfVal[4]="\0\0\0";
1217 			wchar_t wcs[2];
1218 			if (IS_CHAR(key) && IS_ACC(lastKey)) {
1219 				lastKey = key = MakeAccent(key, lastKey);
1220 			}
1221 			if (IS_ACC_OR_CHAR(key)) {
1222 				lastKey = key;
1223 			}
1224 			wcs[0] = gdk_keyval_to_unicode(key);
1225 			wcs[1] = 0;
1226 			UTF8FromUCS2(wcs, 1, utfVal, 3);
1227 			if (key <= 0xFE00) {
1228 				if (IsUnicodeMode()) {
1229 					AddCharUTF(utfVal,strlen(utfVal));
1230 					return 1;
1231 				} else {
1232 					const char *source = CharacterSetID();
1233 					if (*source) {
1234 						Converter conv(source, "UTF-8");
1235 						if (conv) {
1236 							char localeVal[4]="\0\0\0";
1237 							char *pin = utfVal;
1238 							size_t inLeft = strlen(utfVal);
1239 							char *pout = localeVal;
1240 							size_t outLeft = sizeof(localeVal);
1241 							size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
1242 							if (conversions != ((size_t)(-1))) {
1243 								*pout = '\0';
1244 								for (int i=0; localeVal[i]; i++) {
1245 									AddChar(localeVal[i]);
1246 								}
1247 								return 1;
1248 							}
1249 						}
1250 					}
1251 				}
1252 			}
1253 		}
1254 #endif
1255 		if (key < 256) {
1256 			AddChar(key);
1257 			return 1;
1258 		} else {
1259 			// Pass up to container in case it is an accelerator
1260 			NotifyKey(key, modifiers);
1261 			return 0;
1262 		}
1263 	} else {
1264 		// Pass up to container in case it is an accelerator
1265 		NotifyKey(key, modifiers);
1266 		return 0;
1267 	}
1268 	//Platform::DebugPrintf("SK-key: %d %x %x\n",key, modifiers);
1269 }
1270 
CopyToClipboard(const SelectionText & selectedText)1271 void ScintillaGTK::CopyToClipboard(const SelectionText &selectedText) {
1272 #ifndef USE_GTK_CLIPBOARD
1273 	copyText.Copy(selectedText);
1274 	gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)),
1275 				atomClipboard,
1276 				GDK_CURRENT_TIME);
1277 #else
1278 	GtkClipboard *clipBoard;
1279 	clipBoard = gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain)), atomClipboard);
1280 	if (clipBoard == NULL) // Occurs if widget isn't in a toplevel
1281 		return;
1282 
1283 	SelectionText *clipText = new SelectionText();
1284 	clipText->Copy(selectedText);
1285 
1286 	gtk_clipboard_set_with_data(clipBoard, clipboardTargets, nClipboardTargets,
1287 				    ClipboardGetSelection, ClipboardClearSelection, clipText);
1288 
1289 #endif
1290 }
1291 
Copy()1292 void ScintillaGTK::Copy() {
1293 	if (currentPos != anchor) {
1294 #ifndef USE_GTK_CLIPBOARD
1295 		CopySelectionRange(&copyText);
1296 		gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)),
1297 		                        atomClipboard,
1298 		                        GDK_CURRENT_TIME);
1299 #else
1300 		GtkClipboard *clipBoard;
1301 		clipBoard = gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain)), atomClipboard);
1302 		if (clipBoard == NULL) // Occurs if widget isn't in a toplevel
1303 			return;
1304 
1305 		SelectionText *clipText = new SelectionText();
1306 		CopySelectionRange(clipText);
1307 
1308 		gtk_clipboard_set_with_data(clipBoard, clipboardTargets, nClipboardTargets,
1309 					    ClipboardGetSelection, ClipboardClearSelection, clipText);
1310 
1311 #endif
1312 #if PLAT_GTK_WIN32
1313 		if (selType == selRectangle) {
1314 			::OpenClipboard(NULL);
1315 			::SetClipboardData(cfColumnSelect, 0);
1316 			::CloseClipboard();
1317 		}
1318 #endif
1319 	}
1320 }
1321 
Paste()1322 void ScintillaGTK::Paste() {
1323 	atomSought = atomUTF8;
1324 	gtk_selection_convert(GTK_WIDGET(PWidget(wMain)),
1325 	                      atomClipboard, atomSought, GDK_CURRENT_TIME);
1326 }
1327 
CreateCallTipWindow(PRectangle rc)1328 void ScintillaGTK::CreateCallTipWindow(PRectangle rc) {
1329 	if (!ct.wCallTip.Created()) {
1330 		ct.wCallTip = gtk_window_new(GTK_WINDOW_POPUP);
1331 		ct.wDraw = gtk_drawing_area_new();
1332 		gtk_container_add(GTK_CONTAINER(PWidget(ct.wCallTip)), PWidget(ct.wDraw));
1333 		gtk_signal_connect(GTK_OBJECT(PWidget(ct.wDraw)), "expose_event",
1334 				   GtkSignalFunc(ScintillaGTK::ExposeCT), &ct);
1335 		gtk_signal_connect(GTK_OBJECT(PWidget(ct.wDraw)), "button_press_event",
1336 				   GtkSignalFunc(ScintillaGTK::PressCT), static_cast<void *>(this));
1337 		gtk_widget_set_events(PWidget(ct.wDraw),
1338 			GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK);
1339 	}
1340 
1341 	gtk_drawing_area_size(GTK_DRAWING_AREA(PWidget(ct.wDraw)),
1342 	                      rc.Width(), rc.Height());
1343 	ct.wDraw.Show();
1344 	//ct.wCallTip.Show();
1345 	//gtk_widget_set_usize(PWidget(ct.wCallTip), rc.Width(), rc.Height());
1346 
1347 	if( PWidget(ct.wCallTip)->window != NULL )
1348 		gdk_window_resize(PWidget(ct.wCallTip)->window, rc.Width(), rc.Height());
1349 }
1350 
AddToPopUp(const char * label,int cmd,bool enabled)1351 void ScintillaGTK::AddToPopUp(const char *label, int cmd, bool enabled) {
1352 	char fulllabel[200];
1353 	strcpy(fulllabel, "/");
1354 	strcat(fulllabel, label);
1355 	GtkItemFactoryCallback menuSig = GtkItemFactoryCallback(PopUpCB);
1356 	GtkItemFactoryEntry itemEntry = {
1357 	    fulllabel, NULL,
1358 	    menuSig,
1359 	    cmd,
1360 	    const_cast<gchar *>(label[0] ? "<Item>" : "<Separator>"),
1361 #if GTK_MAJOR_VERSION >= 2
1362 	    NULL
1363 #endif
1364 	};
1365 	gtk_item_factory_create_item(GTK_ITEM_FACTORY(popup.GetID()),
1366 	                             &itemEntry, this, 1);
1367 	if (cmd) {
1368 		GtkWidget *item = gtk_item_factory_get_widget_by_action(
1369 		                      reinterpret_cast<GtkItemFactory *>(popup.GetID()), cmd);
1370 		if (item)
1371 			gtk_widget_set_sensitive(item, enabled);
1372 	}
1373 }
1374 
OwnPrimarySelection()1375 bool ScintillaGTK::OwnPrimarySelection() {
1376 	return ((gdk_selection_owner_get(GDK_SELECTION_PRIMARY)
1377 		== GTK_WIDGET(PWidget(wMain))->window) &&
1378 			(GTK_WIDGET(PWidget(wMain))->window != NULL));
1379 }
1380 
ClaimSelection()1381 void ScintillaGTK::ClaimSelection() {
1382 	// X Windows has a 'primary selection' as well as the clipboard.
1383 	// Whenever the user selects some text, we become the primary selection
1384 	if (currentPos != anchor) {
1385 		primarySelection = true;
1386 		gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)),
1387 		                        GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
1388 		primary.Free();
1389 	} else if (OwnPrimarySelection()) {
1390 		primarySelection = true;
1391 		if (primary.s == NULL)
1392 			gtk_selection_owner_set(NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
1393 	} else {
1394 		primarySelection = false;
1395 		primary.Free();
1396 	}
1397 }
1398 
1399 // Detect rectangular text, convert line ends to current mode, convert from or to UTF-8
GetGtkSelectionText(GtkSelectionData * selectionData,SelectionText & selText)1400 void ScintillaGTK::GetGtkSelectionText(GtkSelectionData *selectionData, SelectionText &selText) {
1401 	char *data = reinterpret_cast<char *>(selectionData->data);
1402 	int len = selectionData->length;
1403 	GdkAtom selectionType = selectionData->type;
1404 
1405 	// Return empty string if selection is not a string
1406 	if ((selectionType != GDK_TARGET_STRING) && (selectionType != atomUTF8)) {
1407 		char *empty = new char[1];
1408 		empty[0] = '\0';
1409 		selText.Set(empty, 0, SC_CP_UTF8, 0, false);
1410 		return;
1411 	}
1412 
1413 	// Check for "\n\0" ending to string indicating that selection is rectangular
1414 	bool isRectangular;
1415 #if PLAT_GTK_WIN32
1416 	isRectangular = ::IsClipboardFormatAvailable(cfColumnSelect) != 0;
1417 #else
1418 	isRectangular = ((len > 2) && (data[len - 1] == 0 && data[len - 2] == '\n'));
1419 #endif
1420 
1421 	char *dest;
1422 	if (selectionType == GDK_TARGET_STRING) {
1423 		dest = Document::TransformLineEnds(&len, data, len, pdoc->eolMode);
1424 		if (IsUnicodeMode()) {
1425 			// Unknown encoding so assume in Latin1
1426 			char *destPrevious = dest;
1427 			dest = UTF8FromLatin1(dest, len);
1428 			selText.Set(dest, len, SC_CP_UTF8, 0, selText.rectangular);
1429 			delete []destPrevious;
1430 		} else {
1431 			// Assume buffer is in same encoding as selection
1432 			selText.Set(dest, len, pdoc->dbcsCodePage,
1433 				vs.styles[STYLE_DEFAULT].characterSet, isRectangular);
1434 		}
1435 	} else {	// UTF-8
1436 		dest = Document::TransformLineEnds(&len, data, len, pdoc->eolMode);
1437 		selText.Set(dest, len, SC_CP_UTF8, 0, isRectangular);
1438 #ifdef USE_CONVERTER
1439 		const char *charSetBuffer = CharacterSetID();
1440 		if (!IsUnicodeMode() && *charSetBuffer) {
1441 //fprintf(stderr, "Convert to locale %s\n", CharacterSetID());
1442 				// Convert to locale
1443 				dest = ConvertText(&len, selText.s, selText.len, charSetBuffer, "UTF-8");
1444 				selText.Set(dest, len, pdoc->dbcsCodePage,
1445 					vs.styles[STYLE_DEFAULT].characterSet, selText.rectangular);
1446 		}
1447 #endif
1448 	}
1449 }
1450 
ReceivedSelection(GtkSelectionData * selection_data)1451 void ScintillaGTK::ReceivedSelection(GtkSelectionData *selection_data) {
1452 	if ((selection_data->selection == atomClipboard) ||
1453 		(selection_data->selection == GDK_SELECTION_PRIMARY)) {
1454 		if ((atomSought == atomUTF8) && (selection_data->length <= 0)) {
1455 			atomSought = atomString;
1456 			gtk_selection_convert(GTK_WIDGET(PWidget(wMain)),
1457 					      selection_data->selection, atomSought, GDK_CURRENT_TIME);
1458 		} else if ((selection_data->length > 0) &&
1459 			((selection_data->type == GDK_TARGET_STRING) || (selection_data->type == atomUTF8))) {
1460 			SelectionText selText;
1461 			GetGtkSelectionText(selection_data, selText);
1462 
1463 			pdoc->BeginUndoAction();
1464 			if (selection_data->selection != GDK_SELECTION_PRIMARY) {
1465 				ClearSelection();
1466 			}
1467 			int selStart = SelectionStart();
1468 
1469 			if (selText.rectangular) {
1470 				PasteRectangular(selStart, selText.s, selText.len);
1471 			} else {
1472 				pdoc->InsertString(currentPos, selText.s, selText.len);
1473 				SetEmptySelection(currentPos + selText.len);
1474 			}
1475 			pdoc->EndUndoAction();
1476 		}
1477 	}
1478 //	else fprintf(stderr, "Target non string %d %d\n", (int)(selection_data->type),
1479 //		(int)(atomUTF8));
1480 	Redraw();
1481 }
1482 
ReceivedDrop(GtkSelectionData * selection_data)1483 void ScintillaGTK::ReceivedDrop(GtkSelectionData *selection_data) {
1484 	dragWasDropped = true;
1485 	if ((selection_data->type == GDK_TARGET_STRING) || (selection_data->type == atomUTF8)) {
1486 		if (selection_data->length > 0) {
1487 			SelectionText selText;
1488 			GetGtkSelectionText(selection_data, selText);
1489 			DropAt(posDrop, selText.s, false, selText.rectangular);
1490 		}
1491 	} else {
1492 		char *ptr = reinterpret_cast<char *>(selection_data->data);
1493 		NotifyURIDropped(ptr);
1494 	}
1495 	Redraw();
1496 }
1497 
1498 
1499 
GetSelection(GtkSelectionData * selection_data,guint info,SelectionText * text)1500 void ScintillaGTK::GetSelection(GtkSelectionData *selection_data, guint info, SelectionText *text) {
1501 #if GTK_MAJOR_VERSION >= 2
1502 	// Convert text to utf8 if it isn't already
1503 	SelectionText *converted = 0;
1504 	if ((text->codePage != SC_CP_UTF8) && (info == TARGET_UTF8_STRING)) {
1505 		const char *charSet = ::CharacterSetID(text->characterSet);
1506 		if (*charSet) {
1507 			int new_len;
1508 			char* tmputf = ConvertText(&new_len, text->s, text->len, "UTF-8", charSet);
1509 			converted = new SelectionText();
1510 			converted->Set(tmputf, new_len, SC_CP_UTF8, 0, text->rectangular);
1511 			text = converted;
1512 		}
1513 	}
1514 
1515 	// Here is a somewhat evil kludge.
1516 	// As I can not work out how to store data on the clipboard in multiple formats
1517 	// and need some way to mark the clipping as being stream or rectangular,
1518 	// the terminating \0 is included in the length for rectangular clippings.
1519 	// All other tested aplications behave benignly by ignoring the \0.
1520 	// The #if is here because on Windows cfColumnSelect clip entry is used
1521 	// instead as standard indicator of rectangularness (so no need to kludge)
1522 	int len = strlen(text->s);
1523 #if PLAT_GTK_WIN32 == 0
1524 	if (text->rectangular)
1525 		len++;
1526 #endif
1527 
1528 	if (info == TARGET_UTF8_STRING) {
1529 		gtk_selection_data_set_text(selection_data, text->s, len);
1530 	} else {
1531 		gtk_selection_data_set(selection_data,
1532 			static_cast<GdkAtom>(GDK_SELECTION_TYPE_STRING),
1533 			8, reinterpret_cast<unsigned char *>(text->s), len);
1534 	}
1535 	delete converted;
1536 
1537 #else /* Gtk 1 */
1538 	char *selBuffer = text->s;
1539 
1540 #if PLAT_GTK_WIN32
1541 
1542 	// Many native win32 programs require \n line endings,
1543 	 // so make a copy of the clip text now with newlines converted
1544 
1545 	int new_len;
1546 	char *tmpstr = Document::TransformLineEnds(&new_len, selBuffer, text->len, SC_EOL_LF);
1547 	selBuffer = tmpstr;
1548 #endif
1549 	char *tmputf = 0;
1550 	if ((info == TARGET_UTF8_STRING) || (info == TARGET_STRING)) {
1551 		int len = strlen(selBuffer);
1552 #ifdef USE_CONVERTER
1553 		// Possible character set conversion
1554 		const char *charSetBuffer = ::CharacterSetID(text->characterSet);
1555 		if (info == TARGET_UTF8_STRING) {
1556 			//fprintf(stderr, "Copy to clipboard as UTF-8\n");
1557 			if (text->codePage != SC_CP_UTF8) {
1558 				// Convert to UTF-8
1559 	//fprintf(stderr, "Convert to UTF-8 from %s\n", charSetBuffer);
1560 				tmputf = ConvertText(&len, selBuffer, len, "UTF-8", charSetBuffer);
1561 				selBuffer = tmputf;
1562 			}
1563 		} else if (info == TARGET_STRING) {
1564 			if (text->codePage == SC_CP_UTF8) {
1565 	//fprintf(stderr, "Convert to locale %s\n", charSetBuffer);
1566 				// Convert to locale
1567 				tmputf = ConvertText(&len, selBuffer, len, charSetBuffer, "UTF-8");
1568 				selBuffer = tmputf;
1569 			}
1570 		}
1571 #endif
1572 
1573 		// Here is a somewhat evil kludge.
1574 		// As I can not work out how to store data on the clipboard in multiple formats
1575 		// and need some way to mark the clipping as being stream or rectangular,
1576 		// the terminating \0 is included in the length for rectangular clippings.
1577 		// All other tested aplications behave benignly by ignoring the \0.
1578 		// The #if is here because on Windows cfColumnSelect clip entry is used
1579                 // instead as standard indicator of rectangularness (so no need to kludge)
1580 #if PLAT_GTK_WIN32 == 0
1581 		if (text->rectangular)
1582 			len++;
1583 #endif
1584 		gtk_selection_data_set(selection_data,
1585 					(info == TARGET_STRING) ?
1586 					static_cast<GdkAtom>(GDK_SELECTION_TYPE_STRING) : atomUTF8,
1587 		                       8, reinterpret_cast<unsigned char *>(selBuffer),
1588 		                       len);
1589 	} else if ((info == TARGET_TEXT) || (info == TARGET_COMPOUND_TEXT)) {
1590 		guchar *text;
1591 		GdkAtom encoding;
1592 		gint format;
1593 		gint new_length;
1594 
1595 		gdk_string_to_compound_text(reinterpret_cast<char *>(selBuffer),
1596 		                            &encoding, &format, &text, &new_length);
1597 		gtk_selection_data_set(selection_data, encoding, format, text, new_length);
1598 		gdk_free_compound_text(text);
1599 	}
1600 
1601 	delete []tmputf;
1602 #if PLAT_GTK_WIN32
1603 	delete []tmpstr;
1604 #endif
1605 #endif /* Gtk >= 2 */
1606 }
1607 
1608 #ifdef USE_GTK_CLIPBOARD
ClipboardGetSelection(GtkClipboard *,GtkSelectionData * selection_data,guint info,void * data)1609 void ScintillaGTK::ClipboardGetSelection(GtkClipboard *, GtkSelectionData *selection_data, guint info, void *data) {
1610 	GetSelection(selection_data, info, static_cast<SelectionText*>(data));
1611 }
1612 
ClipboardClearSelection(GtkClipboard *,void * data)1613 void ScintillaGTK::ClipboardClearSelection(GtkClipboard *, void *data) {
1614 	SelectionText *obj = static_cast<SelectionText*>(data);
1615 	delete obj;
1616 }
1617 #endif
1618 
UnclaimSelection(GdkEventSelection * selection_event)1619 void ScintillaGTK::UnclaimSelection(GdkEventSelection *selection_event) {
1620 	//Platform::DebugPrintf("UnclaimSelection\n");
1621 	if (selection_event->selection == GDK_SELECTION_PRIMARY) {
1622 		//Platform::DebugPrintf("UnclaimPrimarySelection\n");
1623 		if (!OwnPrimarySelection()) {
1624 			primary.Free();
1625 			primarySelection = false;
1626 			FullPaint();
1627 		}
1628 	}
1629 }
1630 
Resize(int width,int height)1631 void 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 	// Not always needed, but some themes can have different sizes of scrollbars
1636 	scrollBarWidth = GTK_WIDGET(PWidget(scrollbarv))->requisition.width;
1637 	scrollBarHeight = GTK_WIDGET(PWidget(scrollbarh))->requisition.height;
1638 
1639 	// These allocations should never produce negative sizes as they would wrap around to huge
1640 	// unsigned numbers inside GTK+ causing warnings.
1641 	bool showSBHorizontal = horizontalScrollBarVisible && (wrapState == eWrapNone);
1642 	int horizontalScrollBarHeight = scrollBarHeight;
1643 	if (!showSBHorizontal)
1644 		horizontalScrollBarHeight = 0;
1645 	int verticalScrollBarHeight = scrollBarWidth;
1646 	if (!verticalScrollBarVisible)
1647 		verticalScrollBarHeight = 0;
1648 
1649 	GtkAllocation alloc;
1650 	alloc.x = 0;
1651 	if (showSBHorizontal) {
1652 		alloc.y = height - scrollBarHeight;
1653 		alloc.width = Platform::Maximum(1, width - scrollBarWidth) + 1;
1654 		alloc.height = horizontalScrollBarHeight;
1655 	} else {
1656 		alloc.y = -scrollBarHeight;
1657 		alloc.width = 0;
1658 		alloc.height = 0;
1659 	}
1660 	gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarh)), &alloc);
1661 
1662 	alloc.y = 0;
1663 	if (verticalScrollBarVisible) {
1664 		alloc.x = width - scrollBarWidth;
1665 		alloc.width = scrollBarWidth;
1666 		alloc.height = Platform::Maximum(1, height - scrollBarHeight) + 1;
1667 		if (!showSBHorizontal)
1668 			alloc.height += scrollBarWidth-1;
1669 	} else {
1670 		alloc.x = -scrollBarWidth;
1671 		alloc.width = 0;
1672 		alloc.height = 0;
1673 	}
1674 	gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarv)), &alloc);
1675 	if (GTK_WIDGET_MAPPED(PWidget(wMain))) {
1676 		ChangeSize();
1677 	}
1678 
1679 	alloc.x = 0;
1680 	alloc.y = 0;
1681 	alloc.width = Platform::Maximum(1, width - scrollBarWidth);
1682 	alloc.height = Platform::Maximum(1, height - scrollBarHeight);
1683 	if (!showSBHorizontal)
1684 		alloc.height += scrollBarWidth;
1685 	gtk_widget_size_allocate(GTK_WIDGET(PWidget(wText)), &alloc);
1686 }
1687 
SetAdjustmentValue(GtkObject * object,int value)1688 static void SetAdjustmentValue(GtkObject *object, int value) {
1689 	GtkAdjustment *adjustment = GTK_ADJUSTMENT(object);
1690 	int maxValue = static_cast<int>(
1691 		adjustment->upper - adjustment->page_size);
1692 	if (value > maxValue)
1693 		value = maxValue;
1694 	if (value < 0)
1695 		value = 0;
1696 	gtk_adjustment_set_value(adjustment, value);
1697 }
1698 
PressThis(GdkEventButton * event)1699 gint ScintillaGTK::PressThis(GdkEventButton *event) {
1700 	//Platform::DebugPrintf("Press %x time=%d state = %x button = %x\n",this,event->time, event->state, event->button);
1701 	// Do not use GTK+ double click events as Scintilla has its own double click detection
1702 	if (event->type != GDK_BUTTON_PRESS)
1703 		return FALSE;
1704 
1705 	evbtn = *event;
1706 	Point pt;
1707 	pt.x = int(event->x);
1708 	pt.y = int(event->y);
1709 	PRectangle rcClient = GetClientRectangle();
1710 	//Platform::DebugPrintf("Press %0d,%0d in %0d,%0d %0d,%0d\n",
1711 	//	pt.x, pt.y, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1712 	if ((pt.x > rcClient.right) || (pt.y > rcClient.bottom)) {
1713 		Platform::DebugPrintf("Bad location\n");
1714 		return FALSE;
1715 	}
1716 
1717 	bool ctrl = (event->state & GDK_CONTROL_MASK) != 0;
1718 
1719 	gtk_widget_grab_focus(PWidget(wMain));
1720 	if (event->button == 1) {
1721 		// On X, instead of sending literal modifiers use control instead of alt
1722 		// This is because most X window managers grab alt + click for moving
1723 #if !PLAT_GTK_WIN32
1724 		ButtonDown(pt, event->time,
1725 				    (event->state & GDK_SHIFT_MASK) != 0,
1726 				    (event->state & GDK_CONTROL_MASK) != 0,
1727 				    (event->state & GDK_CONTROL_MASK) != 0);
1728 #else
1729 		ButtonDown(pt, event->time,
1730 				    (event->state & GDK_SHIFT_MASK) != 0,
1731 				    (event->state & GDK_CONTROL_MASK) != 0,
1732 				    (event->state & GDK_MOD1_MASK) != 0);
1733 #endif
1734 	} else if (event->button == 2) {
1735 		// Grab the primary selection if it exists
1736 		Position pos = PositionFromLocation(pt);
1737 		if (OwnPrimarySelection() && primary.s == NULL)
1738 			CopySelectionRange(&primary);
1739 
1740 		SetSelection(pos, pos);
1741 		atomSought = atomUTF8;
1742 		gtk_selection_convert(GTK_WIDGET(PWidget(wMain)), GDK_SELECTION_PRIMARY,
1743 		                      atomSought, event->time);
1744 	} else if (event->button == 3) {
1745 		if (displayPopupMenu) {
1746 			// PopUp menu
1747 			// Convert to screen
1748 			int ox = 0;
1749 			int oy = 0;
1750 			gdk_window_get_origin(PWidget(wMain)->window, &ox, &oy);
1751 			ContextMenu(Point(pt.x + ox, pt.y + oy));
1752 		} else {
1753 			return FALSE;
1754 		}
1755 	} else if (event->button == 4) {
1756 		// Wheel scrolling up (only xwin gtk does it this way)
1757 		if (ctrl)
1758 			SetAdjustmentValue(adjustmenth, (xOffset / 2) - 6);
1759 		else
1760 			SetAdjustmentValue(adjustmentv, topLine - 3);
1761 	} else if (event->button == 5) {
1762 		// Wheel scrolling down (only xwin gtk does it this way)
1763 		if (ctrl)
1764 			SetAdjustmentValue(adjustmenth, (xOffset / 2) + 6);
1765 		else
1766 			SetAdjustmentValue(adjustmentv, topLine + 3);
1767 	}
1768 #if GTK_MAJOR_VERSION >= 2
1769 	return TRUE;
1770 #else
1771 	return FALSE;
1772 #endif
1773 }
1774 
Press(GtkWidget * widget,GdkEventButton * event)1775 gint ScintillaGTK::Press(GtkWidget *widget, GdkEventButton *event) {
1776 	if (event->window != widget->window)
1777 		return FALSE;
1778 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
1779 	return sciThis->PressThis(event);
1780 }
1781 
MouseRelease(GtkWidget * widget,GdkEventButton * event)1782 gint ScintillaGTK::MouseRelease(GtkWidget *widget, GdkEventButton *event) {
1783 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
1784 	//Platform::DebugPrintf("Release %x %d %d\n",sciThis,event->time,event->state);
1785 	if (!sciThis->HaveMouseCapture())
1786 		return FALSE;
1787 	if (event->button == 1) {
1788 		Point pt;
1789 		pt.x = int(event->x);
1790 		pt.y = int(event->y);
1791 		//Platform::DebugPrintf("Up %x %x %d %d %d\n",
1792 		//	sciThis,event->window,event->time, pt.x, pt.y);
1793 		if (event->window != PWidget(sciThis->wMain)->window)
1794 			// If mouse released on scroll bar then the position is relative to the
1795 			// scrollbar, not the drawing window so just repeat the most recent point.
1796 			pt = sciThis->ptMouseLast;
1797 		sciThis->ButtonUp(pt, event->time, (event->state & 4) != 0);
1798 	}
1799 	return FALSE;
1800 }
1801 
1802 // win32gtk has a special wheel mouse event for whatever reason and doesn't
1803 // use the button4/5 trick used under X windows.
1804 #if PLAT_GTK_WIN32 || (GTK_MAJOR_VERSION >= 2)
ScrollEvent(GtkWidget * widget,GdkEventScroll * event)1805 gint ScintillaGTK::ScrollEvent(GtkWidget *widget,
1806                                GdkEventScroll *event) {
1807 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
1808 
1809 	if (widget == NULL || event == NULL)
1810 		return FALSE;
1811 
1812 	// Compute amount and direction to scroll (even tho on win32 there is
1813 	// intensity of scrolling info in the native message, gtk doesn't
1814 	// support this so we simulate similarly adaptive scrolling)
1815 	int cLineScroll;
1816 	int timeDelta = 1000000;
1817 	GTimeVal curTime;
1818 	g_get_current_time(&curTime);
1819 	if (curTime.tv_sec == sciThis->lastWheelMouseTime.tv_sec)
1820 		timeDelta = curTime.tv_usec - sciThis->lastWheelMouseTime.tv_usec;
1821 	else if (curTime.tv_sec == sciThis->lastWheelMouseTime.tv_sec + 1)
1822 		timeDelta = 1000000 + (curTime.tv_usec - sciThis->lastWheelMouseTime.tv_usec);
1823 	if ((event->direction == sciThis->lastWheelMouseDirection) && (timeDelta < 250000)) {
1824 		if (sciThis->wheelMouseIntensity < 12)
1825 			sciThis->wheelMouseIntensity++;
1826 		cLineScroll = sciThis->wheelMouseIntensity;
1827 	} else {
1828 		cLineScroll = sciThis->linesPerScroll;
1829 		if (cLineScroll == 0)
1830 			cLineScroll = 4;
1831 		sciThis->wheelMouseIntensity = cLineScroll;
1832 	}
1833 	if (event->direction == GDK_SCROLL_UP) {
1834 		cLineScroll *= -1;
1835 	}
1836 	g_get_current_time(&sciThis->lastWheelMouseTime);
1837 	sciThis->lastWheelMouseDirection = event->direction;
1838 
1839 	// Note:  Unpatched versions of win32gtk don't set the 'state' value so
1840 	// only regular scrolling is supported there.  Also, unpatched win32gtk
1841 	// issues spurious button 2 mouse events during wheeling, which can cause
1842 	// problems (a patch for both was submitted by archaeopteryx.com on 13Jun2001)
1843 
1844 	// Data zoom not supported
1845 	if (event->state & GDK_SHIFT_MASK) {
1846 		return FALSE;
1847 	}
1848 
1849 	// Text font size zoom
1850 	if (event->state & GDK_CONTROL_MASK) {
1851 		if (cLineScroll < 0) {
1852 			sciThis->KeyCommand(SCI_ZOOMIN);
1853 			return TRUE;
1854 		} else {
1855 			sciThis->KeyCommand(SCI_ZOOMOUT);
1856 			return TRUE;
1857 		}
1858 
1859 	// Regular scrolling
1860 	} else {
1861 		sciThis->ScrollTo(sciThis->topLine + cLineScroll);
1862 		return TRUE;
1863 	}
1864 }
1865 #endif
1866 
Motion(GtkWidget * widget,GdkEventMotion * event)1867 gint ScintillaGTK::Motion(GtkWidget *widget, GdkEventMotion *event) {
1868 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
1869 	//Platform::DebugPrintf("Motion %x %d\n",sciThis,event->time);
1870 	if (event->window != widget->window)
1871 		return FALSE;
1872 	int x = 0;
1873 	int y = 0;
1874 	GdkModifierType state;
1875 	if (event->is_hint) {
1876 		gdk_window_get_pointer(event->window, &x, &y, &state);
1877 	} else {
1878 		x = static_cast<int>(event->x);
1879 		y = static_cast<int>(event->y);
1880 		state = static_cast<GdkModifierType>(event->state);
1881 	}
1882 	//Platform::DebugPrintf("Move %x %x %d %c %d %d\n",
1883 	//	sciThis,event->window,event->time,event->is_hint? 'h' :'.', x, y);
1884 	Point pt(x, y);
1885 	sciThis->ButtonMove(pt);
1886 	return FALSE;
1887 }
1888 
1889 // Map the keypad keys to their equivalent functions
KeyTranslate(int keyIn)1890 static int KeyTranslate(int keyIn) {
1891 	switch (keyIn) {
1892 	case GDK_ISO_Left_Tab:
1893 		return SCK_TAB;
1894 	case GDK_KP_Down:
1895 		return SCK_DOWN;
1896 	case GDK_KP_Up:
1897 		return SCK_UP;
1898 	case GDK_KP_Left:
1899 		return SCK_LEFT;
1900 	case GDK_KP_Right:
1901 		return SCK_RIGHT;
1902 	case GDK_KP_Home:
1903 		return SCK_HOME;
1904 	case GDK_KP_End:
1905 		return SCK_END;
1906 	case GDK_KP_Page_Up:
1907 		return SCK_PRIOR;
1908 	case GDK_KP_Page_Down:
1909 		return SCK_NEXT;
1910 	case GDK_KP_Delete:
1911 		return SCK_DELETE;
1912 	case GDK_KP_Insert:
1913 		return SCK_INSERT;
1914 	case GDK_KP_Enter:
1915 		return SCK_RETURN;
1916 
1917 	case GDK_Down:
1918 		return SCK_DOWN;
1919 	case GDK_Up:
1920 		return SCK_UP;
1921 	case GDK_Left:
1922 		return SCK_LEFT;
1923 	case GDK_Right:
1924 		return SCK_RIGHT;
1925 	case GDK_Home:
1926 		return SCK_HOME;
1927 	case GDK_End:
1928 		return SCK_END;
1929 	case GDK_Page_Up:
1930 		return SCK_PRIOR;
1931 	case GDK_Page_Down:
1932 		return SCK_NEXT;
1933 	case GDK_Delete:
1934 		return SCK_DELETE;
1935 	case GDK_Insert:
1936 		return SCK_INSERT;
1937 	case GDK_Escape:
1938 		return SCK_ESCAPE;
1939 	case GDK_BackSpace:
1940 		return SCK_BACK;
1941 	case GDK_Tab:
1942 		return SCK_TAB;
1943 	case GDK_Return:
1944 		return SCK_RETURN;
1945 	case GDK_KP_Add:
1946 		return SCK_ADD;
1947 	case GDK_KP_Subtract:
1948 		return SCK_SUBTRACT;
1949 	case GDK_KP_Divide:
1950 		return SCK_DIVIDE;
1951 	default:
1952 		return keyIn;
1953 	}
1954 }
1955 
KeyThis(GdkEventKey * event)1956 gint ScintillaGTK::KeyThis(GdkEventKey *event) {
1957 	//Platform::DebugPrintf("SC-key: %d %x [%s]\n",
1958 	//	event->keyval, event->state, (event->length > 0) ? event->string : "empty");
1959 #if GTK_MAJOR_VERSION >= 2
1960 	if (UseInputMethod()) {
1961 		if (gtk_im_context_filter_keypress(im_context, event)) {
1962 			return 1;
1963 		}
1964 	}
1965 #endif
1966 	if (!event->keyval) {
1967 		return true;
1968 	}
1969 
1970 	bool shift = (event->state & GDK_SHIFT_MASK) != 0;
1971 	bool ctrl = (event->state & GDK_CONTROL_MASK) != 0;
1972 	bool alt = (event->state & GDK_MOD1_MASK) != 0;
1973 	int key = event->keyval;
1974 	if (ctrl && (key < 128))
1975 		key = toupper(key);
1976 	else if (!ctrl && (key >= GDK_KP_Multiply && key <= GDK_KP_9))
1977 		key &= 0x7F;
1978 	// Hack for keys over 256 and below command keys but makes Hungarian work.
1979 	// This will have to change for Unicode
1980 	else if (key >= 0xFE00)
1981 		key = KeyTranslate(key);
1982 	else if (IsUnicodeMode())
1983 		;	// No operation
1984 #if GTK_MAJOR_VERSION < 2
1985 	else if ((key >= 0x100) && (key < 0x1000))
1986 		key &= 0xff;
1987 #endif
1988 
1989 	bool consumed = false;
1990 	bool added = KeyDown(key, shift, ctrl, alt, &consumed) != 0;
1991 	if (!consumed)
1992 		consumed = added;
1993 	//Platform::DebugPrintf("SK-key: %d %x %x\n",event->keyval, event->state, consumed);
1994 	if (event->keyval == 0xffffff && event->length > 0) {
1995 		ClearSelection();
1996 		if (pdoc->InsertString(CurrentPosition(), event->string)) {
1997 			MovePositionTo(CurrentPosition() + event->length);
1998 		}
1999 	}
2000 	return consumed;
2001 }
2002 
KeyPress(GtkWidget * widget,GdkEventKey * event)2003 gint ScintillaGTK::KeyPress(GtkWidget *widget, GdkEventKey *event) {
2004 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2005 	return sciThis->KeyThis(event);
2006 }
2007 
KeyRelease(GtkWidget *,GdkEventKey *)2008 gint ScintillaGTK::KeyRelease(GtkWidget *, GdkEventKey * /*event*/) {
2009 	//Platform::DebugPrintf("SC-keyrel: %d %x %3s\n",event->keyval, event->state, event->string);
2010 	return FALSE;
2011 }
2012 
2013 #if GTK_MAJOR_VERSION >= 2
ExposePreedit(GtkWidget * widget,GdkEventExpose * ose,ScintillaGTK * sciThis)2014 gint ScintillaGTK::ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis) {
2015 	return sciThis->ExposePreeditThis(widget, ose);
2016 }
2017 
ExposePreeditThis(GtkWidget * widget,GdkEventExpose * ose)2018 gint ScintillaGTK::ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose) {
2019 	gchar *str;
2020 	gint cursor_pos;
2021 	PangoAttrList *attrs;
2022 
2023 	gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos);
2024 	PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str);
2025 	pango_layout_set_attributes(layout, attrs);
2026 
2027 	GdkGC *gc = gdk_gc_new(widget->window);
2028 	GdkColor color[2] = {   {0, 0x0000, 0x0000, 0x0000},
2029                             {0, 0xffff, 0xffff, 0xffff}};
2030 	gdk_color_alloc(gdk_colormap_get_system(), color);
2031 	gdk_color_alloc(gdk_colormap_get_system(), color + 1);
2032 
2033 	gdk_gc_set_foreground(gc, color + 1);
2034 	gdk_draw_rectangle(widget->window, gc, TRUE, ose->area.x, ose->area.y,
2035 	                   ose->area.width, ose->area.height);
2036 
2037 	gdk_gc_set_foreground(gc, color);
2038 	gdk_gc_set_background(gc, color + 1);
2039 	gdk_draw_layout(widget->window, gc, 0, 0, layout);
2040 
2041 	gdk_gc_unref(gc);
2042 	g_free(str);
2043 	pango_attr_list_unref(attrs);
2044 	g_object_unref(layout);
2045 	return TRUE;
2046 }
2047 
Commit(GtkIMContext *,char * str,ScintillaGTK * sciThis)2048 void ScintillaGTK::Commit(GtkIMContext *, char  *str, ScintillaGTK *sciThis) {
2049 	sciThis->CommitThis(str);
2050 }
2051 
CommitThis(char * str)2052 void ScintillaGTK::CommitThis(char *str) {
2053 	AddCharUTF(str, strlen(str));
2054 }
2055 
PreeditChanged(GtkIMContext *,ScintillaGTK * sciThis)2056 void ScintillaGTK::PreeditChanged(GtkIMContext *, ScintillaGTK *sciThis) {
2057 	sciThis->PreeditChangedThis();
2058 }
2059 
PreeditChangedThis()2060 void ScintillaGTK::PreeditChangedThis() {
2061 	gchar *str;
2062 	PangoAttrList *attrs;
2063 	gint cursor_pos;
2064 	gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos);
2065 	if (strlen(str) > 0){
2066 		PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str);
2067 		pango_layout_set_attributes(layout, attrs);
2068 
2069 		gint w, h;
2070 		pango_layout_get_pixel_size(layout, &w, &h);
2071 		g_object_unref(layout);
2072 
2073 		gint x, y;
2074 		gdk_window_get_origin((PWidget(wText))->window, &x, &y);
2075 
2076 		Point pt = LocationFromPosition(currentPos);
2077 		if (pt.x < 0)
2078 			pt.x = 0;
2079 		if (pt.y < 0)
2080 			pt.y = 0;
2081 
2082 		gtk_window_move(GTK_WINDOW(PWidget(wPreedit)), x+pt.x, y+pt.y);
2083 		gtk_window_resize(GTK_WINDOW(PWidget(wPreedit)), w, h);
2084 		gtk_widget_show(PWidget(wPreedit));
2085 		gtk_widget_queue_draw_area(PWidget(wPreeditDraw), 0, 0, w, h);
2086 	} else {
2087 		gtk_widget_hide(PWidget(wPreedit));
2088 	}
2089 	g_free(str);
2090 	pango_attr_list_unref(attrs);
2091 }
2092 #endif
2093 
StyleSetText(GtkWidget * widget,GtkStyle *,void *)2094 gint ScintillaGTK::StyleSetText(GtkWidget *widget, GtkStyle *, void*) {
2095 	if (widget->window != NULL)
2096 		gdk_window_set_back_pixmap(widget->window, NULL, FALSE);
2097 	return FALSE;
2098 }
2099 
RealizeText(GtkWidget * widget,void *)2100 gint ScintillaGTK::RealizeText(GtkWidget *widget, void*) {
2101 	if (widget->window != NULL)
2102 		gdk_window_set_back_pixmap(widget->window, NULL, FALSE);
2103 	return FALSE;
2104 }
2105 
Destroy(GtkObject * object)2106 void ScintillaGTK::Destroy(GtkObject* object) {
2107 	ScintillaObject *scio = reinterpret_cast<ScintillaObject *>(object);
2108 	// This avoids a double destruction
2109 	if (!scio->pscin)
2110 		return;
2111 	ScintillaGTK *sciThis = reinterpret_cast<ScintillaGTK *>(scio->pscin);
2112 	//Platform::DebugPrintf("Destroying %x %x\n", sciThis, object);
2113 	sciThis->Finalise();
2114 
2115 	if (GTK_OBJECT_CLASS(parent_class)->destroy)
2116 		(* GTK_OBJECT_CLASS(parent_class)->destroy)(object);
2117 
2118 	delete sciThis;
2119 	scio->pscin = 0;
2120 }
2121 
DrawChild(GtkWidget * widget,GdkRectangle * area)2122 static void DrawChild(GtkWidget *widget, GdkRectangle *area) {
2123 	GdkRectangle areaIntersect;
2124 	if (widget &&
2125 	        GTK_WIDGET_DRAWABLE(widget) &&
2126 	        gtk_widget_intersect(widget, area, &areaIntersect)) {
2127 		gtk_widget_draw(widget, &areaIntersect);
2128 	}
2129 }
2130 
Draw(GtkWidget * widget,GdkRectangle * area)2131 void ScintillaGTK::Draw(GtkWidget *widget, GdkRectangle *area) {
2132 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2133 	//Platform::DebugPrintf("Draw %p %0d,%0d %0d,%0d\n", widget, area->x, area->y, area->width, area->height);
2134 	PRectangle rcPaint(area->x, area->y, area->x + area->width, area->y + area->height);
2135 	sciThis->SyncPaint(rcPaint);
2136 	if (GTK_WIDGET_DRAWABLE(PWidget(sciThis->wMain))) {
2137 		DrawChild(PWidget(sciThis->scrollbarh), area);
2138 		DrawChild(PWidget(sciThis->scrollbarv), area);
2139 	}
2140 
2141 #ifdef INTERNATIONAL_INPUT
2142 	Point pt = sciThis->LocationFromPosition(sciThis->currentPos);
2143 	pt.y += sciThis->vs.lineHeight - 2;
2144 	if (pt.x < 0) pt.x = 0;
2145 	if (pt.y < 0) pt.y = 0;
2146 	CursorMoved(widget, pt.x, pt.y, sciThis);
2147 #endif
2148 }
2149 
ExposeTextThis(GtkWidget *,GdkEventExpose * ose)2150 gint ScintillaGTK::ExposeTextThis(GtkWidget * /*widget*/, GdkEventExpose *ose) {
2151 	paintState = painting;
2152 
2153 	rcPaint.left = ose->area.x;
2154 	rcPaint.top = ose->area.y;
2155 	rcPaint.right = ose->area.x + ose->area.width;
2156 	rcPaint.bottom = ose->area.y + ose->area.height;
2157 
2158 	PRectangle rcClient = GetClientRectangle();
2159 	paintingAllText = rcPaint.Contains(rcClient);
2160 	Surface *surfaceWindow = Surface::Allocate();
2161 	if (surfaceWindow) {
2162 		surfaceWindow->Init(PWidget(wText)->window, PWidget(wText));
2163 		Paint(surfaceWindow, rcPaint);
2164 		surfaceWindow->Release();
2165 		delete surfaceWindow;
2166 	}
2167 	if (paintState == paintAbandoned) {
2168 		// Painting area was insufficient to cover new styling or brace highlight positions
2169 		FullPaint();
2170 	}
2171 	paintState = notPainting;
2172 	return FALSE;
2173 }
2174 
ExposeText(GtkWidget * widget,GdkEventExpose * ose,ScintillaGTK * sciThis)2175 gint ScintillaGTK::ExposeText(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis) {
2176 	return sciThis->ExposeTextThis(widget, ose);
2177 }
2178 
ExposeMain(GtkWidget * widget,GdkEventExpose * ose)2179 gint ScintillaGTK::ExposeMain(GtkWidget *widget, GdkEventExpose *ose) {
2180 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2181 	//Platform::DebugPrintf("Expose Main %0d,%0d %0d,%0d\n",
2182 	//ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2183 	return sciThis->Expose(widget, ose);
2184 }
2185 
Expose(GtkWidget *,GdkEventExpose * ose)2186 gint ScintillaGTK::Expose(GtkWidget *, GdkEventExpose *ose) {
2187 	//fprintf(stderr, "Expose %0d,%0d %0d,%0d\n",
2188 	//ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2189 
2190 #if GTK_MAJOR_VERSION < 2
2191 
2192 	paintState = painting;
2193 
2194 	rcPaint.left = ose->area.x;
2195 	rcPaint.top = ose->area.y;
2196 	rcPaint.right = ose->area.x + ose->area.width;
2197 	rcPaint.bottom = ose->area.y + ose->area.height;
2198 
2199 	PRectangle rcClient = GetClientRectangle();
2200 	paintingAllText = rcPaint.Contains(rcClient);
2201 	Surface *surfaceWindow = Surface::Allocate();
2202 	if (surfaceWindow) {
2203 		surfaceWindow->Init(PWidget(wMain)->window, PWidget(wMain));
2204 
2205 		// Fill the corner between the scrollbars
2206 		if (verticalScrollBarVisible) {
2207 			if (horizontalScrollBarVisible && (wrapState == eWrapNone)) {
2208 				PRectangle rcCorner = wMain.GetClientPosition();
2209 				rcCorner.left = rcCorner.right - scrollBarWidth + 1;
2210 				rcCorner.top = rcCorner.bottom - scrollBarHeight + 1;
2211 				//fprintf(stderr, "Corner %0d,%0d %0d,%0d\n",
2212 				//rcCorner.left, rcCorner.top, rcCorner.right, rcCorner.bottom);
2213 				surfaceWindow->FillRectangle(rcCorner,
2214 					vs.styles[STYLE_LINENUMBER].back.allocated);
2215 			}
2216 		}
2217 
2218 		//Paint(surfaceWindow, rcPaint);
2219 		surfaceWindow->Release();
2220 		delete surfaceWindow;
2221 	}
2222 	if (paintState == paintAbandoned) {
2223 		// Painting area was insufficient to cover new styling or brace highlight positions
2224 		FullPaint();
2225 	}
2226 	paintState = notPainting;
2227 
2228 #else
2229 	// For GTK+ 2, the text is painted in ExposeText
2230 	gtk_container_propagate_expose(
2231 		GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarh), ose);
2232 	gtk_container_propagate_expose(
2233 		GTK_CONTAINER(PWidget(wMain)), PWidget(scrollbarv), ose);
2234 #endif
2235 
2236 	return FALSE;
2237 }
2238 
ScrollSignal(GtkAdjustment * adj,ScintillaGTK * sciThis)2239 void ScintillaGTK::ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) {
2240 	sciThis->ScrollTo(static_cast<int>(adj->value), false);
2241 }
2242 
ScrollHSignal(GtkAdjustment * adj,ScintillaGTK * sciThis)2243 void ScintillaGTK::ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) {
2244 	sciThis->HorizontalScrollTo(static_cast<int>(adj->value * 2));
2245 }
2246 
SelectionReceived(GtkWidget * widget,GtkSelectionData * selection_data,guint)2247 void ScintillaGTK::SelectionReceived(GtkWidget *widget,
2248                                      GtkSelectionData *selection_data, guint) {
2249 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2250 	//Platform::DebugPrintf("Selection received\n");
2251 	sciThis->ReceivedSelection(selection_data);
2252 }
2253 
SelectionGet(GtkWidget * widget,GtkSelectionData * selection_data,guint info,guint)2254 void ScintillaGTK::SelectionGet(GtkWidget *widget,
2255                                 GtkSelectionData *selection_data, guint info, guint) {
2256 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2257 	//Platform::DebugPrintf("Selection get\n");
2258 	if (selection_data->selection == GDK_SELECTION_PRIMARY) {
2259 		if (sciThis->primary.s == NULL) {
2260 			sciThis->CopySelectionRange(&sciThis->primary);
2261 		}
2262 		sciThis->GetSelection(selection_data, info, &sciThis->primary);
2263 	}
2264 #ifndef USE_GTK_CLIPBOARD
2265 	else {
2266 		sciThis->GetSelection(selection_data, info, &sciThis->copyText);
2267 	}
2268 #endif
2269 }
2270 
SelectionClear(GtkWidget * widget,GdkEventSelection * selection_event)2271 gint ScintillaGTK::SelectionClear(GtkWidget *widget, GdkEventSelection *selection_event) {
2272 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2273 	//Platform::DebugPrintf("Selection clear\n");
2274 	sciThis->UnclaimSelection(selection_event);
2275 	return gtk_selection_clear(widget, selection_event);
2276 }
2277 
2278 #if GTK_MAJOR_VERSION < 2
SelectionNotify(GtkWidget * widget,GdkEventSelection * selection_event)2279 gint ScintillaGTK::SelectionNotify(GtkWidget *widget, GdkEventSelection *selection_event) {
2280 	//Platform::DebugPrintf("Selection notify\n");
2281 	return gtk_selection_notify(widget, selection_event);
2282 }
2283 #endif
2284 
DragBegin(GtkWidget *,GdkDragContext *)2285 void ScintillaGTK::DragBegin(GtkWidget *, GdkDragContext *) {
2286 	//Platform::DebugPrintf("DragBegin\n");
2287 }
2288 
DragMotion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint dragtime)2289 gboolean ScintillaGTK::DragMotion(GtkWidget *widget, GdkDragContext *context,
2290                                   gint x, gint y, guint dragtime) {
2291 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2292 	//Platform::DebugPrintf("DragMotion %d %d %x %x %x\n", x, y,
2293 	//	context->actions, context->suggested_action, sciThis);
2294 	Point npt(x, y);
2295 	sciThis->inDragDrop = true;
2296 	sciThis->SetDragPosition(sciThis->PositionFromLocation(npt));
2297 	gdk_drag_status(context, context->suggested_action, dragtime);
2298 	return FALSE;
2299 }
2300 
DragLeave(GtkWidget * widget,GdkDragContext *,guint)2301 void ScintillaGTK::DragLeave(GtkWidget *widget, GdkDragContext * /*context*/, guint) {
2302 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2303 	sciThis->SetDragPosition(invalidPosition);
2304 	//Platform::DebugPrintf("DragLeave %x\n", sciThis);
2305 }
2306 
DragEnd(GtkWidget * widget,GdkDragContext *)2307 void ScintillaGTK::DragEnd(GtkWidget *widget, GdkDragContext * /*context*/) {
2308 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2309 	// If drag did not result in drop here or elsewhere
2310 	if (!sciThis->dragWasDropped)
2311 		sciThis->SetEmptySelection(sciThis->posDrag);
2312 	sciThis->SetDragPosition(invalidPosition);
2313 	//Platform::DebugPrintf("DragEnd %x %d\n", sciThis, sciThis->dragWasDropped);
2314 }
2315 
Drop(GtkWidget * widget,GdkDragContext *,gint,gint,guint)2316 gboolean ScintillaGTK::Drop(GtkWidget *widget, GdkDragContext * /*context*/,
2317                             gint, gint, guint) {
2318 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2319 	//Platform::DebugPrintf("Drop %x\n", sciThis);
2320 	sciThis->SetDragPosition(invalidPosition);
2321 	return FALSE;
2322 }
2323 
DragDataReceived(GtkWidget * widget,GdkDragContext *,gint,gint,GtkSelectionData * selection_data,guint,guint)2324 void ScintillaGTK::DragDataReceived(GtkWidget *widget, GdkDragContext * /*context*/,
2325                                     gint, gint, GtkSelectionData *selection_data, guint /*info*/, guint) {
2326 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2327 	sciThis->ReceivedDrop(selection_data);
2328 	sciThis->SetDragPosition(invalidPosition);
2329 }
2330 
DragDataGet(GtkWidget * widget,GdkDragContext * context,GtkSelectionData * selection_data,guint info,guint)2331 void ScintillaGTK::DragDataGet(GtkWidget *widget, GdkDragContext *context,
2332                                GtkSelectionData *selection_data, guint info, guint) {
2333 	ScintillaGTK *sciThis = ScintillaFromWidget(widget);
2334 	sciThis->dragWasDropped = true;
2335 	if (sciThis->currentPos != sciThis->anchor) {
2336 		sciThis->GetSelection(selection_data, info, &sciThis->drag);
2337 	}
2338 	if (context->action == GDK_ACTION_MOVE) {
2339 		int selStart = sciThis->SelectionStart();
2340 		int selEnd = sciThis->SelectionEnd();
2341 		if (sciThis->posDrop > selStart) {
2342 			if (sciThis->posDrop > selEnd)
2343 				sciThis->posDrop = sciThis->posDrop - (selEnd - selStart);
2344 			else
2345 				sciThis->posDrop = selStart;
2346 			sciThis->posDrop = sciThis->pdoc->ClampPositionIntoDocument(sciThis->posDrop);
2347 		}
2348 		sciThis->ClearSelection();
2349 	}
2350 	sciThis->SetDragPosition(invalidPosition);
2351 }
2352 
TimeOut(ScintillaGTK * sciThis)2353 int ScintillaGTK::TimeOut(ScintillaGTK *sciThis) {
2354 	sciThis->Tick();
2355 	return 1;
2356 }
2357 
IdleCallback(ScintillaGTK * sciThis)2358 int ScintillaGTK::IdleCallback(ScintillaGTK *sciThis) {
2359 	// Idler will be automatically stoped, if there is nothing
2360 	// to do while idle.
2361 	bool ret = sciThis->Idle();
2362 	if (ret == false) {
2363 		// FIXME: This will remove the idler from GTK, we don't want to
2364 		// remove it as it is removed automatically when this function
2365 		// returns false (although, it should be harmless).
2366 		sciThis->SetIdle(false);
2367 	}
2368 	return ret;
2369 }
2370 
PopUpCB(ScintillaGTK * sciThis,guint action,GtkWidget *)2371 void ScintillaGTK::PopUpCB(ScintillaGTK *sciThis, guint action, GtkWidget *) {
2372 	if (action) {
2373 		sciThis->Command(action);
2374 	}
2375 }
2376 
PressCT(GtkWidget * widget,GdkEventButton * event,ScintillaGTK * sciThis)2377 gint ScintillaGTK::PressCT(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis) {
2378 	if (event->window != widget->window)
2379 		return FALSE;
2380 	if (event->type != GDK_BUTTON_PRESS)
2381 		return FALSE;
2382 	Point pt;
2383 	pt.x = int(event->x);
2384 	pt.y = int(event->y);
2385 	sciThis->ct.MouseClick(pt);
2386 	sciThis->CallTipClick();
2387 #if GTK_MAJOR_VERSION >= 2
2388 	return TRUE;
2389 #else
2390 	return FALSE;
2391 #endif
2392 }
2393 
ExposeCT(GtkWidget * widget,GdkEventExpose *,CallTip * ctip)2394 gint ScintillaGTK::ExposeCT(GtkWidget *widget, GdkEventExpose * /*ose*/, CallTip *ctip) {
2395 	Surface *surfaceWindow = Surface::Allocate();
2396 	if (surfaceWindow) {
2397 		surfaceWindow->Init(widget->window, widget);
2398 		ctip->PaintCT(surfaceWindow);
2399 		surfaceWindow->Release();
2400 		delete surfaceWindow;
2401 	}
2402 	return TRUE;
2403 }
2404 
DirectFunction(ScintillaGTK * sciThis,unsigned int iMessage,uptr_t wParam,sptr_t lParam)2405 sptr_t ScintillaGTK::DirectFunction(
2406     ScintillaGTK *sciThis, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
2407 	return sciThis->WndProc(iMessage, wParam, lParam);
2408 }
2409 
scintilla_send_message(ScintillaObject * sci,unsigned int iMessage,uptr_t wParam,sptr_t lParam)2410 sptr_t scintilla_send_message(ScintillaObject *sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
2411 	ScintillaGTK *psci = reinterpret_cast<ScintillaGTK *>(sci->pscin);
2412 	return psci->WndProc(iMessage, wParam, lParam);
2413 }
2414 
2415 static void scintilla_class_init(ScintillaClass *klass);
2416 static void scintilla_init(ScintillaObject *sci);
2417 
2418 extern void Platform_Initialise();
2419 extern void Platform_Finalise();
2420 
scintilla_get_type()2421 GtkType scintilla_get_type() {
2422 	static GtkType scintilla_type = 0;
2423 
2424 	if (!scintilla_type) {
2425 		Platform_Initialise();
2426 		static GtkTypeInfo scintilla_info = {
2427 		    "Scintilla",
2428 		    sizeof (ScintillaObject),
2429 		    sizeof (ScintillaClass),
2430 		    (GtkClassInitFunc) scintilla_class_init,
2431 		    (GtkObjectInitFunc) scintilla_init,
2432 		    (gpointer) NULL,
2433 		    (gpointer) NULL,
2434 		    0
2435 		};
2436 
2437 		scintilla_type = gtk_type_unique(gtk_container_get_type(), &scintilla_info);
2438 	}
2439 
2440 	return scintilla_type;
2441 }
2442 
ClassInit(GtkObjectClass * object_class,GtkWidgetClass * widget_class,GtkContainerClass * container_class)2443 void ScintillaGTK::ClassInit(GtkObjectClass* object_class, GtkWidgetClass *widget_class, GtkContainerClass *container_class) {
2444     atomClipboard = gdk_atom_intern("CLIPBOARD", FALSE);
2445     atomUTF8 = gdk_atom_intern("UTF8_STRING", FALSE);
2446     atomString = GDK_SELECTION_TYPE_STRING;
2447 
2448 	// Define default signal handlers for the class:  Could move more
2449 	// of the signal handlers here (those that currently attached to wDraw
2450 	// in Initialise() may require coordinate translation?)
2451 
2452 	object_class->destroy = Destroy;
2453 
2454 	widget_class->size_request = SizeRequest;
2455 	widget_class->size_allocate = SizeAllocate;
2456 	widget_class->expose_event = ExposeMain;
2457 #if GTK_MAJOR_VERSION < 2
2458 	widget_class->draw = Draw;
2459 #endif
2460 
2461 	widget_class->motion_notify_event = Motion;
2462 	widget_class->button_press_event = Press;
2463 	widget_class->button_release_event = MouseRelease;
2464 #if PLAT_GTK_WIN32 || (GTK_MAJOR_VERSION >= 2)
2465 	widget_class->scroll_event = ScrollEvent;
2466 #endif
2467 	widget_class->key_press_event = KeyPress;
2468 	widget_class->key_release_event = KeyRelease;
2469 	widget_class->focus_in_event = FocusIn;
2470 	widget_class->focus_out_event = FocusOut;
2471 	widget_class->selection_received = SelectionReceived;
2472 	widget_class->selection_get = SelectionGet;
2473 	widget_class->selection_clear_event = SelectionClear;
2474 #if GTK_MAJOR_VERSION < 2
2475 	widget_class->selection_notify_event = SelectionNotify;
2476 #endif
2477 
2478 	widget_class->drag_data_received = DragDataReceived;
2479 	widget_class->drag_motion = DragMotion;
2480 	widget_class->drag_leave = DragLeave;
2481 	widget_class->drag_end = DragEnd;
2482 	widget_class->drag_drop = Drop;
2483 	widget_class->drag_data_get = DragDataGet;
2484 
2485 	widget_class->realize = Realize;
2486 	widget_class->unrealize = UnRealize;
2487 	widget_class->map = Map;
2488 	widget_class->unmap = UnMap;
2489 
2490 	container_class->forall = MainForAll;
2491 }
2492 
2493 #if GTK_MAJOR_VERSION < 2
2494 #define GTK_CLASS_TYPE(c) (c->type)
2495 #define SIG_MARSHAL gtk_marshal_NONE__INT_POINTER
2496 #else
2497 #define SIG_MARSHAL scintilla_marshal_NONE__INT_POINTER
2498 #endif
2499 #define MARSHAL_ARGUMENTS GTK_TYPE_INT, GTK_TYPE_POINTER
2500 
scintilla_class_init(ScintillaClass * klass)2501 static void scintilla_class_init(ScintillaClass *klass) {
2502 	GtkObjectClass *object_class = (GtkObjectClass*) klass;
2503 	GtkWidgetClass *widget_class = (GtkWidgetClass*) klass;
2504 	GtkContainerClass *container_class = (GtkContainerClass*) klass;
2505 
2506 	parent_class = (GtkWidgetClass*) gtk_type_class(gtk_container_get_type());
2507 
2508 	scintilla_signals[COMMAND_SIGNAL] = gtk_signal_new(
2509 	                                        "command",
2510 	                                        GTK_RUN_LAST,
2511 	                                        GTK_CLASS_TYPE(object_class),
2512 	                                        GTK_SIGNAL_OFFSET(ScintillaClass, command),
2513 	                                        SIG_MARSHAL,
2514 	                                        GTK_TYPE_NONE,
2515 	                                        2, MARSHAL_ARGUMENTS);
2516 
2517 	scintilla_signals[NOTIFY_SIGNAL] = gtk_signal_new(
2518 	                                       SCINTILLA_NOTIFY,
2519 	                                       GTK_RUN_LAST,
2520 	                                       GTK_CLASS_TYPE(object_class),
2521 	                                       GTK_SIGNAL_OFFSET(ScintillaClass, notify),
2522 	                                       SIG_MARSHAL,
2523 	                                       GTK_TYPE_NONE,
2524 	                                       2, MARSHAL_ARGUMENTS);
2525 #if GTK_MAJOR_VERSION < 2
2526 	gtk_object_class_add_signals(object_class,
2527 	                             reinterpret_cast<unsigned int *>(scintilla_signals), LAST_SIGNAL);
2528 #endif
2529 	klass->command = NULL;
2530 	klass->notify = NULL;
2531 
2532 	ScintillaGTK::ClassInit(object_class, widget_class, container_class);
2533 }
2534 
scintilla_init(ScintillaObject * sci)2535 static void scintilla_init(ScintillaObject *sci) {
2536 	GTK_WIDGET_SET_FLAGS(sci, GTK_CAN_FOCUS);
2537 	sci->pscin = new ScintillaGTK(sci);
2538 }
2539 
scintilla_new()2540 GtkWidget* scintilla_new() {
2541 	return GTK_WIDGET(gtk_type_new(scintilla_get_type()));
2542 }
2543 
scintilla_set_id(ScintillaObject * sci,int id)2544 void scintilla_set_id(ScintillaObject *sci, int id) {
2545 	ScintillaGTK *psci = reinterpret_cast<ScintillaGTK *>(sci->pscin);
2546 	psci->ctrlID = id;
2547 }
2548 
scintilla_release_resources(void)2549 void scintilla_release_resources(void) {
2550 	Platform_Finalise();
2551 }
2552