1 // Scintilla source code edit control
2 // ScintillaGTK.cxx - GTK+ specific subclass of ScintillaBase
3 // Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
4 // The License.txt file describes the conditions under which this software may be distributed.
17 #include <gdk/gdkkeysyms.h>
25 #include "Scintilla.h"
26 #include "ScintillaWidget.h"
30 #include "PropSetSimple.h"
35 #include "SplitVector.h"
36 #include "Partitioning.h"
37 #include "RunStyles.h"
38 #include "ContractionState.h"
39 #include "CellBuffer.h"
42 #include "Indicator.h"
44 #include "LineMarker.h"
46 #include "AutoComplete.h"
47 #include "ViewStyle.h"
48 #include "Decoration.h"
49 #include "CharClassify.h"
51 #include "Selection.h"
52 #include "PositionCache.h"
54 #include "ScintillaBase.h"
55 #include "UniConversion.h"
57 #include "gtk/gtksignal.h"
58 #include "gtk/gtkmarshal.h"
59 #if GLIB_MAJOR_VERSION >= 2
60 #include "scintilla-marshal.h"
66 #include "ExternalLexer.h"
69 #define INTERNATIONAL_INPUT
71 #if !PLAT_GTK_WIN32 || GTK_MAJOR_VERSION >= 2
76 #include "Converter.h"
80 // Constant conditional expressions are because of GTK+ headers
81 #pragma warning(disable: 4127)
82 // Ignore unreferenced local functions in GTK+ headers
83 #pragma warning(disable: 4505)
86 #if GTK_CHECK_VERSION(2,6,0)
87 #define USE_GTK_CLIPBOARD
90 #if GLIB_MAJOR_VERSION < 2
91 #define OBJECT_CLASS GtkObjectClass
93 #define OBJECT_CLASS GObjectClass
97 using namespace Scintilla
;
100 extern char *UTF8FromLatin1(const char *s
, int &len
);
102 class ScintillaGTK
: public ScintillaBase
{
103 _ScintillaObject
*sci
;
107 GtkObject
*adjustmentv
;
108 GtkObject
*adjustmenth
;
112 // Because clipboard access is asynchronous, copyText is created by Copy
113 #ifndef USE_GTK_CLIPBOARD
114 SelectionText copyText
;
117 SelectionText primary
;
119 GdkEventButton evbtn
;
123 int rectangularSelectionModifier
;
125 GtkWidgetClass
*parentClass
;
127 static GdkAtom atomClipboard
;
128 static GdkAtom atomUTF8
;
129 static GdkAtom atomString
;
130 static GdkAtom atomUriList
;
131 static GdkAtom atomDROPFILES_DND
;
135 CLIPFORMAT cfColumnSelect
;
138 #ifdef INTERNATIONAL_INPUT
139 #if GTK_MAJOR_VERSION < 2
140 // Input context used for supporting internationalized key entry
146 GtkIMContext
*im_context
;
150 // Wheel mouse support
151 unsigned int linesPerScroll
;
152 GTimeVal lastWheelMouseTime
;
153 gint lastWheelMouseDirection
;
154 gint wheelMouseIntensity
;
156 GdkRegion
*rgnUpdate
;
158 // Private so ScintillaGTK objects can not be copied
159 ScintillaGTK(const ScintillaGTK
&);
160 ScintillaGTK
&operator=(const ScintillaGTK
&);
163 ScintillaGTK(_ScintillaObject
*sci_
);
164 virtual ~ScintillaGTK();
165 static void ClassInit(OBJECT_CLASS
* object_class
, GtkWidgetClass
*widget_class
, GtkContainerClass
*container_class
);
167 virtual void Initialise();
168 virtual void Finalise();
169 virtual void DisplayCursor(Window::Cursor c
);
170 virtual bool DragThreshold(Point ptStart
, Point ptNow
);
171 virtual void StartDrag();
172 int TargetAsUTF8(char *text
);
173 int EncodedFromUTF8(char *utf8
, char *encoded
);
174 virtual bool ValidCodePage(int codePage
) const;
175 public: // Public for scintilla_send_message
176 virtual sptr_t
WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
178 virtual sptr_t
DefWndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
179 virtual void SetTicking(bool on
);
180 virtual bool SetIdle(bool on
);
181 virtual void SetMouseCapture(bool on
);
182 virtual bool HaveMouseCapture();
183 virtual bool PaintContains(PRectangle rc
);
185 virtual PRectangle
GetClientRectangle();
186 void SyncPaint(PRectangle rc
);
187 virtual void ScrollText(int linesToMove
);
188 virtual void SetVerticalScrollPos();
189 virtual void SetHorizontalScrollPos();
190 virtual bool ModifyScrollBars(int nMax
, int nPage
);
191 void ReconfigureScrollBars();
192 virtual void NotifyChange();
193 virtual void NotifyFocus(bool focus
);
194 virtual void NotifyParent(SCNotification scn
);
195 void NotifyKey(int key
, int modifiers
);
196 void NotifyURIDropped(const char *list
);
197 const char *CharacterSetID() const;
198 virtual int KeyDefault(int key
, int modifiers
);
199 virtual void CopyToClipboard(const SelectionText
&selectedText
);
201 virtual void Paste();
202 virtual void CreateCallTipWindow(PRectangle rc
);
203 virtual void AddToPopUp(const char *label
, int cmd
= 0, bool enabled
= true);
204 bool OwnPrimarySelection();
205 virtual void ClaimSelection();
206 void GetGtkSelectionText(GtkSelectionData
*selectionData
, SelectionText
&selText
);
207 void ReceivedSelection(GtkSelectionData
*selection_data
);
208 void ReceivedDrop(GtkSelectionData
*selection_data
);
209 static void GetSelection(GtkSelectionData
*selection_data
, guint info
, SelectionText
*selected
);
210 #ifdef USE_GTK_CLIPBOARD
211 void StoreOnClipboard(SelectionText
*clipText
);
212 static void ClipboardGetSelection(GtkClipboard
* clip
, GtkSelectionData
*selection_data
, guint info
, void *data
);
213 static void ClipboardClearSelection(GtkClipboard
* clip
, void *data
);
216 void UnclaimSelection(GdkEventSelection
*selection_event
);
217 void Resize(int width
, int height
);
219 // Callback functions
220 void RealizeThis(GtkWidget
*widget
);
221 static void Realize(GtkWidget
*widget
);
222 void UnRealizeThis(GtkWidget
*widget
);
223 static void UnRealize(GtkWidget
*widget
);
225 static void Map(GtkWidget
*widget
);
227 static void UnMap(GtkWidget
*widget
);
228 static gint
CursorMoved(GtkWidget
*widget
, int xoffset
, int yoffset
, ScintillaGTK
*sciThis
);
229 gint
FocusInThis(GtkWidget
*widget
);
230 static gint
FocusIn(GtkWidget
*widget
, GdkEventFocus
*event
);
231 gint
FocusOutThis(GtkWidget
*widget
);
232 static gint
FocusOut(GtkWidget
*widget
, GdkEventFocus
*event
);
233 static void SizeRequest(GtkWidget
*widget
, GtkRequisition
*requisition
);
234 static void SizeAllocate(GtkWidget
*widget
, GtkAllocation
*allocation
);
235 gint
Expose(GtkWidget
*widget
, GdkEventExpose
*ose
);
236 static gint
ExposeMain(GtkWidget
*widget
, GdkEventExpose
*ose
);
237 static void Draw(GtkWidget
*widget
, GdkRectangle
*area
);
238 void ForAll(GtkCallback callback
, gpointer callback_data
);
239 static void MainForAll(GtkContainer
*container
, gboolean include_internals
, GtkCallback callback
, gpointer callback_data
);
241 static void ScrollSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
);
242 static void ScrollHSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
);
243 gint
PressThis(GdkEventButton
*event
);
244 static gint
Press(GtkWidget
*widget
, GdkEventButton
*event
);
245 static gint
MouseRelease(GtkWidget
*widget
, GdkEventButton
*event
);
246 #if PLAT_GTK_WIN32 || (GTK_MAJOR_VERSION >= 2)
247 static gint
ScrollEvent(GtkWidget
*widget
, GdkEventScroll
*event
);
249 static gint
Motion(GtkWidget
*widget
, GdkEventMotion
*event
);
250 gboolean
KeyThis(GdkEventKey
*event
);
251 static gboolean
KeyPress(GtkWidget
*widget
, GdkEventKey
*event
);
252 static gboolean
KeyRelease(GtkWidget
*widget
, GdkEventKey
*event
);
253 #if GTK_MAJOR_VERSION >= 2
254 gboolean
ExposePreeditThis(GtkWidget
*widget
, GdkEventExpose
*ose
);
255 static gboolean
ExposePreedit(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
);
256 void CommitThis(char *str
);
257 static void Commit(GtkIMContext
*context
, char *str
, ScintillaGTK
*sciThis
);
258 void PreeditChangedThis();
259 static void PreeditChanged(GtkIMContext
*context
, ScintillaGTK
*sciThis
);
261 static gint
StyleSetText(GtkWidget
*widget
, GtkStyle
*previous
, void*);
262 static gint
RealizeText(GtkWidget
*widget
, void*);
263 #if GLIB_MAJOR_VERSION < 2
264 static void Destroy(GtkObject
*object
);
266 static void Destroy(GObject
*object
);
268 static void SelectionReceived(GtkWidget
*widget
, GtkSelectionData
*selection_data
,
270 static void SelectionGet(GtkWidget
*widget
, GtkSelectionData
*selection_data
,
271 guint info
, guint time
);
272 static gint
SelectionClear(GtkWidget
*widget
, GdkEventSelection
*selection_event
);
273 #if GTK_MAJOR_VERSION < 2
274 static gint
SelectionNotify(GtkWidget
*widget
, GdkEventSelection
*selection_event
);
276 static void DragBegin(GtkWidget
*widget
, GdkDragContext
*context
);
277 gboolean
DragMotionThis(GdkDragContext
*context
, gint x
, gint y
, guint dragtime
);
278 static gboolean
DragMotion(GtkWidget
*widget
, GdkDragContext
*context
,
279 gint x
, gint y
, guint dragtime
);
280 static void DragLeave(GtkWidget
*widget
, GdkDragContext
*context
,
282 static void DragEnd(GtkWidget
*widget
, GdkDragContext
*context
);
283 static gboolean
Drop(GtkWidget
*widget
, GdkDragContext
*context
,
284 gint x
, gint y
, guint time
);
285 static void DragDataReceived(GtkWidget
*widget
, GdkDragContext
*context
,
286 gint x
, gint y
, GtkSelectionData
*selection_data
, guint info
, guint time
);
287 static void DragDataGet(GtkWidget
*widget
, GdkDragContext
*context
,
288 GtkSelectionData
*selection_data
, guint info
, guint time
);
289 static gint
TimeOut(ScintillaGTK
*sciThis
);
290 static gint
IdleCallback(ScintillaGTK
*sciThis
);
291 static void PopUpCB(ScintillaGTK
*sciThis
, guint action
, GtkWidget
*widget
);
293 gint
ExposeTextThis(GtkWidget
*widget
, GdkEventExpose
*ose
);
294 static gint
ExposeText(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
);
296 static gint
ExposeCT(GtkWidget
*widget
, GdkEventExpose
*ose
, CallTip
*ct
);
297 static gint
PressCT(GtkWidget
*widget
, GdkEventButton
*event
, ScintillaGTK
*sciThis
);
299 static sptr_t
DirectFunction(ScintillaGTK
*sciThis
,
300 unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
);
309 static gint scintilla_signals
[LAST_SIGNAL
] = { 0 };
310 #if GLIB_MAJOR_VERSION < 2
311 static GtkWidgetClass
*parent_class
= NULL
;
317 TARGET_COMPOUND_TEXT
,
322 GdkAtom
ScintillaGTK::atomClipboard
= 0;
323 GdkAtom
ScintillaGTK::atomUTF8
= 0;
324 GdkAtom
ScintillaGTK::atomString
= 0;
325 GdkAtom
ScintillaGTK::atomUriList
= 0;
326 GdkAtom
ScintillaGTK::atomDROPFILES_DND
= 0;
328 static const GtkTargetEntry clipboardCopyTargets
[] = {
329 { (gchar
*) "UTF8_STRING", 0, TARGET_UTF8_STRING
},
330 { (gchar
*) "STRING", 0, TARGET_STRING
},
332 static const gint nClipboardCopyTargets
= sizeof(clipboardCopyTargets
) / sizeof(clipboardCopyTargets
[0]);
334 static const GtkTargetEntry clipboardPasteTargets
[] = {
335 { (gchar
*) "text/uri-list", 0, TARGET_URI
},
336 { (gchar
*) "UTF8_STRING", 0, TARGET_UTF8_STRING
},
337 { (gchar
*) "STRING", 0, TARGET_STRING
},
339 static const gint nClipboardPasteTargets
= sizeof(clipboardPasteTargets
) / sizeof(clipboardPasteTargets
[0]);
341 static GtkWidget
*PWidget(Window
&w
) {
342 return reinterpret_cast<GtkWidget
*>(w
.GetID());
345 static ScintillaGTK
*ScintillaFromWidget(GtkWidget
*widget
) {
346 ScintillaObject
*scio
= reinterpret_cast<ScintillaObject
*>(widget
);
347 return reinterpret_cast<ScintillaGTK
*>(scio
->pscin
);
350 ScintillaGTK::ScintillaGTK(_ScintillaObject
*sci_
) :
351 adjustmentv(0), adjustmenth(0),
352 scrollBarWidth(30), scrollBarHeight(30),
353 capturedMouse(false), dragWasDropped(false),
354 lastKey(0), rectangularSelectionModifier(SCMOD_CTRL
), parentClass(0),
355 #ifdef INTERNATIONAL_INPUT
356 #if GTK_MAJOR_VERSION < 2
363 lastWheelMouseDirection(0),
364 wheelMouseIntensity(0),
367 wMain
= GTK_WIDGET(sci
);
370 rectangularSelectionModifier
= SCMOD_ALT
;
372 rectangularSelectionModifier
= SCMOD_CTRL
;
376 // There does not seem to be a real standard for indicating that the clipboard
377 // contains a rectangular selection, so copy Developer Studio.
378 cfColumnSelect
= static_cast<CLIPFORMAT
>(
379 ::RegisterClipboardFormat("MSDEVColumnSelect"));
381 // Get intellimouse parameters when running on win32; otherwise use
382 // reasonable default
383 #ifndef SPI_GETWHEELSCROLLLINES
384 #define SPI_GETWHEELSCROLLLINES 104
386 ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &linesPerScroll
, 0);
390 lastWheelMouseTime
.tv_sec
= 0;
391 lastWheelMouseTime
.tv_usec
= 0;
396 ScintillaGTK::~ScintillaGTK() {
399 void ScintillaGTK::RealizeThis(GtkWidget
*widget
) {
400 //Platform::DebugPrintf("ScintillaGTK::realize this\n");
401 GTK_WIDGET_SET_FLAGS(widget
, GTK_REALIZED
);
403 attrs
.window_type
= GDK_WINDOW_CHILD
;
404 attrs
.x
= widget
->allocation
.x
;
405 attrs
.y
= widget
->allocation
.y
;
406 attrs
.width
= widget
->allocation
.width
;
407 attrs
.height
= widget
->allocation
.height
;
408 attrs
.wclass
= GDK_INPUT_OUTPUT
;
409 attrs
.visual
= gtk_widget_get_visual(widget
);
410 attrs
.colormap
= gtk_widget_get_colormap(widget
);
411 attrs
.event_mask
= gtk_widget_get_events(widget
) | GDK_EXPOSURE_MASK
;
412 GdkCursor
*cursor
= gdk_cursor_new(GDK_XTERM
);
413 attrs
.cursor
= cursor
;
414 widget
->window
= gdk_window_new(gtk_widget_get_parent_window(widget
), &attrs
,
415 GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
| GDK_WA_COLORMAP
| GDK_WA_CURSOR
);
416 gdk_window_set_user_data(widget
->window
, widget
);
417 gdk_window_set_background(widget
->window
, &widget
->style
->bg
[GTK_STATE_NORMAL
]);
418 gdk_window_show(widget
->window
);
419 gdk_cursor_destroy(cursor
);
420 widget
->style
= gtk_style_attach(widget
->style
, widget
->window
);
421 #ifdef INTERNATIONAL_INPUT
422 #if GTK_MAJOR_VERSION < 2
423 if (gdk_im_ready() && (ic_attr
= gdk_ic_attr_new()) != NULL
) {
425 GdkColormap
*colormap
;
427 GdkICAttr
*attr
= ic_attr
;
428 GdkICAttributesType attrmask
= GDK_IC_ALL_REQ
;
430 GdkIMStyle supported_style
= (GdkIMStyle
) (GDK_IM_PREEDIT_NONE
|
431 GDK_IM_PREEDIT_NOTHING
|
432 GDK_IM_PREEDIT_POSITION
|
434 GDK_IM_STATUS_NOTHING
);
436 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
437 supported_style
= (GdkIMStyle
) ((int) supported_style
& ~GDK_IM_PREEDIT_POSITION
);
439 attr
->style
= style
= gdk_im_decide_style(supported_style
);
440 attr
->client_window
= widget
->window
;
442 if ((colormap
= gtk_widget_get_colormap (widget
)) != gtk_widget_get_default_colormap ()) {
443 attrmask
= (GdkICAttributesType
) ((int) attrmask
| GDK_IC_PREEDIT_COLORMAP
);
444 attr
->preedit_colormap
= colormap
;
447 switch (style
& GDK_IM_PREEDIT_MASK
) {
448 case GDK_IM_PREEDIT_POSITION
:
449 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
) {
450 g_warning("over-the-spot style requires fontset");
454 attrmask
= (GdkICAttributesType
) ((int) attrmask
| GDK_IC_PREEDIT_POSITION_REQ
);
455 gdk_window_get_size(widget
->window
, &width
, &height
);
456 attr
->spot_location
.x
= 0;
457 attr
->spot_location
.y
= height
;
458 attr
->preedit_area
.x
= 0;
459 attr
->preedit_area
.y
= 0;
460 attr
->preedit_area
.width
= width
;
461 attr
->preedit_area
.height
= height
;
462 attr
->preedit_fontset
= widget
->style
->font
;
466 ic
= gdk_ic_new(attr
, attrmask
);
469 g_warning("Can't create input context.");
471 mask
= gdk_window_get_events(widget
->window
);
472 mask
= (GdkEventMask
) ((int) mask
| gdk_ic_get_events(ic
));
473 gdk_window_set_events(widget
->window
, mask
);
475 if (GTK_WIDGET_HAS_FOCUS(widget
))
476 gdk_im_begin(ic
, widget
->window
);
480 wPreedit
= gtk_window_new(GTK_WINDOW_POPUP
);
481 wPreeditDraw
= gtk_drawing_area_new();
482 GtkWidget
*predrw
= PWidget(wPreeditDraw
); // No code inside the G_OBJECT macro
483 g_signal_connect(G_OBJECT(predrw
), "expose_event",
484 G_CALLBACK(ExposePreedit
), this);
485 gtk_container_add(GTK_CONTAINER(PWidget(wPreedit
)), predrw
);
486 gtk_widget_realize(PWidget(wPreedit
));
487 gtk_widget_realize(predrw
);
488 gtk_widget_show(predrw
);
490 im_context
= gtk_im_multicontext_new();
491 g_signal_connect(G_OBJECT(im_context
), "commit",
492 G_CALLBACK(Commit
), this);
493 g_signal_connect(G_OBJECT(im_context
), "preedit_changed",
494 G_CALLBACK(PreeditChanged
), this);
495 gtk_im_context_set_client_window(im_context
, widget
->window
);
498 GtkWidget
*widtxt
= PWidget(wText
); // // No code inside the G_OBJECT macro
499 #if GLIB_MAJOR_VERSION < 2
500 gtk_signal_connect_after(GTK_OBJECT(widtxt
), "style_set",
501 GtkSignalFunc(ScintillaGTK::StyleSetText
), NULL
);
502 gtk_signal_connect_after(GTK_OBJECT(widtxt
), "realize",
503 GtkSignalFunc(ScintillaGTK::RealizeText
), NULL
);
505 g_signal_connect_after(G_OBJECT(widtxt
), "style_set",
506 G_CALLBACK(ScintillaGTK::StyleSetText
), NULL
);
507 g_signal_connect_after(G_OBJECT(widtxt
), "realize",
508 G_CALLBACK(ScintillaGTK::RealizeText
), NULL
);
510 gtk_widget_realize(widtxt
);
511 gtk_widget_realize(PWidget(scrollbarv
));
512 gtk_widget_realize(PWidget(scrollbarh
));
515 void ScintillaGTK::Realize(GtkWidget
*widget
) {
516 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
517 sciThis
->RealizeThis(widget
);
520 void ScintillaGTK::UnRealizeThis(GtkWidget
*widget
) {
522 if (GTK_WIDGET_MAPPED(widget
)) {
523 gtk_widget_unmap(widget
);
525 GTK_WIDGET_UNSET_FLAGS(widget
, GTK_REALIZED
);
526 gtk_widget_unrealize(PWidget(wText
));
527 gtk_widget_unrealize(PWidget(scrollbarv
));
528 gtk_widget_unrealize(PWidget(scrollbarh
));
529 #ifdef INTERNATIONAL_INPUT
530 #if GTK_MAJOR_VERSION < 2
536 gdk_ic_attr_destroy(ic_attr
);
540 gtk_widget_unrealize(PWidget(wPreedit
));
541 gtk_widget_unrealize(PWidget(wPreeditDraw
));
542 g_object_unref(im_context
);
546 if (GTK_WIDGET_CLASS(parentClass
)->unrealize
)
547 GTK_WIDGET_CLASS(parentClass
)->unrealize(widget
);
551 errorStatus
= SC_STATUS_FAILURE
;
555 void ScintillaGTK::UnRealize(GtkWidget
*widget
) {
556 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
557 sciThis
->UnRealizeThis(widget
);
560 static void MapWidget(GtkWidget
*widget
) {
562 GTK_WIDGET_VISIBLE(widget
) &&
563 !GTK_WIDGET_MAPPED(widget
)) {
564 gtk_widget_map(widget
);
568 void ScintillaGTK::MapThis() {
570 //Platform::DebugPrintf("ScintillaGTK::map this\n");
571 GTK_WIDGET_SET_FLAGS(PWidget(wMain
), GTK_MAPPED
);
572 MapWidget(PWidget(wText
));
573 MapWidget(PWidget(scrollbarh
));
574 MapWidget(PWidget(scrollbarv
));
575 wMain
.SetCursor(Window::cursorArrow
);
576 scrollbarv
.SetCursor(Window::cursorArrow
);
577 scrollbarh
.SetCursor(Window::cursorArrow
);
579 gdk_window_show(PWidget(wMain
)->window
);
581 errorStatus
= SC_STATUS_FAILURE
;
585 void ScintillaGTK::Map(GtkWidget
*widget
) {
586 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
590 void ScintillaGTK::UnMapThis() {
592 //Platform::DebugPrintf("ScintillaGTK::unmap this\n");
593 GTK_WIDGET_UNSET_FLAGS(PWidget(wMain
), GTK_MAPPED
);
595 gdk_window_hide(PWidget(wMain
)->window
);
596 gtk_widget_unmap(PWidget(wText
));
597 gtk_widget_unmap(PWidget(scrollbarh
));
598 gtk_widget_unmap(PWidget(scrollbarv
));
600 errorStatus
= SC_STATUS_FAILURE
;
604 void ScintillaGTK::UnMap(GtkWidget
*widget
) {
605 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
606 sciThis
->UnMapThis();
609 void ScintillaGTK::ForAll(GtkCallback callback
, gpointer callback_data
) {
611 (*callback
) (PWidget(wText
), callback_data
);
612 (*callback
) (PWidget(scrollbarv
), callback_data
);
613 (*callback
) (PWidget(scrollbarh
), callback_data
);
615 errorStatus
= SC_STATUS_FAILURE
;
619 void ScintillaGTK::MainForAll(GtkContainer
*container
, gboolean include_internals
, GtkCallback callback
, gpointer callback_data
) {
620 ScintillaGTK
*sciThis
= ScintillaFromWidget((GtkWidget
*)container
);
622 if (callback
!= NULL
&& include_internals
) {
623 sciThis
->ForAll(callback
, callback_data
);
627 #ifdef INTERNATIONAL_INPUT
628 #if GTK_MAJOR_VERSION < 2
629 gint
ScintillaGTK::CursorMoved(GtkWidget
*widget
, int xoffset
, int yoffset
, ScintillaGTK
*sciThis
) {
630 if (GTK_WIDGET_HAS_FOCUS(widget
) && gdk_im_ready() && sciThis
->ic
&&
631 (gdk_ic_get_style(sciThis
->ic
) & GDK_IM_PREEDIT_POSITION
)) {
632 sciThis
->ic_attr
->spot_location
.x
= xoffset
;
633 sciThis
->ic_attr
->spot_location
.y
= yoffset
;
634 gdk_ic_set_attr(sciThis
->ic
, sciThis
->ic_attr
, GDK_IC_SPOT_LOCATION
);
639 gint
ScintillaGTK::CursorMoved(GtkWidget
*, int xoffset
, int yoffset
, ScintillaGTK
*sciThis
) {
645 gtk_im_context_set_cursor_location(sciThis
->im_context
, &area
);
650 gint
ScintillaGTK::CursorMoved(GtkWidget
*, int, int, ScintillaGTK
*) {
655 gint
ScintillaGTK::FocusInThis(GtkWidget
*widget
) {
657 GTK_WIDGET_SET_FLAGS(widget
, GTK_HAS_FOCUS
);
659 #ifdef INTERNATIONAL_INPUT
660 #if GTK_MAJOR_VERSION < 2
662 gdk_im_begin(ic
, widget
->window
);
664 if (im_context
!= NULL
) {
668 gtk_im_context_get_preedit_string(im_context
, &str
, NULL
, &cursor_pos
);
669 if (PWidget(wPreedit
) != NULL
) {
670 if (strlen(str
) > 0) {
671 gtk_widget_show(PWidget(wPreedit
));
673 gtk_widget_hide(PWidget(wPreedit
));
677 gtk_im_context_focus_in(im_context
);
683 errorStatus
= SC_STATUS_FAILURE
;
688 gint
ScintillaGTK::FocusIn(GtkWidget
*widget
, GdkEventFocus
* /*event*/) {
689 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
690 return sciThis
->FocusInThis(widget
);
693 gint
ScintillaGTK::FocusOutThis(GtkWidget
*widget
) {
695 GTK_WIDGET_UNSET_FLAGS(widget
, GTK_HAS_FOCUS
);
696 SetFocusState(false);
698 #ifdef INTERNATIONAL_INPUT
699 #if GTK_MAJOR_VERSION < 2
702 if (PWidget(wPreedit
) != NULL
)
703 gtk_widget_hide(PWidget(wPreedit
));
704 if (im_context
!= NULL
)
705 gtk_im_context_focus_out(im_context
);
710 errorStatus
= SC_STATUS_FAILURE
;
715 gint
ScintillaGTK::FocusOut(GtkWidget
*widget
, GdkEventFocus
* /*event*/) {
716 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
717 return sciThis
->FocusOutThis(widget
);
720 void ScintillaGTK::SizeRequest(GtkWidget
*widget
, GtkRequisition
*requisition
) {
721 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
722 requisition
->width
= 600;
723 requisition
->height
= gdk_screen_height();
724 GtkRequisition child_requisition
;
725 gtk_widget_size_request(PWidget(sciThis
->scrollbarh
), &child_requisition
);
726 gtk_widget_size_request(PWidget(sciThis
->scrollbarv
), &child_requisition
);
729 void ScintillaGTK::SizeAllocate(GtkWidget
*widget
, GtkAllocation
*allocation
) {
730 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
732 widget
->allocation
= *allocation
;
733 if (GTK_WIDGET_REALIZED(widget
))
734 gdk_window_move_resize(widget
->window
,
735 widget
->allocation
.x
,
736 widget
->allocation
.y
,
737 widget
->allocation
.width
,
738 widget
->allocation
.height
);
740 sciThis
->Resize(allocation
->width
, allocation
->height
);
742 #ifdef INTERNATIONAL_INPUT
743 #if GTK_MAJOR_VERSION < 2
744 if (sciThis
->ic
&& (gdk_ic_get_style(sciThis
->ic
) & GDK_IM_PREEDIT_POSITION
)) {
747 gdk_window_get_size(widget
->window
, &width
, &height
);
748 sciThis
->ic_attr
->preedit_area
.width
= width
;
749 sciThis
->ic_attr
->preedit_area
.height
= height
;
751 gdk_ic_set_attr(sciThis
->ic
, sciThis
->ic_attr
, GDK_IC_PREEDIT_AREA
);
756 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
760 void ScintillaGTK::Initialise() {
761 //Platform::DebugPrintf("ScintillaGTK::Initialise\n");
762 parentClass
= reinterpret_cast<GtkWidgetClass
*>(
763 gtk_type_class(gtk_container_get_type()));
765 GTK_WIDGET_SET_FLAGS(PWidget(wMain
), GTK_CAN_FOCUS
);
766 GTK_WIDGET_SET_FLAGS(GTK_WIDGET(PWidget(wMain
)), GTK_SENSITIVE
);
767 gtk_widget_set_events(PWidget(wMain
),
771 | GDK_KEY_RELEASE_MASK
772 | GDK_FOCUS_CHANGE_MASK
773 | GDK_LEAVE_NOTIFY_MASK
774 | GDK_BUTTON_PRESS_MASK
775 | GDK_BUTTON_RELEASE_MASK
776 | GDK_POINTER_MOTION_MASK
777 | GDK_POINTER_MOTION_HINT_MASK
);
779 wText
= gtk_drawing_area_new();
780 gtk_widget_set_parent(PWidget(wText
), PWidget(wMain
));
781 GtkWidget
*widtxt
= PWidget(wText
); // No code inside the G_OBJECT macro
782 gtk_widget_show(widtxt
);
783 #if GLIB_MAJOR_VERSION < 2
784 gtk_signal_connect(GTK_OBJECT(widtxt
), "expose_event",
785 GtkSignalFunc(ScintillaGTK::ExposeText
), this);
787 g_signal_connect(G_OBJECT(widtxt
), "expose_event",
788 G_CALLBACK(ScintillaGTK::ExposeText
), this);
790 gtk_widget_set_events(widtxt
, GDK_EXPOSURE_MASK
);
791 #if GTK_MAJOR_VERSION >= 2
792 // Avoid background drawing flash
793 gtk_widget_set_double_buffered(widtxt
, FALSE
);
795 gtk_drawing_area_size(GTK_DRAWING_AREA(widtxt
),
797 adjustmentv
= gtk_adjustment_new(0.0, 0.0, 201.0, 1.0, 20.0, 20.0);
798 scrollbarv
= gtk_vscrollbar_new(GTK_ADJUSTMENT(adjustmentv
));
799 GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarv
), GTK_CAN_FOCUS
);
800 #if GLIB_MAJOR_VERSION < 2
801 gtk_signal_connect(adjustmentv
, "value_changed",
802 GtkSignalFunc(ScrollSignal
), this);
804 g_signal_connect(G_OBJECT(adjustmentv
), "value_changed",
805 G_CALLBACK(ScrollSignal
), this);
807 gtk_widget_set_parent(PWidget(scrollbarv
), PWidget(wMain
));
808 gtk_widget_show(PWidget(scrollbarv
));
810 adjustmenth
= gtk_adjustment_new(0.0, 0.0, 101.0, 1.0, 20.0, 20.0);
811 scrollbarh
= gtk_hscrollbar_new(GTK_ADJUSTMENT(adjustmenth
));
812 GTK_WIDGET_UNSET_FLAGS(PWidget(scrollbarh
), GTK_CAN_FOCUS
);
813 #if GLIB_MAJOR_VERSION < 2
814 gtk_signal_connect(adjustmenth
, "value_changed",
815 GtkSignalFunc(ScrollHSignal
), this);
817 g_signal_connect(G_OBJECT(adjustmenth
), "value_changed",
818 G_CALLBACK(ScrollHSignal
), this);
820 gtk_widget_set_parent(PWidget(scrollbarh
), PWidget(wMain
));
821 gtk_widget_show(PWidget(scrollbarh
));
823 gtk_widget_grab_focus(PWidget(wMain
));
825 gtk_selection_add_targets(GTK_WIDGET(PWidget(wMain
)), GDK_SELECTION_PRIMARY
,
826 clipboardCopyTargets
, nClipboardCopyTargets
);
828 #ifndef USE_GTK_CLIPBOARD
829 gtk_selection_add_targets(GTK_WIDGET(PWidget(wMain
)), atomClipboard
,
830 clipboardPasteTargets
, nClipboardPasteTargets
);
833 gtk_drag_dest_set(GTK_WIDGET(PWidget(wMain
)),
834 GTK_DEST_DEFAULT_ALL
, clipboardPasteTargets
, nClipboardPasteTargets
,
835 static_cast<GdkDragAction
>(GDK_ACTION_COPY
| GDK_ACTION_MOVE
));
837 #if GLIB_MAJOR_VERSION >= 2
838 // Set caret period based on GTK settings
839 gboolean blinkOn
= false;
840 if (g_object_class_find_property(G_OBJECT_GET_CLASS(
841 G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink")) {
842 g_object_get(G_OBJECT(
843 gtk_settings_get_default()), "gtk-cursor-blink", &blinkOn
, NULL
);
846 g_object_class_find_property(G_OBJECT_GET_CLASS(
847 G_OBJECT(gtk_settings_get_default())), "gtk-cursor-blink-time")) {
849 g_object_get(G_OBJECT(
850 gtk_settings_get_default()), "gtk-cursor-blink-time", &value
, NULL
);
851 caret
.period
= gint(value
/ 1.75);
860 void ScintillaGTK::Finalise() {
862 ScintillaBase::Finalise();
865 void ScintillaGTK::DisplayCursor(Window::Cursor c
) {
866 if (cursorMode
== SC_CURSORNORMAL
)
869 wText
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
872 bool ScintillaGTK::DragThreshold(Point ptStart
, Point ptNow
) {
873 #if GTK_MAJOR_VERSION < 2
874 return Editor::DragThreshold(ptStart
, ptNow
);
876 return gtk_drag_check_threshold(GTK_WIDGET(PWidget(wMain
)),
877 ptStart
.x
, ptStart
.y
, ptNow
.x
, ptNow
.y
);
881 void ScintillaGTK::StartDrag() {
882 dragWasDropped
= false;
883 inDragDrop
= ddDragging
;
884 GtkTargetList
*tl
= gtk_target_list_new(clipboardCopyTargets
, nClipboardCopyTargets
);
885 gtk_drag_begin(GTK_WIDGET(PWidget(wMain
)),
887 static_cast<GdkDragAction
>(GDK_ACTION_COPY
| GDK_ACTION_MOVE
),
889 reinterpret_cast<GdkEvent
*>(&evbtn
));
893 static char *ConvertText(int *lenResult
, char *s
, size_t len
, const char *charSetDest
,
894 const char *charSetSource
, bool transliterations
) {
897 Converter
conv(charSetDest
, charSetSource
, transliterations
);
899 destForm
= new char[len
*3+1];
902 char *pout
= destForm
;
903 size_t outLeft
= len
*3+1;
904 size_t conversions
= conv
.Convert(&pin
, &inLeft
, &pout
, &outLeft
);
905 if (conversions
== ((size_t)(-1))) {
906 fprintf(stderr
, "iconv %s->%s failed for %s\n", charSetSource
, charSetDest
, static_cast<char *>(s
));
910 //fprintf(stderr, "iconv OK %s %d\n", destForm, pout - destForm);
912 *lenResult
= pout
- destForm
;
915 fprintf(stderr
, "Can not iconv %s %s\n", charSetDest
, charSetSource
);
918 destForm
= new char[1];
926 // Returns the target converted to UTF8.
927 // Return the length in bytes.
928 int ScintillaGTK::TargetAsUTF8(char *text
) {
929 int targetLength
= targetEnd
- targetStart
;
930 if (IsUnicodeMode()) {
932 pdoc
->GetCharRange(text
, targetStart
, targetLength
);
937 const char *charSetBuffer
= CharacterSetID();
938 if (*charSetBuffer
) {
939 //~ fprintf(stderr, "AsUTF8 %s %d %0d-%0d\n", charSetBuffer, targetLength, targetStart, targetEnd);
940 char *s
= new char[targetLength
];
942 pdoc
->GetCharRange(s
, targetStart
, targetLength
);
943 //~ fprintf(stderr, " \"%s\"\n", s);
945 char *tmputf
= ConvertText(&targetLength
, s
, targetLength
, "UTF-8", charSetBuffer
, false);
946 memcpy(text
, tmputf
, targetLength
);
948 //~ fprintf(stderr, " \"%s\"\n", text);
954 pdoc
->GetCharRange(text
, targetStart
, targetLength
);
962 //~ fprintf(stderr, "Length = %d bytes\n", targetLength);
966 // Translates a nul terminated UTF8 string into the document encoding.
967 // Return the length of the result in bytes.
968 int ScintillaGTK::EncodedFromUTF8(char *utf8
, char *encoded
) {
969 int inputLength
= (lengthForEncode
>= 0) ? lengthForEncode
: strlen(utf8
);
970 if (IsUnicodeMode()) {
972 memcpy(encoded
, utf8
, inputLength
);
978 const char *charSetBuffer
= CharacterSetID();
979 if (*charSetBuffer
) {
980 //~ fprintf(stderr, "Encode %s %d\n", charSetBuffer, inputLength);
982 char *tmpEncoded
= ConvertText(&outLength
, utf8
, inputLength
, charSetBuffer
, "UTF-8", true);
984 //~ fprintf(stderr, " \"%s\"\n", tmpEncoded);
986 memcpy(encoded
, tmpEncoded
, outLength
);
993 memcpy(encoded
, utf8
, inputLength
);
1003 bool ScintillaGTK::ValidCodePage(int codePage
) const {
1004 return codePage
== 0
1005 || codePage
== SC_CP_UTF8
1009 || codePage
== SC_CP_DBCS
;
1012 sptr_t
ScintillaGTK::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
1017 gtk_widget_grab_focus(PWidget(wMain
));
1020 case SCI_GETDIRECTFUNCTION
:
1021 return reinterpret_cast<sptr_t
>(DirectFunction
);
1023 case SCI_GETDIRECTPOINTER
:
1024 return reinterpret_cast<sptr_t
>(this);
1027 case SCI_LOADLEXERLIBRARY
:
1028 LexerManager::GetInstance()->Load(reinterpret_cast<const char*>(wParam
));
1031 case SCI_TARGETASUTF8
:
1032 return TargetAsUTF8(reinterpret_cast<char*>(lParam
));
1034 case SCI_ENCODEDFROMUTF8
:
1035 return EncodedFromUTF8(reinterpret_cast<char*>(wParam
),
1036 reinterpret_cast<char*>(lParam
));
1038 case SCI_SETRECTANGULARSELECTIONMODIFIER
:
1039 rectangularSelectionModifier
= wParam
;
1042 case SCI_GETRECTANGULARSELECTIONMODIFIER
:
1043 return rectangularSelectionModifier
;
1046 return ScintillaBase::WndProc(iMessage
, wParam
, lParam
);
1048 } catch (std::bad_alloc
&) {
1049 errorStatus
= SC_STATUS_BADALLOC
;
1051 errorStatus
= SC_STATUS_FAILURE
;
1056 sptr_t
ScintillaGTK::DefWndProc(unsigned int, uptr_t
, sptr_t
) {
1060 void ScintillaGTK::SetTicking(bool on
) {
1061 if (timer
.ticking
!= on
) {
1063 if (timer
.ticking
) {
1064 timer
.tickerID
= reinterpret_cast<TickerID
>(gtk_timeout_add(timer
.tickSize
, (GtkFunction
)TimeOut
, this));
1066 gtk_timeout_remove(GPOINTER_TO_UINT(timer
.tickerID
));
1069 timer
.ticksToWait
= caret
.period
;
1072 bool ScintillaGTK::SetIdle(bool on
) {
1074 // Start idler, if it's not running.
1075 if (idler
.state
== false) {
1077 idler
.idlerID
= reinterpret_cast<IdlerID
>
1078 (gtk_idle_add((GtkFunction
)IdleCallback
, this));
1081 // Stop idler, if it's running
1082 if (idler
.state
== true) {
1083 idler
.state
= false;
1084 gtk_idle_remove(GPOINTER_TO_UINT(idler
.idlerID
));
1090 void ScintillaGTK::SetMouseCapture(bool on
) {
1091 if (mouseDownCaptures
) {
1093 gtk_grab_add(GTK_WIDGET(PWidget(wMain
)));
1095 gtk_grab_remove(GTK_WIDGET(PWidget(wMain
)));
1101 bool ScintillaGTK::HaveMouseCapture() {
1102 return capturedMouse
;
1105 bool ScintillaGTK::PaintContains(PRectangle rc
) {
1106 bool contains
= true;
1107 if (paintState
== painting
) {
1108 if (!rcPaint
.Contains(rc
)) {
1110 } else if (rgnUpdate
) {
1111 GdkRectangle grc
= {rc
.left
, rc
.top
,
1112 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
};
1113 if (gdk_region_rect_in(rgnUpdate
, &grc
) != GDK_OVERLAP_RECTANGLE_IN
) {
1121 // Redraw all of text area. This paint will not be abandoned.
1122 void ScintillaGTK::FullPaint() {
1123 #if GTK_MAJOR_VERSION < 2
1124 paintState
= painting
;
1125 rcPaint
= GetClientRectangle();
1126 //Platform::DebugPrintf("ScintillaGTK::FullPaint %0d,%0d %0d,%0d\n",
1127 // rcPaint.left, rcPaint.top, rcPaint.right, rcPaint.bottom);
1128 paintingAllText
= true;
1129 if ((PWidget(wText
))->window
) {
1130 Surface
*sw
= Surface::Allocate();
1132 sw
->Init(PWidget(wText
)->window
, PWidget(wText
));
1138 paintState
= notPainting
;
1140 wText
.InvalidateAll();
1144 PRectangle
ScintillaGTK::GetClientRectangle() {
1145 PRectangle rc
= wMain
.GetClientPosition();
1146 if (verticalScrollBarVisible
)
1147 rc
.right
-= scrollBarWidth
;
1148 if (horizontalScrollBarVisible
&& (wrapState
== eWrapNone
))
1149 rc
.bottom
-= scrollBarHeight
;
1151 rc
.right
-= rc
.left
;
1152 rc
.bottom
-= rc
.top
;
1158 // Synchronously paint a rectangle of the window.
1159 void ScintillaGTK::SyncPaint(PRectangle rc
) {
1160 paintState
= painting
;
1162 PRectangle rcClient
= GetClientRectangle();
1163 paintingAllText
= rcPaint
.Contains(rcClient
);
1164 if ((PWidget(wText
))->window
) {
1165 Surface
*sw
= Surface::Allocate();
1167 sw
->Init(PWidget(wText
)->window
, PWidget(wText
));
1173 if (paintState
== paintAbandoned
) {
1174 // Painting area was insufficient to cover new styling or brace highlight positions
1177 paintState
= notPainting
;
1180 void ScintillaGTK::ScrollText(int linesToMove
) {
1181 int diff
= vs
.lineHeight
* -linesToMove
;
1182 //Platform::DebugPrintf("ScintillaGTK::ScrollText %d %d %0d,%0d %0d,%0d\n", linesToMove, diff,
1183 // rc.left, rc.top, rc.right, rc.bottom);
1184 GtkWidget
*wi
= PWidget(wText
);
1186 #if GTK_MAJOR_VERSION < 2
1187 PRectangle rc
= GetClientRectangle();
1188 GdkGC
*gc
= gdk_gc_new(wi
->window
);
1190 // Set up gc so we get GraphicsExposures from gdk_draw_pixmap
1191 // which calls XCopyArea
1192 gdk_gc_set_exposures(gc
, TRUE
);
1194 // Redraw exposed bit : scrolling upwards
1196 gdk_draw_pixmap(wi
->window
,
1200 rc
.Width()-1, rc
.Height() - diff
);
1201 SyncPaint(PRectangle(0, rc
.Height() - diff
,
1202 rc
.Width(), rc
.Height()+1));
1204 // Redraw exposed bit : scrolling downwards
1206 gdk_draw_pixmap(wi
->window
,
1210 rc
.Width()-1, rc
.Height() + diff
);
1211 SyncPaint(PRectangle(0, 0, rc
.Width(), -diff
));
1214 // Look for any graphics expose
1216 while ((event
= gdk_event_get_graphics_expose(wi
->window
)) != NULL
) {
1217 gtk_widget_event(wi
, event
);
1218 if (event
->expose
.count
== 0) {
1219 gdk_event_free(event
);
1222 gdk_event_free(event
);
1227 gdk_window_scroll(wi
->window
, 0, -diff
);
1228 gdk_window_process_updates(wi
->window
, FALSE
);
1232 void ScintillaGTK::SetVerticalScrollPos() {
1234 gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmentv
), topLine
);
1237 void ScintillaGTK::SetHorizontalScrollPos() {
1239 gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmenth
), xOffset
/ 2);
1242 bool ScintillaGTK::ModifyScrollBars(int nMax
, int nPage
) {
1243 bool modified
= false;
1244 int pageScroll
= LinesToScroll();
1246 if (GTK_ADJUSTMENT(adjustmentv
)->upper
!= (nMax
+ 1) ||
1247 GTK_ADJUSTMENT(adjustmentv
)->page_size
!= nPage
||
1248 GTK_ADJUSTMENT(adjustmentv
)->page_increment
!= pageScroll
) {
1249 GTK_ADJUSTMENT(adjustmentv
)->upper
= nMax
+ 1;
1250 GTK_ADJUSTMENT(adjustmentv
)->page_size
= nPage
;
1251 GTK_ADJUSTMENT(adjustmentv
)->page_increment
= pageScroll
;
1252 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv
));
1256 PRectangle rcText
= GetTextRectangle();
1257 int horizEndPreferred
= scrollWidth
;
1258 if (horizEndPreferred
< 0)
1259 horizEndPreferred
= 0;
1260 unsigned int pageWidth
= rcText
.Width();
1261 unsigned int pageIncrement
= pageWidth
/ 3;
1262 unsigned int charWidth
= vs
.styles
[STYLE_DEFAULT
].aveCharWidth
;
1263 if (GTK_ADJUSTMENT(adjustmenth
)->upper
!= horizEndPreferred
||
1264 GTK_ADJUSTMENT(adjustmenth
)->page_size
!= pageWidth
||
1265 GTK_ADJUSTMENT(adjustmenth
)->page_increment
!= pageIncrement
||
1266 GTK_ADJUSTMENT(adjustmenth
)->step_increment
!= charWidth
) {
1267 GTK_ADJUSTMENT(adjustmenth
)->upper
= horizEndPreferred
;
1268 GTK_ADJUSTMENT(adjustmenth
)->step_increment
= charWidth
;
1269 GTK_ADJUSTMENT(adjustmenth
)->page_size
= pageWidth
;
1270 GTK_ADJUSTMENT(adjustmenth
)->page_increment
= pageIncrement
;
1271 gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth
));
1277 void ScintillaGTK::ReconfigureScrollBars() {
1278 PRectangle rc
= wMain
.GetClientPosition();
1279 Resize(rc
.Width(), rc
.Height());
1282 void ScintillaGTK::NotifyChange() {
1283 #if GLIB_MAJOR_VERSION < 2
1284 gtk_signal_emit(GTK_OBJECT(sci
), scintilla_signals
[COMMAND_SIGNAL
],
1285 Platform::LongFromTwoShorts(GetCtrlID(), SCEN_CHANGE
), PWidget(wMain
));
1287 g_signal_emit(G_OBJECT(sci
), scintilla_signals
[COMMAND_SIGNAL
], 0,
1288 Platform::LongFromTwoShorts(GetCtrlID(), SCEN_CHANGE
), PWidget(wMain
));
1292 void ScintillaGTK::NotifyFocus(bool focus
) {
1293 #if GLIB_MAJOR_VERSION < 2
1294 gtk_signal_emit(GTK_OBJECT(sci
), scintilla_signals
[COMMAND_SIGNAL
],
1295 Platform::LongFromTwoShorts
1296 (GetCtrlID(), focus
? SCEN_SETFOCUS
: SCEN_KILLFOCUS
), PWidget(wMain
));
1298 g_signal_emit(G_OBJECT(sci
), scintilla_signals
[COMMAND_SIGNAL
], 0,
1299 Platform::LongFromTwoShorts
1300 (GetCtrlID(), focus
? SCEN_SETFOCUS
: SCEN_KILLFOCUS
), PWidget(wMain
));
1304 void ScintillaGTK::NotifyParent(SCNotification scn
) {
1305 scn
.nmhdr
.hwndFrom
= PWidget(wMain
);
1306 scn
.nmhdr
.idFrom
= GetCtrlID();
1307 #if GLIB_MAJOR_VERSION < 2
1308 gtk_signal_emit(GTK_OBJECT(sci
), scintilla_signals
[NOTIFY_SIGNAL
],
1311 g_signal_emit(G_OBJECT(sci
), scintilla_signals
[NOTIFY_SIGNAL
], 0,
1316 void ScintillaGTK::NotifyKey(int key
, int modifiers
) {
1317 SCNotification scn
= {0};
1318 scn
.nmhdr
.code
= SCN_KEY
;
1320 scn
.modifiers
= modifiers
;
1325 void ScintillaGTK::NotifyURIDropped(const char *list
) {
1326 SCNotification scn
= {0};
1327 scn
.nmhdr
.code
= SCN_URIDROPPED
;
1333 const char *CharacterSetID(int characterSet
);
1335 const char *ScintillaGTK::CharacterSetID() const {
1336 return ::CharacterSetID(vs
.styles
[STYLE_DEFAULT
].characterSet
);
1339 int ScintillaGTK::KeyDefault(int key
, int modifiers
) {
1340 if (!(modifiers
& SCI_CTRL
) && !(modifiers
& SCI_ALT
)) {
1342 NotifyKey(key
, modifiers
);
1345 // Pass up to container in case it is an accelerator
1346 NotifyKey(key
, modifiers
);
1350 // Pass up to container in case it is an accelerator
1351 NotifyKey(key
, modifiers
);
1354 //Platform::DebugPrintf("SK-key: %d %x %x\n",key, modifiers);
1357 void ScintillaGTK::CopyToClipboard(const SelectionText
&selectedText
) {
1358 #ifndef USE_GTK_CLIPBOARD
1359 copyText
.Copy(selectedText
);
1360 gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain
)),
1364 SelectionText
*clipText
= new SelectionText();
1365 clipText
->Copy(selectedText
);
1366 StoreOnClipboard(clipText
);
1370 void ScintillaGTK::Copy() {
1372 #ifndef USE_GTK_CLIPBOARD
1373 CopySelectionRange(©Text
);
1374 gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain
)),
1378 SelectionText
*clipText
= new SelectionText();
1379 CopySelectionRange(clipText
);
1380 StoreOnClipboard(clipText
);
1383 if (sel
.IsRectangular()) {
1384 ::OpenClipboard(NULL
);
1385 ::SetClipboardData(cfColumnSelect
, 0);
1392 void ScintillaGTK::Paste() {
1393 atomSought
= atomUTF8
;
1394 gtk_selection_convert(GTK_WIDGET(PWidget(wMain
)),
1395 atomClipboard
, atomSought
, GDK_CURRENT_TIME
);
1398 void ScintillaGTK::CreateCallTipWindow(PRectangle rc
) {
1399 if (!ct
.wCallTip
.Created()) {
1400 ct
.wCallTip
= gtk_window_new(GTK_WINDOW_POPUP
);
1401 ct
.wDraw
= gtk_drawing_area_new();
1402 GtkWidget
*widcdrw
= PWidget(ct
.wDraw
); // // No code inside the G_OBJECT macro
1403 gtk_container_add(GTK_CONTAINER(PWidget(ct
.wCallTip
)), widcdrw
);
1404 #if GLIB_MAJOR_VERSION < 2
1405 gtk_signal_connect(GTK_OBJECT(widcdrw
), "expose_event",
1406 GtkSignalFunc(ScintillaGTK::ExposeCT
), &ct
);
1407 gtk_signal_connect(GTK_OBJECT(widcdrw
), "button_press_event",
1408 GtkSignalFunc(ScintillaGTK::PressCT
), static_cast<void *>(this));
1410 g_signal_connect(G_OBJECT(widcdrw
), "expose_event",
1411 G_CALLBACK(ScintillaGTK::ExposeCT
), &ct
);
1412 g_signal_connect(G_OBJECT(widcdrw
), "button_press_event",
1413 G_CALLBACK(ScintillaGTK::PressCT
), static_cast<void *>(this));
1415 gtk_widget_set_events(widcdrw
,
1416 GDK_EXPOSURE_MASK
| GDK_BUTTON_PRESS_MASK
);
1418 gtk_drawing_area_size(GTK_DRAWING_AREA(PWidget(ct
.wDraw
)),
1419 rc
.Width(), rc
.Height());
1421 if (PWidget(ct
.wCallTip
)->window
) {
1422 gdk_window_resize(PWidget(ct
.wCallTip
)->window
, rc
.Width(), rc
.Height());
1426 void ScintillaGTK::AddToPopUp(const char *label
, int cmd
, bool enabled
) {
1427 char fulllabel
[200];
1428 strcpy(fulllabel
, "/");
1429 strcat(fulllabel
, label
);
1430 GtkItemFactoryCallback menuSig
= GtkItemFactoryCallback(PopUpCB
);
1431 GtkItemFactoryEntry itemEntry
= {
1435 const_cast<gchar
*>(label
[0] ? "<Item>" : "<Separator>"),
1436 #if GTK_MAJOR_VERSION >= 2
1440 gtk_item_factory_create_item(GTK_ITEM_FACTORY(popup
.GetID()),
1441 &itemEntry
, this, 1);
1443 GtkWidget
*item
= gtk_item_factory_get_widget_by_action(
1444 reinterpret_cast<GtkItemFactory
*>(popup
.GetID()), cmd
);
1446 gtk_widget_set_sensitive(item
, enabled
);
1450 bool ScintillaGTK::OwnPrimarySelection() {
1451 return ((gdk_selection_owner_get(GDK_SELECTION_PRIMARY
)
1452 == GTK_WIDGET(PWidget(wMain
))->window
) &&
1453 (GTK_WIDGET(PWidget(wMain
))->window
!= NULL
));
1456 void ScintillaGTK::ClaimSelection() {
1457 // X Windows has a 'primary selection' as well as the clipboard.
1458 // Whenever the user selects some text, we become the primary selection
1459 if (!sel
.Empty() && GTK_WIDGET_REALIZED(GTK_WIDGET(PWidget(wMain
)))) {
1460 primarySelection
= true;
1461 gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain
)),
1462 GDK_SELECTION_PRIMARY
, GDK_CURRENT_TIME
);
1464 } else if (OwnPrimarySelection()) {
1465 primarySelection
= true;
1466 if (primary
.s
== NULL
)
1467 gtk_selection_owner_set(NULL
, GDK_SELECTION_PRIMARY
, GDK_CURRENT_TIME
);
1469 primarySelection
= false;
1474 // Detect rectangular text, convert line ends to current mode, convert from or to UTF-8
1475 void ScintillaGTK::GetGtkSelectionText(GtkSelectionData
*selectionData
, SelectionText
&selText
) {
1476 char *data
= reinterpret_cast<char *>(selectionData
->data
);
1477 int len
= selectionData
->length
;
1478 GdkAtom selectionTypeData
= selectionData
->type
;
1480 // Return empty string if selection is not a string
1481 if ((selectionTypeData
!= GDK_TARGET_STRING
) && (selectionTypeData
!= atomUTF8
)) {
1482 char *empty
= new char[1];
1484 selText
.Set(empty
, 0, SC_CP_UTF8
, 0, false, false);
1488 // Check for "\n\0" ending to string indicating that selection is rectangular
1491 isRectangular
= ::IsClipboardFormatAvailable(cfColumnSelect
) != 0;
1493 isRectangular
= ((len
> 2) && (data
[len
- 1] == 0 && data
[len
- 2] == '\n'));
1497 if (selectionTypeData
== GDK_TARGET_STRING
) {
1498 dest
= Document::TransformLineEnds(&len
, data
, len
, pdoc
->eolMode
);
1499 if (IsUnicodeMode()) {
1500 // Unknown encoding so assume in Latin1
1501 char *destPrevious
= dest
;
1502 dest
= UTF8FromLatin1(dest
, len
);
1503 selText
.Set(dest
, len
, SC_CP_UTF8
, 0, selText
.rectangular
, false);
1504 delete []destPrevious
;
1506 // Assume buffer is in same encoding as selection
1507 selText
.Set(dest
, len
, pdoc
->dbcsCodePage
,
1508 vs
.styles
[STYLE_DEFAULT
].characterSet
, isRectangular
, false);
1511 dest
= Document::TransformLineEnds(&len
, data
, len
, pdoc
->eolMode
);
1512 selText
.Set(dest
, len
, SC_CP_UTF8
, 0, isRectangular
, false);
1513 #ifdef USE_CONVERTER
1514 const char *charSetBuffer
= CharacterSetID();
1515 if (!IsUnicodeMode() && *charSetBuffer
) {
1516 //fprintf(stderr, "Convert to locale %s\n", CharacterSetID());
1517 // Convert to locale
1518 dest
= ConvertText(&len
, selText
.s
, selText
.len
, charSetBuffer
, "UTF-8", true);
1519 selText
.Set(dest
, len
, pdoc
->dbcsCodePage
,
1520 vs
.styles
[STYLE_DEFAULT
].characterSet
, selText
.rectangular
, false);
1526 void ScintillaGTK::ReceivedSelection(GtkSelectionData
*selection_data
) {
1528 if ((selection_data
->selection
== atomClipboard
) ||
1529 (selection_data
->selection
== GDK_SELECTION_PRIMARY
)) {
1530 if ((atomSought
== atomUTF8
) && (selection_data
->length
<= 0)) {
1531 atomSought
= atomString
;
1532 gtk_selection_convert(GTK_WIDGET(PWidget(wMain
)),
1533 selection_data
->selection
, atomSought
, GDK_CURRENT_TIME
);
1534 } else if ((selection_data
->length
> 0) &&
1535 ((selection_data
->type
== GDK_TARGET_STRING
) || (selection_data
->type
== atomUTF8
))) {
1536 SelectionText selText
;
1537 GetGtkSelectionText(selection_data
, selText
);
1540 if (selection_data
->selection
!= GDK_SELECTION_PRIMARY
) {
1543 SelectionPosition selStart
= sel
.IsRectangular() ?
1544 sel
.Rectangular().Start() :
1545 sel
.Range(sel
.Main()).Start();
1547 if (selText
.rectangular
) {
1548 PasteRectangular(selStart
, selText
.s
, selText
.len
);
1550 selStart
= SelectionPosition(InsertSpace(selStart
.Position(), selStart
.VirtualSpace()));
1551 if (pdoc
->InsertString(selStart
.Position(),selText
.s
, selText
.len
)) {
1552 SetEmptySelection(selStart
.Position() + selText
.len
);
1555 EnsureCaretVisible();
1558 // else fprintf(stderr, "Target non string %d %d\n", (int)(selection_data->type),
1559 // (int)(atomUTF8));
1562 errorStatus
= SC_STATUS_FAILURE
;
1566 void ScintillaGTK::ReceivedDrop(GtkSelectionData
*selection_data
) {
1567 dragWasDropped
= true;
1568 if (selection_data
->type
== atomUriList
|| selection_data
->type
== atomDROPFILES_DND
) {
1569 char *ptr
= new char[selection_data
->length
+ 1];
1570 ptr
[selection_data
->length
] = '\0';
1571 memcpy(ptr
, selection_data
->data
, selection_data
->length
);
1572 NotifyURIDropped(ptr
);
1574 } else if ((selection_data
->type
== GDK_TARGET_STRING
) || (selection_data
->type
== atomUTF8
)) {
1575 if (selection_data
->length
> 0) {
1576 SelectionText selText
;
1577 GetGtkSelectionText(selection_data
, selText
);
1578 DropAt(posDrop
, selText
.s
, false, selText
.rectangular
);
1580 } else if (selection_data
->length
> 0) {
1581 //~ fprintf(stderr, "ReceivedDrop other %p\n", static_cast<void *>(selection_data->type));
1588 void ScintillaGTK::GetSelection(GtkSelectionData
*selection_data
, guint info
, SelectionText
*text
) {
1590 // GDK on Win32 expands any \n into \r\n, so make a copy of
1591 // the clip text now with newlines converted to \n. Use { } to hide symbols
1593 SelectionText
*newline_normalized
= NULL
;
1596 char *tmpstr
= Document::TransformLineEnds(&tmpstr_len
, text
->s
, text
->len
, SC_EOL_LF
);
1597 newline_normalized
= new SelectionText();
1598 newline_normalized
->Set(tmpstr
, tmpstr_len
, SC_CP_UTF8
, 0, text
->rectangular
, false);
1599 text
= newline_normalized
;
1603 #if GTK_MAJOR_VERSION >= 2
1604 // Convert text to utf8 if it isn't already
1605 SelectionText
*converted
= 0;
1606 if ((text
->codePage
!= SC_CP_UTF8
) && (info
== TARGET_UTF8_STRING
)) {
1607 const char *charSet
= ::CharacterSetID(text
->characterSet
);
1610 char* tmputf
= ConvertText(&new_len
, text
->s
, text
->len
, "UTF-8", charSet
, false);
1611 converted
= new SelectionText();
1612 converted
->Set(tmputf
, new_len
, SC_CP_UTF8
, 0, text
->rectangular
, false);
1617 // Here is a somewhat evil kludge.
1618 // As I can not work out how to store data on the clipboard in multiple formats
1619 // and need some way to mark the clipping as being stream or rectangular,
1620 // the terminating \0 is included in the length for rectangular clippings.
1621 // All other tested aplications behave benignly by ignoring the \0.
1622 // The #if is here because on Windows cfColumnSelect clip entry is used
1623 // instead as standard indicator of rectangularness (so no need to kludge)
1624 const char *textData
= text
->s
? text
->s
: "";
1625 int len
= strlen(textData
);
1626 #if PLAT_GTK_WIN32 == 0
1627 if (text
->rectangular
)
1631 if (info
== TARGET_UTF8_STRING
) {
1632 gtk_selection_data_set_text(selection_data
, textData
, len
);
1634 gtk_selection_data_set(selection_data
,
1635 static_cast<GdkAtom
>(GDK_SELECTION_TYPE_STRING
),
1636 8, reinterpret_cast<const unsigned char *>(textData
), len
);
1641 char *selBuffer
= text
->s
;
1644 if ((info
== TARGET_UTF8_STRING
) || (info
== TARGET_STRING
)) {
1645 int len
= strlen(selBuffer
);
1646 #ifdef USE_CONVERTER
1647 // Possible character set conversion
1648 const char *charSetBuffer
= ::CharacterSetID(text
->characterSet
);
1649 if (info
== TARGET_UTF8_STRING
) {
1650 //fprintf(stderr, "Copy to clipboard as UTF-8\n");
1651 if (text
->codePage
!= SC_CP_UTF8
) {
1653 //fprintf(stderr, "Convert to UTF-8 from %s\n", charSetBuffer);
1654 tmputf
= ConvertText(&len
, selBuffer
, len
, "UTF-8", charSetBuffer
, false);
1657 } else if (info
== TARGET_STRING
) {
1658 if (text
->codePage
== SC_CP_UTF8
) {
1659 //fprintf(stderr, "Convert to locale %s\n", charSetBuffer);
1660 // Convert to locale
1661 tmputf
= ConvertText(&len
, selBuffer
, len
, charSetBuffer
, "UTF-8", true);
1667 // Here is a somewhat evil kludge.
1668 // As I can not work out how to store data on the clipboard in multiple formats
1669 // and need some way to mark the clipping as being stream or rectangular,
1670 // the terminating \0 is included in the length for rectangular clippings.
1671 // All other tested aplications behave benignly by ignoring the \0.
1672 // The #if is here because on Windows cfColumnSelect clip entry is used
1673 // instead as standard indicator of rectangularness (so no need to kludge)
1674 #if PLAT_GTK_WIN32 == 0
1675 if (text
->rectangular
)
1678 gtk_selection_data_set(selection_data
,
1679 (info
== TARGET_STRING
) ?
1680 static_cast<GdkAtom
>(GDK_SELECTION_TYPE_STRING
) : atomUTF8
,
1681 8, reinterpret_cast<unsigned char *>(selBuffer
),
1683 } else if ((info
== TARGET_TEXT
) || (info
== TARGET_COMPOUND_TEXT
)) {
1689 gdk_string_to_compound_text(reinterpret_cast<char *>(selBuffer
),
1690 &encoding
, &format
, &text
, &new_length
);
1691 gtk_selection_data_set(selection_data
, encoding
, format
, text
, new_length
);
1692 gdk_free_compound_text(text
);
1696 #endif /* Gtk >= 2 */
1699 delete newline_normalized
;
1703 #ifdef USE_GTK_CLIPBOARD
1704 void ScintillaGTK::StoreOnClipboard(SelectionText
*clipText
) {
1705 GtkClipboard
*clipBoard
=
1706 gtk_widget_get_clipboard(GTK_WIDGET(PWidget(wMain
)), atomClipboard
);
1707 if (clipBoard
== NULL
) // Occurs if widget isn't in a toplevel
1710 if (gtk_clipboard_set_with_data(clipBoard
, clipboardCopyTargets
, nClipboardCopyTargets
,
1711 ClipboardGetSelection
, ClipboardClearSelection
, clipText
)) {
1712 gtk_clipboard_set_can_store(clipBoard
, clipboardCopyTargets
, nClipboardCopyTargets
);
1716 void ScintillaGTK::ClipboardGetSelection(GtkClipboard
*, GtkSelectionData
*selection_data
, guint info
, void *data
) {
1717 GetSelection(selection_data
, info
, static_cast<SelectionText
*>(data
));
1720 void ScintillaGTK::ClipboardClearSelection(GtkClipboard
*, void *data
) {
1721 SelectionText
*obj
= static_cast<SelectionText
*>(data
);
1726 void ScintillaGTK::UnclaimSelection(GdkEventSelection
*selection_event
) {
1728 //Platform::DebugPrintf("UnclaimSelection\n");
1729 if (selection_event
->selection
== GDK_SELECTION_PRIMARY
) {
1730 //Platform::DebugPrintf("UnclaimPrimarySelection\n");
1731 if (!OwnPrimarySelection()) {
1733 primarySelection
= false;
1738 errorStatus
= SC_STATUS_FAILURE
;
1742 void ScintillaGTK::Resize(int width
, int height
) {
1743 //Platform::DebugPrintf("Resize %d %d\n", width, height);
1744 //printf("Resize %d %d\n", width, height);
1746 // Not always needed, but some themes can have different sizes of scrollbars
1747 scrollBarWidth
= GTK_WIDGET(PWidget(scrollbarv
))->requisition
.width
;
1748 scrollBarHeight
= GTK_WIDGET(PWidget(scrollbarh
))->requisition
.height
;
1750 // These allocations should never produce negative sizes as they would wrap around to huge
1751 // unsigned numbers inside GTK+ causing warnings.
1752 bool showSBHorizontal
= horizontalScrollBarVisible
&& (wrapState
== eWrapNone
);
1753 int horizontalScrollBarHeight
= scrollBarHeight
;
1754 if (!showSBHorizontal
)
1755 horizontalScrollBarHeight
= 0;
1756 int verticalScrollBarHeight
= scrollBarWidth
;
1757 if (!verticalScrollBarVisible
)
1758 verticalScrollBarHeight
= 0;
1760 GtkAllocation alloc
;
1761 if (showSBHorizontal
) {
1762 gtk_widget_show(GTK_WIDGET(PWidget(scrollbarh
)));
1764 alloc
.y
= height
- scrollBarHeight
;
1765 alloc
.width
= Platform::Maximum(1, width
- scrollBarWidth
) + 1;
1766 alloc
.height
= horizontalScrollBarHeight
;
1767 gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarh
)), &alloc
);
1769 gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarh
)));
1772 if (verticalScrollBarVisible
) {
1773 gtk_widget_show(GTK_WIDGET(PWidget(scrollbarv
)));
1774 alloc
.x
= width
- scrollBarWidth
;
1776 alloc
.width
= scrollBarWidth
;
1777 alloc
.height
= Platform::Maximum(1, height
- scrollBarHeight
) + 1;
1778 if (!showSBHorizontal
)
1779 alloc
.height
+= scrollBarWidth
-1;
1780 gtk_widget_size_allocate(GTK_WIDGET(PWidget(scrollbarv
)), &alloc
);
1782 gtk_widget_hide(GTK_WIDGET(PWidget(scrollbarv
)));
1784 if (GTK_WIDGET_MAPPED(PWidget(wMain
))) {
1790 alloc
.width
= Platform::Maximum(1, width
- scrollBarWidth
);
1791 alloc
.height
= Platform::Maximum(1, height
- scrollBarHeight
);
1792 if (!showSBHorizontal
)
1793 alloc
.height
+= scrollBarHeight
;
1794 if (!verticalScrollBarVisible
)
1795 alloc
.width
+= scrollBarWidth
;
1796 gtk_widget_size_allocate(GTK_WIDGET(PWidget(wText
)), &alloc
);
1799 static void SetAdjustmentValue(GtkObject
*object
, int value
) {
1800 GtkAdjustment
*adjustment
= GTK_ADJUSTMENT(object
);
1801 int maxValue
= static_cast<int>(
1802 adjustment
->upper
- adjustment
->page_size
);
1803 if (value
> maxValue
)
1807 gtk_adjustment_set_value(adjustment
, value
);
1810 static int modifierTranslated(int sciModifier
) {
1811 switch (sciModifier
) {
1813 return GDK_SHIFT_MASK
;
1815 return GDK_CONTROL_MASK
;
1817 return GDK_MOD1_MASK
;
1819 return GDK_MOD4_MASK
;
1825 gint
ScintillaGTK::PressThis(GdkEventButton
*event
) {
1827 //Platform::DebugPrintf("Press %x time=%d state = %x button = %x\n",this,event->time, event->state, event->button);
1828 // Do not use GTK+ double click events as Scintilla has its own double click detection
1829 if (event
->type
!= GDK_BUTTON_PRESS
)
1834 pt
.x
= int(event
->x
);
1835 pt
.y
= int(event
->y
);
1836 PRectangle rcClient
= GetClientRectangle();
1837 //Platform::DebugPrintf("Press %0d,%0d in %0d,%0d %0d,%0d\n",
1838 // pt.x, pt.y, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1839 if ((pt
.x
> rcClient
.right
) || (pt
.y
> rcClient
.bottom
)) {
1840 Platform::DebugPrintf("Bad location\n");
1844 bool ctrl
= (event
->state
& GDK_CONTROL_MASK
) != 0;
1846 gtk_widget_grab_focus(PWidget(wMain
));
1847 if (event
->button
== 1) {
1848 // On X, instead of sending literal modifiers use the user specified
1849 // modifier, defaulting to control instead of alt.
1850 // This is because most X window managers grab alt + click for moving
1851 ButtonDown(pt
, event
->time
,
1852 (event
->state
& GDK_SHIFT_MASK
) != 0,
1853 (event
->state
& GDK_CONTROL_MASK
) != 0,
1854 (event
->state
& modifierTranslated(rectangularSelectionModifier
)) != 0);
1855 } else if (event
->button
== 2) {
1856 // Grab the primary selection if it exists
1857 SelectionPosition pos
= SPositionFromLocation(pt
, false, false, UserVirtualSpace());
1858 if (OwnPrimarySelection() && primary
.s
== NULL
)
1859 CopySelectionRange(&primary
);
1861 SetSelection(pos
, pos
);
1862 atomSought
= atomUTF8
;
1863 gtk_selection_convert(GTK_WIDGET(PWidget(wMain
)), GDK_SELECTION_PRIMARY
,
1864 atomSought
, event
->time
);
1865 } else if (event
->button
== 3) {
1866 if (displayPopupMenu
) {
1868 // Convert to screen
1871 gdk_window_get_origin(PWidget(wMain
)->window
, &ox
, &oy
);
1872 ContextMenu(Point(pt
.x
+ ox
, pt
.y
+ oy
));
1876 } else if (event
->button
== 4) {
1877 // Wheel scrolling up (only GTK 1.x does it this way)
1879 SetAdjustmentValue(adjustmenth
, (xOffset
/ 2) - 6);
1881 SetAdjustmentValue(adjustmentv
, topLine
- 3);
1882 } else if (event
->button
== 5) {
1883 // Wheel scrolling down (only GTK 1.x does it this way)
1885 SetAdjustmentValue(adjustmenth
, (xOffset
/ 2) + 6);
1887 SetAdjustmentValue(adjustmentv
, topLine
+ 3);
1890 errorStatus
= SC_STATUS_FAILURE
;
1892 #if GTK_MAJOR_VERSION >= 2
1899 gint
ScintillaGTK::Press(GtkWidget
*widget
, GdkEventButton
*event
) {
1900 if (event
->window
!= widget
->window
)
1902 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1903 return sciThis
->PressThis(event
);
1906 gint
ScintillaGTK::MouseRelease(GtkWidget
*widget
, GdkEventButton
*event
) {
1907 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1909 //Platform::DebugPrintf("Release %x %d %d\n",sciThis,event->time,event->state);
1910 if (!sciThis
->HaveMouseCapture())
1912 if (event
->button
== 1) {
1914 pt
.x
= int(event
->x
);
1915 pt
.y
= int(event
->y
);
1916 //Platform::DebugPrintf("Up %x %x %d %d %d\n",
1917 // sciThis,event->window,event->time, pt.x, pt.y);
1918 if (event
->window
!= PWidget(sciThis
->wMain
)->window
)
1919 // If mouse released on scroll bar then the position is relative to the
1920 // scrollbar, not the drawing window so just repeat the most recent point.
1921 pt
= sciThis
->ptMouseLast
;
1922 sciThis
->ButtonUp(pt
, event
->time
, (event
->state
& 4) != 0);
1925 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
1930 // win32gtk and GTK >= 2 use SCROLL_* events instead of passing the
1931 // button4/5/6/7 events to the GTK app
1932 #if PLAT_GTK_WIN32 || (GTK_MAJOR_VERSION >= 2)
1933 gint
ScintillaGTK::ScrollEvent(GtkWidget
*widget
,
1934 GdkEventScroll
*event
) {
1935 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
1938 if (widget
== NULL
|| event
== NULL
)
1941 // Compute amount and direction to scroll (even tho on win32 there is
1942 // intensity of scrolling info in the native message, gtk doesn't
1943 // support this so we simulate similarly adaptive scrolling)
1944 // Note that this is disabled on OS X (Darwin) where the X11 server already has
1945 // and adaptive scrolling algorithm that fights with this one
1947 #if defined(__MWERKS__) || defined(__APPLE_CPP__) || defined(__APPLE_CC__)
1948 cLineScroll
= sciThis
->linesPerScroll
;
1949 if (cLineScroll
== 0)
1951 sciThis
->wheelMouseIntensity
= cLineScroll
;
1953 int timeDelta
= 1000000;
1955 g_get_current_time(&curTime
);
1956 if (curTime
.tv_sec
== sciThis
->lastWheelMouseTime
.tv_sec
)
1957 timeDelta
= curTime
.tv_usec
- sciThis
->lastWheelMouseTime
.tv_usec
;
1958 else if (curTime
.tv_sec
== sciThis
->lastWheelMouseTime
.tv_sec
+ 1)
1959 timeDelta
= 1000000 + (curTime
.tv_usec
- sciThis
->lastWheelMouseTime
.tv_usec
);
1960 if ((event
->direction
== sciThis
->lastWheelMouseDirection
) && (timeDelta
< 250000)) {
1961 if (sciThis
->wheelMouseIntensity
< 12)
1962 sciThis
->wheelMouseIntensity
++;
1963 cLineScroll
= sciThis
->wheelMouseIntensity
;
1965 cLineScroll
= sciThis
->linesPerScroll
;
1966 if (cLineScroll
== 0)
1968 sciThis
->wheelMouseIntensity
= cLineScroll
;
1971 if (event
->direction
== GDK_SCROLL_UP
|| event
->direction
== GDK_SCROLL_LEFT
) {
1974 g_get_current_time(&sciThis
->lastWheelMouseTime
);
1975 sciThis
->lastWheelMouseDirection
= event
->direction
;
1977 // Note: Unpatched versions of win32gtk don't set the 'state' value so
1978 // only regular scrolling is supported there. Also, unpatched win32gtk
1979 // issues spurious button 2 mouse events during wheeling, which can cause
1980 // problems (a patch for both was submitted by archaeopteryx.com on 13Jun2001)
1982 // Data zoom not supported
1983 if (event
->state
& GDK_SHIFT_MASK
) {
1987 // Horizontal scrolling
1988 if (event
->direction
== GDK_SCROLL_LEFT
|| event
->direction
== GDK_SCROLL_RIGHT
) {
1989 sciThis
->HorizontalScrollTo(sciThis
->xOffset
+ cLineScroll
);
1991 // Text font size zoom
1992 } else if (event
->state
& GDK_CONTROL_MASK
) {
1993 if (cLineScroll
< 0) {
1994 sciThis
->KeyCommand(SCI_ZOOMIN
);
1996 sciThis
->KeyCommand(SCI_ZOOMOUT
);
1999 // Regular scrolling
2001 sciThis
->ScrollTo(sciThis
->topLine
+ cLineScroll
);
2005 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2011 gint
ScintillaGTK::Motion(GtkWidget
*widget
, GdkEventMotion
*event
) {
2012 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2014 //Platform::DebugPrintf("Motion %x %d\n",sciThis,event->time);
2015 if (event
->window
!= widget
->window
)
2019 GdkModifierType state
;
2020 if (event
->is_hint
) {
2021 gdk_window_get_pointer(event
->window
, &x
, &y
, &state
);
2023 x
= static_cast<int>(event
->x
);
2024 y
= static_cast<int>(event
->y
);
2025 state
= static_cast<GdkModifierType
>(event
->state
);
2027 //Platform::DebugPrintf("Move %x %x %d %c %d %d\n",
2028 // sciThis,event->window,event->time,event->is_hint? 'h' :'.', x, y);
2030 sciThis
->ButtonMove(pt
);
2032 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2037 // Map the keypad keys to their equivalent functions
2038 static int KeyTranslate(int keyIn
) {
2040 case GDK_ISO_Left_Tab
:
2054 case GDK_KP_Page_Up
:
2056 case GDK_KP_Page_Down
:
2095 case GDK_KP_Subtract
:
2096 return SCK_SUBTRACT
;
2110 gboolean
ScintillaGTK::KeyThis(GdkEventKey
*event
) {
2112 //fprintf(stderr, "SC-key: %d %x [%s]\n",
2113 // event->keyval, event->state, (event->length > 0) ? event->string : "empty");
2114 #if GTK_MAJOR_VERSION >= 2
2115 if (gtk_im_context_filter_keypress(im_context
, event
)) {
2119 if (!event
->keyval
) {
2123 bool shift
= (event
->state
& GDK_SHIFT_MASK
) != 0;
2124 bool ctrl
= (event
->state
& GDK_CONTROL_MASK
) != 0;
2125 bool alt
= (event
->state
& GDK_MOD1_MASK
) != 0;
2126 guint key
= event
->keyval
;
2127 if (ctrl
&& (key
< 128))
2129 else if (!ctrl
&& (key
>= GDK_KP_Multiply
&& key
<= GDK_KP_9
))
2131 // Hack for keys over 256 and below command keys but makes Hungarian work.
2132 // This will have to change for Unicode
2133 else if (key
>= 0xFE00)
2134 key
= KeyTranslate(key
);
2135 #if GTK_MAJOR_VERSION < 2
2136 else if (!IsUnicodeMode() && (key
>= 0x100) && (key
< 0x1000))
2140 bool consumed
= false;
2141 bool added
= KeyDown(key
, shift
, ctrl
, alt
, &consumed
) != 0;
2144 //fprintf(stderr, "SK-key: %d %x %x\n",event->keyval, event->state, consumed);
2145 if (event
->keyval
== 0xffffff && event
->length
> 0) {
2147 if (pdoc
->InsertCString(CurrentPosition(), event
->string
)) {
2148 MovePositionTo(CurrentPosition() + event
->length
);
2153 errorStatus
= SC_STATUS_FAILURE
;
2158 gboolean
ScintillaGTK::KeyPress(GtkWidget
*widget
, GdkEventKey
*event
) {
2159 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2160 return sciThis
->KeyThis(event
);
2163 gboolean
ScintillaGTK::KeyRelease(GtkWidget
*, GdkEventKey
* /*event*/) {
2164 //Platform::DebugPrintf("SC-keyrel: %d %x %3s\n",event->keyval, event->state, event->string);
2168 #if GTK_MAJOR_VERSION >= 2
2169 gboolean
ScintillaGTK::ExposePreeditThis(GtkWidget
*widget
, GdkEventExpose
*ose
) {
2173 PangoAttrList
*attrs
;
2175 gtk_im_context_get_preedit_string(im_context
, &str
, &attrs
, &cursor_pos
);
2176 PangoLayout
*layout
= gtk_widget_create_pango_layout(PWidget(wText
), str
);
2177 pango_layout_set_attributes(layout
, attrs
);
2179 GdkGC
*gc
= gdk_gc_new(widget
->window
);
2180 GdkColor color
[2] = { {0, 0x0000, 0x0000, 0x0000},
2181 {0, 0xffff, 0xffff, 0xffff}
2183 gdk_color_alloc(gdk_colormap_get_system(), color
);
2184 gdk_color_alloc(gdk_colormap_get_system(), color
+ 1);
2186 gdk_gc_set_foreground(gc
, color
+ 1);
2187 gdk_draw_rectangle(widget
->window
, gc
, TRUE
, ose
->area
.x
, ose
->area
.y
,
2188 ose
->area
.width
, ose
->area
.height
);
2190 gdk_gc_set_foreground(gc
, color
);
2191 gdk_gc_set_background(gc
, color
+ 1);
2192 gdk_draw_layout(widget
->window
, gc
, 0, 0, layout
);
2196 pango_attr_list_unref(attrs
);
2197 g_object_unref(layout
);
2199 errorStatus
= SC_STATUS_FAILURE
;
2204 gboolean
ScintillaGTK::ExposePreedit(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
) {
2205 return sciThis
->ExposePreeditThis(widget
, ose
);
2208 void ScintillaGTK::CommitThis(char *utfVal
) {
2210 //~ fprintf(stderr, "Commit '%s'\n", utfVal);
2211 if (IsUnicodeMode()) {
2212 AddCharUTF(utfVal
, strlen(utfVal
));
2214 const char *source
= CharacterSetID();
2216 Converter
conv(source
, "UTF-8", true);
2218 char localeVal
[4] = "\0\0\0";
2220 size_t inLeft
= strlen(utfVal
);
2221 char *pout
= localeVal
;
2222 size_t outLeft
= sizeof(localeVal
);
2223 size_t conversions
= conv
.Convert(&pin
, &inLeft
, &pout
, &outLeft
);
2224 if (conversions
!= ((size_t)(-1))) {
2226 for (int i
= 0; localeVal
[i
]; i
++) {
2227 AddChar(localeVal
[i
]);
2230 fprintf(stderr
, "Conversion failed '%s'\n", utfVal
);
2236 errorStatus
= SC_STATUS_FAILURE
;
2240 void ScintillaGTK::Commit(GtkIMContext
*, char *str
, ScintillaGTK
*sciThis
) {
2241 sciThis
->CommitThis(str
);
2244 void ScintillaGTK::PreeditChangedThis() {
2247 PangoAttrList
*attrs
;
2249 gtk_im_context_get_preedit_string(im_context
, &str
, &attrs
, &cursor_pos
);
2250 if (strlen(str
) > 0) {
2251 PangoLayout
*layout
= gtk_widget_create_pango_layout(PWidget(wText
), str
);
2252 pango_layout_set_attributes(layout
, attrs
);
2255 pango_layout_get_pixel_size(layout
, &w
, &h
);
2256 g_object_unref(layout
);
2259 gdk_window_get_origin((PWidget(wText
))->window
, &x
, &y
);
2261 Point pt
= PointMainCaret();
2267 gtk_window_move(GTK_WINDOW(PWidget(wPreedit
)), x
+ pt
.x
, y
+ pt
.y
);
2268 gtk_window_resize(GTK_WINDOW(PWidget(wPreedit
)), w
, h
);
2269 gtk_widget_show(PWidget(wPreedit
));
2270 gtk_widget_queue_draw_area(PWidget(wPreeditDraw
), 0, 0, w
, h
);
2272 gtk_widget_hide(PWidget(wPreedit
));
2275 pango_attr_list_unref(attrs
);
2277 errorStatus
= SC_STATUS_FAILURE
;
2281 void ScintillaGTK::PreeditChanged(GtkIMContext
*, ScintillaGTK
*sciThis
) {
2282 sciThis
->PreeditChangedThis();
2286 gint
ScintillaGTK::StyleSetText(GtkWidget
*widget
, GtkStyle
*, void*) {
2287 if (widget
->window
!= NULL
)
2288 gdk_window_set_back_pixmap(widget
->window
, NULL
, FALSE
);
2292 gint
ScintillaGTK::RealizeText(GtkWidget
*widget
, void*) {
2293 if (widget
->window
!= NULL
)
2294 gdk_window_set_back_pixmap(widget
->window
, NULL
, FALSE
);
2298 #if GLIB_MAJOR_VERSION < 2
2299 void ScintillaGTK::Destroy(GtkObject
*object
)
2301 void ScintillaGTK::Destroy(GObject
*object
)
2305 ScintillaObject
*scio
= reinterpret_cast<ScintillaObject
*>(object
);
2306 // This avoids a double destruction
2309 ScintillaGTK
*sciThis
= reinterpret_cast<ScintillaGTK
*>(scio
->pscin
);
2310 //Platform::DebugPrintf("Destroying %x %x\n", sciThis, object);
2311 sciThis
->Finalise();
2313 #if GLIB_MAJOR_VERSION < 2
2314 if (GTK_OBJECT_CLASS(parent_class
)->destroy
)
2315 (* GTK_OBJECT_CLASS(parent_class
)->destroy
)(object
);
2317 // IS ANYTHING NEEDED ?
2323 // Its dead so nowhere to save the status
2327 static void DrawChild(GtkWidget
*widget
, GdkRectangle
*area
) {
2328 GdkRectangle areaIntersect
;
2330 GTK_WIDGET_DRAWABLE(widget
) &&
2331 gtk_widget_intersect(widget
, area
, &areaIntersect
)) {
2332 gtk_widget_draw(widget
, &areaIntersect
);
2336 void ScintillaGTK::Draw(GtkWidget
*widget
, GdkRectangle
*area
) {
2337 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2339 //Platform::DebugPrintf("Draw %p %0d,%0d %0d,%0d\n", widget, area->x, area->y, area->width, area->height);
2340 PRectangle
rcPaint(area
->x
, area
->y
, area
->x
+ area
->width
, area
->y
+ area
->height
);
2341 sciThis
->SyncPaint(rcPaint
);
2342 if (GTK_WIDGET_DRAWABLE(PWidget(sciThis
->wMain
))) {
2343 DrawChild(PWidget(sciThis
->scrollbarh
), area
);
2344 DrawChild(PWidget(sciThis
->scrollbarv
), area
);
2347 #ifdef INTERNATIONAL_INPUT
2348 Point pt
= sciThis
->PointMainCaret();
2349 pt
.y
+= sciThis
->vs
.lineHeight
- 2;
2350 if (pt
.x
< 0) pt
.x
= 0;
2351 if (pt
.y
< 0) pt
.y
= 0;
2352 CursorMoved(widget
, pt
.x
, pt
.y
, sciThis
);
2355 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2359 gint
ScintillaGTK::ExposeTextThis(GtkWidget
* /*widget*/, GdkEventExpose
*ose
) {
2361 paintState
= painting
;
2363 rcPaint
.left
= ose
->area
.x
;
2364 rcPaint
.top
= ose
->area
.y
;
2365 rcPaint
.right
= ose
->area
.x
+ ose
->area
.width
;
2366 rcPaint
.bottom
= ose
->area
.y
+ ose
->area
.height
;
2368 PLATFORM_ASSERT(rgnUpdate
== NULL
);
2369 #if GTK_MAJOR_VERSION >= 2
2370 rgnUpdate
= gdk_region_copy(ose
->region
);
2372 PRectangle rcClient
= GetClientRectangle();
2373 paintingAllText
= rcPaint
.Contains(rcClient
);
2374 Surface
*surfaceWindow
= Surface::Allocate();
2375 if (surfaceWindow
) {
2376 surfaceWindow
->Init(PWidget(wText
)->window
, PWidget(wText
));
2377 Paint(surfaceWindow
, rcPaint
);
2378 surfaceWindow
->Release();
2379 delete surfaceWindow
;
2381 if (paintState
== paintAbandoned
) {
2382 // Painting area was insufficient to cover new styling or brace highlight positions
2385 paintState
= notPainting
;
2388 gdk_region_destroy(rgnUpdate
);
2392 errorStatus
= SC_STATUS_FAILURE
;
2398 gint
ScintillaGTK::ExposeText(GtkWidget
*widget
, GdkEventExpose
*ose
, ScintillaGTK
*sciThis
) {
2399 return sciThis
->ExposeTextThis(widget
, ose
);
2402 gint
ScintillaGTK::ExposeMain(GtkWidget
*widget
, GdkEventExpose
*ose
) {
2403 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2404 //Platform::DebugPrintf("Expose Main %0d,%0d %0d,%0d\n",
2405 //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2406 return sciThis
->Expose(widget
, ose
);
2409 gint
ScintillaGTK::Expose(GtkWidget
*, GdkEventExpose
*ose
) {
2411 //fprintf(stderr, "Expose %0d,%0d %0d,%0d\n",
2412 //ose->area.x, ose->area.y, ose->area.width, ose->area.height);
2414 #if GTK_MAJOR_VERSION < 2
2416 paintState
= painting
;
2418 rcPaint
.left
= ose
->area
.x
;
2419 rcPaint
.top
= ose
->area
.y
;
2420 rcPaint
.right
= ose
->area
.x
+ ose
->area
.width
;
2421 rcPaint
.bottom
= ose
->area
.y
+ ose
->area
.height
;
2423 PRectangle rcClient
= GetClientRectangle();
2424 paintingAllText
= rcPaint
.Contains(rcClient
);
2425 Surface
*surfaceWindow
= Surface::Allocate();
2426 if (surfaceWindow
) {
2427 surfaceWindow
->Init(PWidget(wMain
)->window
, PWidget(wMain
));
2429 // Fill the corner between the scrollbars
2430 if (verticalScrollBarVisible
) {
2431 if (horizontalScrollBarVisible
&& (wrapState
== eWrapNone
)) {
2432 PRectangle rcCorner
= wMain
.GetClientPosition();
2433 rcCorner
.left
= rcCorner
.right
- scrollBarWidth
+ 1;
2434 rcCorner
.top
= rcCorner
.bottom
- scrollBarHeight
+ 1;
2435 //fprintf(stderr, "Corner %0d,%0d %0d,%0d\n",
2436 //rcCorner.left, rcCorner.top, rcCorner.right, rcCorner.bottom);
2437 surfaceWindow
->FillRectangle(rcCorner
,
2438 vs
.styles
[STYLE_LINENUMBER
].back
.allocated
);
2442 //Paint(surfaceWindow, rcPaint);
2443 surfaceWindow
->Release();
2444 delete surfaceWindow
;
2446 if (paintState
== paintAbandoned
) {
2447 // Painting area was insufficient to cover new styling or brace highlight positions
2450 paintState
= notPainting
;
2453 // For GTK+ 2, the text is painted in ExposeText
2454 gtk_container_propagate_expose(
2455 GTK_CONTAINER(PWidget(wMain
)), PWidget(scrollbarh
), ose
);
2456 gtk_container_propagate_expose(
2457 GTK_CONTAINER(PWidget(wMain
)), PWidget(scrollbarv
), ose
);
2461 errorStatus
= SC_STATUS_FAILURE
;
2466 void ScintillaGTK::ScrollSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
) {
2468 sciThis
->ScrollTo(static_cast<int>(adj
->value
), false);
2470 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2474 void ScintillaGTK::ScrollHSignal(GtkAdjustment
*adj
, ScintillaGTK
*sciThis
) {
2476 sciThis
->HorizontalScrollTo(static_cast<int>(adj
->value
* 2));
2478 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2482 void ScintillaGTK::SelectionReceived(GtkWidget
*widget
,
2483 GtkSelectionData
*selection_data
, guint
) {
2484 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2485 //Platform::DebugPrintf("Selection received\n");
2486 sciThis
->ReceivedSelection(selection_data
);
2489 void ScintillaGTK::SelectionGet(GtkWidget
*widget
,
2490 GtkSelectionData
*selection_data
, guint info
, guint
) {
2491 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2493 //Platform::DebugPrintf("Selection get\n");
2494 if (selection_data
->selection
== GDK_SELECTION_PRIMARY
) {
2495 if (sciThis
->primary
.s
== NULL
) {
2496 sciThis
->CopySelectionRange(&sciThis
->primary
);
2498 sciThis
->GetSelection(selection_data
, info
, &sciThis
->primary
);
2500 #ifndef USE_GTK_CLIPBOARD
2502 sciThis
->GetSelection(selection_data
, info
, &sciThis
->copyText
);
2506 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2510 gint
ScintillaGTK::SelectionClear(GtkWidget
*widget
, GdkEventSelection
*selection_event
) {
2511 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2512 //Platform::DebugPrintf("Selection clear\n");
2513 sciThis
->UnclaimSelection(selection_event
);
2514 return gtk_selection_clear(widget
, selection_event
);
2517 #if GTK_MAJOR_VERSION < 2
2518 gint
ScintillaGTK::SelectionNotify(GtkWidget
*widget
, GdkEventSelection
*selection_event
) {
2519 //Platform::DebugPrintf("Selection notify\n");
2520 return gtk_selection_notify(widget
, selection_event
);
2524 void ScintillaGTK::DragBegin(GtkWidget
*, GdkDragContext
*) {
2525 //Platform::DebugPrintf("DragBegin\n");
2528 gboolean
ScintillaGTK::DragMotionThis(GdkDragContext
*context
,
2529 gint x
, gint y
, guint dragtime
) {
2532 SetDragPosition(SPositionFromLocation(npt
, false, false, UserVirtualSpace()));
2533 GdkDragAction preferredAction
= context
->suggested_action
;
2534 SelectionPosition pos
= SPositionFromLocation(npt
);
2535 if ((inDragDrop
== ddDragging
) && (PositionInSelection(pos
.Position()))) {
2536 // Avoid dragging selection onto itself as that produces a move
2537 // with no real effect but which creates undo actions.
2538 preferredAction
= static_cast<GdkDragAction
>(0);
2539 } else if (context
->actions
== static_cast<GdkDragAction
>
2540 (GDK_ACTION_COPY
| GDK_ACTION_MOVE
)) {
2541 preferredAction
= GDK_ACTION_MOVE
;
2543 gdk_drag_status(context
, preferredAction
, dragtime
);
2545 errorStatus
= SC_STATUS_FAILURE
;
2550 gboolean
ScintillaGTK::DragMotion(GtkWidget
*widget
, GdkDragContext
*context
,
2551 gint x
, gint y
, guint dragtime
) {
2552 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2553 return sciThis
->DragMotionThis(context
, x
, y
, dragtime
);
2556 void ScintillaGTK::DragLeave(GtkWidget
*widget
, GdkDragContext
* /*context*/, guint
) {
2557 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2559 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2560 //Platform::DebugPrintf("DragLeave %x\n", sciThis);
2562 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2566 void ScintillaGTK::DragEnd(GtkWidget
*widget
, GdkDragContext
* /*context*/) {
2567 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2569 // If drag did not result in drop here or elsewhere
2570 if (!sciThis
->dragWasDropped
)
2571 sciThis
->SetEmptySelection(sciThis
->posDrag
);
2572 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2573 //Platform::DebugPrintf("DragEnd %x %d\n", sciThis, sciThis->dragWasDropped);
2574 sciThis
->inDragDrop
= ddNone
;
2576 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2580 gboolean
ScintillaGTK::Drop(GtkWidget
*widget
, GdkDragContext
* /*context*/,
2581 gint
, gint
, guint
) {
2582 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2584 //Platform::DebugPrintf("Drop %x\n", sciThis);
2585 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2587 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2592 void ScintillaGTK::DragDataReceived(GtkWidget
*widget
, GdkDragContext
* /*context*/,
2593 gint
, gint
, GtkSelectionData
*selection_data
, guint
/*info*/, guint
) {
2594 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2596 sciThis
->ReceivedDrop(selection_data
);
2597 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2599 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2603 void ScintillaGTK::DragDataGet(GtkWidget
*widget
, GdkDragContext
*context
,
2604 GtkSelectionData
*selection_data
, guint info
, guint
) {
2605 ScintillaGTK
*sciThis
= ScintillaFromWidget(widget
);
2607 sciThis
->dragWasDropped
= true;
2608 if (!sciThis
->sel
.Empty()) {
2609 sciThis
->GetSelection(selection_data
, info
, &sciThis
->drag
);
2611 if (context
->action
== GDK_ACTION_MOVE
) {
2612 for (size_t r
=0; r
<sciThis
->sel
.Count(); r
++) {
2613 if (sciThis
->posDrop
>= sciThis
->sel
.Range(r
).Start()) {
2614 if (sciThis
->posDrop
> sciThis
->sel
.Range(r
).End()) {
2615 sciThis
->posDrop
.Add(-sciThis
->sel
.Range(r
).Length());
2617 sciThis
->posDrop
.Add(-SelectionRange(sciThis
->posDrop
, sciThis
->sel
.Range(r
).Start()).Length());
2621 sciThis
->ClearSelection();
2623 sciThis
->SetDragPosition(SelectionPosition(invalidPosition
));
2625 sciThis
->errorStatus
= SC_STATUS_FAILURE
;
2629 int ScintillaGTK::TimeOut(ScintillaGTK
*sciThis
) {
2634 int ScintillaGTK::IdleCallback(ScintillaGTK
*sciThis
) {
2635 // Idler will be automatically stoped, if there is nothing
2636 // to do while idle.
2637 bool ret
= sciThis
->Idle();
2639 // FIXME: This will remove the idler from GTK, we don't want to
2640 // remove it as it is removed automatically when this function
2641 // returns false (although, it should be harmless).
2642 sciThis
->SetIdle(false);
2647 void ScintillaGTK::PopUpCB(ScintillaGTK
*sciThis
, guint action
, GtkWidget
*) {
2649 sciThis
->Command(action
);
2653 gint
ScintillaGTK::PressCT(GtkWidget
*widget
, GdkEventButton
*event
, ScintillaGTK
*sciThis
) {
2655 if (event
->window
!= widget
->window
)
2657 if (event
->type
!= GDK_BUTTON_PRESS
)
2660 pt
.x
= int(event
->x
);
2661 pt
.y
= int(event
->y
);
2662 sciThis
->ct
.MouseClick(pt
);
2663 sciThis
->CallTipClick();
2666 #if GTK_MAJOR_VERSION >= 2
2673 gint
ScintillaGTK::ExposeCT(GtkWidget
*widget
, GdkEventExpose
* /*ose*/, CallTip
*ctip
) {
2675 Surface
*surfaceWindow
= Surface::Allocate();
2676 if (surfaceWindow
) {
2677 surfaceWindow
->Init(widget
->window
, widget
);
2678 surfaceWindow
->SetUnicodeMode(SC_CP_UTF8
== ctip
->codePage
);
2679 surfaceWindow
->SetDBCSMode(ctip
->codePage
);
2680 ctip
->PaintCT(surfaceWindow
);
2681 surfaceWindow
->Release();
2682 delete surfaceWindow
;
2685 // No pointer back to Scintilla to save status
2690 sptr_t
ScintillaGTK::DirectFunction(
2691 ScintillaGTK
*sciThis
, unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
2692 return sciThis
->WndProc(iMessage
, wParam
, lParam
);
2695 sptr_t
scintilla_send_message(ScintillaObject
*sci
, unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
2696 ScintillaGTK
*psci
= reinterpret_cast<ScintillaGTK
*>(sci
->pscin
);
2697 return psci
->WndProc(iMessage
, wParam
, lParam
);
2700 static void scintilla_class_init(ScintillaClass
*klass
);
2701 static void scintilla_init(ScintillaObject
*sci
);
2703 extern void Platform_Initialise();
2704 extern void Platform_Finalise();
2706 #if GLIB_MAJOR_VERSION < 2
2707 GtkType
scintilla_get_type() {
2708 static GtkType scintilla_type
= 0;
2711 if (!scintilla_type
) {
2712 Platform_Initialise();
2713 static GtkTypeInfo scintilla_info
= {
2715 sizeof (ScintillaObject
),
2716 sizeof (ScintillaClass
),
2717 (GtkClassInitFunc
) scintilla_class_init
,
2718 (GtkObjectInitFunc
) scintilla_init
,
2724 scintilla_type
= gtk_type_unique(gtk_container_get_type(), &scintilla_info
);
2729 return scintilla_type
;
2732 GType
scintilla_get_type() {
2733 static GType scintilla_type
= 0;
2736 if (!scintilla_type
) {
2737 scintilla_type
= g_type_from_name("Scintilla");
2738 if (!scintilla_type
) {
2739 static GTypeInfo scintilla_info
= {
2740 (guint16
) sizeof (ScintillaClass
),
2741 NULL
, //(GBaseInitFunc)
2742 NULL
, //(GBaseFinalizeFunc)
2743 (GClassInitFunc
) scintilla_class_init
,
2744 NULL
, //(GClassFinalizeFunc)
2745 NULL
, //gconstpointer data
2746 (guint16
) sizeof (ScintillaObject
),
2748 (GInstanceInitFunc
) scintilla_init
,
2749 NULL
//(GTypeValueTable*)
2752 scintilla_type
= g_type_register_static(
2753 GTK_TYPE_CONTAINER
, "Scintilla", &scintilla_info
, (GTypeFlags
) 0);
2759 return scintilla_type
;
2763 void ScintillaGTK::ClassInit(OBJECT_CLASS
* object_class
, GtkWidgetClass
*widget_class
, GtkContainerClass
*container_class
) {
2764 #if GLIB_MAJOR_VERSION >= 2
2765 Platform_Initialise();
2767 atomClipboard
= gdk_atom_intern("CLIPBOARD", FALSE
);
2768 atomUTF8
= gdk_atom_intern("UTF8_STRING", FALSE
);
2769 atomString
= GDK_SELECTION_TYPE_STRING
;
2770 atomUriList
= gdk_atom_intern("text/uri-list", FALSE
);
2771 atomDROPFILES_DND
= gdk_atom_intern("DROPFILES_DND", FALSE
);
2773 // Define default signal handlers for the class: Could move more
2774 // of the signal handlers here (those that currently attached to wDraw
2775 // in Initialise() may require coordinate translation?)
2777 #if GLIB_MAJOR_VERSION < 2
2778 object_class
->destroy
= Destroy
;
2780 object_class
->finalize
= Destroy
;
2782 widget_class
->size_request
= SizeRequest
;
2783 widget_class
->size_allocate
= SizeAllocate
;
2784 widget_class
->expose_event
= ExposeMain
;
2785 #if GTK_MAJOR_VERSION < 2
2786 widget_class
->draw
= Draw
;
2788 widget_class
->motion_notify_event
= Motion
;
2789 widget_class
->button_press_event
= Press
;
2790 widget_class
->button_release_event
= MouseRelease
;
2791 #if PLAT_GTK_WIN32 || (GTK_MAJOR_VERSION >= 2)
2792 widget_class
->scroll_event
= ScrollEvent
;
2794 widget_class
->key_press_event
= KeyPress
;
2795 widget_class
->key_release_event
= KeyRelease
;
2796 widget_class
->focus_in_event
= FocusIn
;
2797 widget_class
->focus_out_event
= FocusOut
;
2798 widget_class
->selection_received
= SelectionReceived
;
2799 widget_class
->selection_get
= SelectionGet
;
2800 widget_class
->selection_clear_event
= SelectionClear
;
2801 #if GTK_MAJOR_VERSION < 2
2802 widget_class
->selection_notify_event
= SelectionNotify
;
2805 widget_class
->drag_data_received
= DragDataReceived
;
2806 widget_class
->drag_motion
= DragMotion
;
2807 widget_class
->drag_leave
= DragLeave
;
2808 widget_class
->drag_end
= DragEnd
;
2809 widget_class
->drag_drop
= Drop
;
2810 widget_class
->drag_data_get
= DragDataGet
;
2812 widget_class
->realize
= Realize
;
2813 widget_class
->unrealize
= UnRealize
;
2814 widget_class
->map
= Map
;
2815 widget_class
->unmap
= UnMap
;
2817 container_class
->forall
= MainForAll
;
2820 #if GLIB_MAJOR_VERSION < 2
2821 #define GTK_CLASS_TYPE(c) (c->type)
2822 #define SIG_MARSHAL gtk_marshal_NONE__INT_POINTER
2823 #define MARSHAL_ARGUMENTS GTK_TYPE_INT, GTK_TYPE_POINTER
2825 #define SIG_MARSHAL scintilla_marshal_NONE__INT_POINTER
2826 #define MARSHAL_ARGUMENTS G_TYPE_INT, G_TYPE_POINTER
2829 static void scintilla_class_init(ScintillaClass
*klass
) {
2831 OBJECT_CLASS
*object_class
= (OBJECT_CLASS
*) klass
;
2832 GtkWidgetClass
*widget_class
= (GtkWidgetClass
*) klass
;
2833 GtkContainerClass
*container_class
= (GtkContainerClass
*) klass
;
2835 #if GLIB_MAJOR_VERSION < 2
2836 parent_class
= (GtkWidgetClass
*) gtk_type_class(gtk_container_get_type());
2838 scintilla_signals
[COMMAND_SIGNAL
] = gtk_signal_new(
2841 GTK_CLASS_TYPE(object_class
),
2842 GTK_SIGNAL_OFFSET(ScintillaClass
, command
),
2845 2, MARSHAL_ARGUMENTS
);
2847 scintilla_signals
[NOTIFY_SIGNAL
] = gtk_signal_new(
2850 GTK_CLASS_TYPE(object_class
),
2851 GTK_SIGNAL_OFFSET(ScintillaClass
, notify
),
2854 2, MARSHAL_ARGUMENTS
);
2855 gtk_object_class_add_signals(object_class
,
2856 reinterpret_cast<unsigned int *>(scintilla_signals
), LAST_SIGNAL
);
2858 GSignalFlags sigflags
= GSignalFlags(G_SIGNAL_ACTION
| G_SIGNAL_RUN_LAST
);
2859 scintilla_signals
[COMMAND_SIGNAL
] = g_signal_new(
2861 G_TYPE_FROM_CLASS(object_class
),
2863 G_STRUCT_OFFSET(ScintillaClass
, command
),
2864 NULL
, //(GSignalAccumulator)
2868 2, MARSHAL_ARGUMENTS
);
2870 scintilla_signals
[NOTIFY_SIGNAL
] = g_signal_new(
2872 G_TYPE_FROM_CLASS(object_class
),
2874 G_STRUCT_OFFSET(ScintillaClass
, notify
),
2879 2, MARSHAL_ARGUMENTS
);
2881 klass
->command
= NULL
;
2882 klass
->notify
= NULL
;
2884 ScintillaGTK::ClassInit(object_class
, widget_class
, container_class
);
2889 static void scintilla_init(ScintillaObject
*sci
) {
2891 GTK_WIDGET_SET_FLAGS(sci
, GTK_CAN_FOCUS
);
2892 sci
->pscin
= new ScintillaGTK(sci
);
2897 GtkWidget
* scintilla_new() {
2898 #if GLIB_MAJOR_VERSION < 2
2899 return GTK_WIDGET(gtk_type_new(scintilla_get_type()));
2901 return GTK_WIDGET(g_object_new(scintilla_get_type(), NULL
));
2905 void scintilla_set_id(ScintillaObject
*sci
, uptr_t id
) {
2906 ScintillaGTK
*psci
= reinterpret_cast<ScintillaGTK
*>(sci
->pscin
);
2910 void scintilla_release_resources(void) {
2912 Platform_Finalise();