aboutsummaryrefslogtreecommitdiffhomepage
path: root/gtk/ScintillaGTK.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'gtk/ScintillaGTK.cxx')
-rw-r--r--gtk/ScintillaGTK.cxx1003
1 files changed, 1003 insertions, 0 deletions
diff --git a/gtk/ScintillaGTK.cxx b/gtk/ScintillaGTK.cxx
new file mode 100644
index 000000000..266492fc3
--- /dev/null
+++ b/gtk/ScintillaGTK.cxx
@@ -0,0 +1,1003 @@
+// Scintilla source code edit control
+// ScintillaGTK.cxx - GTK+ specific subclass of ScintillaBase
+// Copyright 1998-2000 by Neil Hodgson <neilh@scintilla.org>
+// The License.txt file describes the conditions under which this software may be distributed.
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "Platform.h"
+
+#include "Scintilla.h"
+#ifdef SCI_LEXER
+#include "SciLexer.h"
+#include "PropSet.h"
+#include "Accessor.h"
+#include "KeyWords.h"
+#endif
+#include "ContractionState.h"
+#include "SVector.h"
+#include "CellBuffer.h"
+#include "CallTip.h"
+#include "KeyMap.h"
+#include "Indicator.h"
+#include "LineMarker.h"
+#include "Style.h"
+#include "AutoComplete.h"
+#include "ViewStyle.h"
+#include "Document.h"
+#include "Editor.h"
+#include "ScintillaBase.h"
+
+#include "gtk/gtksignal.h"
+
+class ScintillaGTK : public ScintillaBase {
+ _ScintillaObject *sci;
+ Window scrollbarv;
+ Window scrollbarh;
+ GtkObject *adjustmentv;
+ GtkObject *adjustmenth;
+ char *pasteBuffer;
+ bool pasteBufferIsRectangular;
+ GdkEventButton evbtn;
+ bool capturedMouse;
+ bool dragWasDropped;
+
+ static GdkAtom clipboard_atom;
+
+public:
+ ScintillaGTK(_ScintillaObject *sci_);
+ virtual ~ScintillaGTK();
+
+private:
+ virtual void Initialise();
+ virtual void Finalise();
+ virtual void StartDrag();
+public: // Public for scintilla_send_message
+ virtual LRESULT WndProc(UINT iMessage,WPARAM wParam,LPARAM lParam);
+private:
+ virtual LRESULT DefWndProc(UINT iMessage,WPARAM wParam,LPARAM lParam);
+ virtual void SetTicking(bool on);
+ virtual void SetMouseCapture(bool on);
+ virtual bool HaveMouseCapture();
+ void FullPaint();
+ void SyncPaint(PRectangle rc);
+ virtual void ScrollText(int linesToMove);
+ virtual void SetVerticalScrollPos();
+ virtual void SetHorizontalScrollPos();
+ virtual bool ModifyScrollBars(int nMax, int nPage);
+ virtual void NotifyChange();
+ virtual void NotifyFocus(bool focus);
+ virtual void NotifyParent(SCNotification scn);
+ void NotifyKey(int key, int modifiers);
+ virtual int KeyDefault(int key, int modifiers);
+ virtual void Copy();
+ virtual void Paste();
+ virtual void CreateCallTipWindow(PRectangle rc);
+ virtual void AddToPopUp(const char *label, int cmd=0, bool enabled=true);
+ virtual void ClaimSelection();
+ void ReceivedSelection(GtkSelectionData *selection_data);
+ void ReceivedDrop(GtkSelectionData *selection_data);
+ void GetSelection(GtkSelectionData *selection_data, guint info, char *text, bool isRectangular);
+ void Resize(int width, int height);
+
+ // Callback functions
+ static gint FocusIn(GtkWidget *widget, GdkEventFocus *event, ScintillaGTK *sciThis);
+ static gint FocusOut(GtkWidget *widget, GdkEventFocus *event, ScintillaGTK *sciThis);
+ static gint Expose(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis);
+ static void ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis);
+ static void ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis);
+ static gint MoveResize(GtkWidget *widget, GtkAllocation *allocation, ScintillaGTK *sciThis);
+ static gint Press(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis);
+ static gint MouseRelease(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis);
+ static gint Motion(GtkWidget *widget, GdkEventMotion *event, ScintillaGTK *sciThis);
+ static gint KeyPress(GtkWidget *widget, GdkEventKey *event, ScintillaGTK *sciThis);
+ static gint KeyRelease(GtkWidget *widget, GdkEventKey *event, ScintillaGTK *sciThis);
+ static gint DestroyWindow(GtkWidget *widget, ScintillaGTK *sciThis);
+ static void SelectionReceived(GtkWidget *widget, GtkSelectionData *selection_data,
+ guint time, ScintillaGTK *sciThis);
+ static void SelectionGet(GtkWidget *widget, GtkSelectionData *selection_data,
+ guint info, guint time, ScintillaGTK *sciThis);
+ static void DragBegin(GtkWidget *widget, GdkDragContext *context,
+ ScintillaGTK *sciThis);
+ static gboolean DragMotion(GtkWidget *widget, GdkDragContext *context,
+ gint x, gint y, guint time, ScintillaGTK *sciThis);
+ static void DragLeave(GtkWidget *widget, GdkDragContext *context,
+ guint time, ScintillaGTK *sciThis);
+ static void DragEnd(GtkWidget *widget, GdkDragContext *context,
+ ScintillaGTK *sciThis);
+ static gboolean Drop(GtkWidget *widget, GdkDragContext *context,
+ gint x, gint y, guint time, ScintillaGTK *sciThis);
+ static void DragDataReceived(GtkWidget *widget, GdkDragContext *context,
+ gint x, gint y, GtkSelectionData *selection_data, guint info, guint time,
+ ScintillaGTK *sciThis);
+ static void DragDataGet(GtkWidget *widget, GdkDragContext *context,
+ GtkSelectionData *selection_data, guint info, guint time, ScintillaGTK *sciThis);
+ static gint TimeOut(ScintillaGTK *sciThis);
+ static void PopUpCB(ScintillaGTK *sciThis, guint action, GtkWidget *widget);
+ static gint ExposeCT(GtkWidget *widget, GdkEventExpose *ose, CallTip *ct);
+};
+
+enum {
+ COMMAND_SIGNAL,
+ NOTIFY_SIGNAL,
+ LAST_SIGNAL
+};
+
+static gint scintilla_signals[LAST_SIGNAL] = { 0 };
+
+GdkAtom ScintillaGTK::clipboard_atom = GDK_NONE;
+
+enum {
+ TARGET_STRING,
+ TARGET_TEXT,
+ TARGET_COMPOUND_TEXT
+};
+
+ScintillaGTK::ScintillaGTK(_ScintillaObject *sci_) :
+ adjustmentv(0), adjustmenth(0),
+ pasteBuffer(0), pasteBufferIsRectangular(false),
+ capturedMouse(false), dragWasDropped(false) {
+ sci = sci_;
+ wMain = GTK_WIDGET(sci);
+
+ Initialise();
+}
+
+ScintillaGTK::~ScintillaGTK() {
+}
+
+gint ScintillaGTK::FocusIn(GtkWidget *widget, GdkEventFocus *event, ScintillaGTK *sciThis) {
+ //Platform::DebugPrintf("ScintillaGTK::focus in %x\n", sciThis);
+ GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
+ sciThis->NotifyFocus(true);
+ sciThis->ShowCaretAtCurrentPosition();
+ return FALSE;
+}
+
+gint ScintillaGTK::FocusOut(GtkWidget *widget, GdkEventFocus *event, ScintillaGTK *sciThis) {
+ //Platform::DebugPrintf("ScintillaGTK::focus out %x\n", sciThis);
+ GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
+ sciThis->NotifyFocus(false);
+ sciThis->DropCaret();
+ return FALSE;
+}
+
+void ScintillaGTK::Initialise() {
+ pasteBuffer = 0;
+ pasteBufferIsRectangular = false;
+
+ GTK_WIDGET_SET_FLAGS(wMain.GetID(), GTK_CAN_FOCUS);
+ GTK_WIDGET_SET_FLAGS(GTK_WIDGET(wMain.GetID()), GTK_SENSITIVE);
+ gtk_signal_connect(GTK_OBJECT(wMain.GetID()), "size_allocate",
+ GTK_SIGNAL_FUNC(MoveResize), this);
+ gtk_widget_set_events (wMain.GetID(),
+ GDK_KEY_PRESS_MASK
+ | GDK_KEY_RELEASE_MASK
+ | GDK_FOCUS_CHANGE_MASK);
+ // Using "after" connect to avoid main window using cursor keys
+ // to move focus.
+ //gtk_signal_connect(GTK_OBJECT(wMain), "key_press_event",
+ // GtkSignalFunc(key_event), this);
+ gtk_signal_connect_after(GTK_OBJECT(wMain.GetID()), "key_press_event",
+ GtkSignalFunc(KeyPress), this);
+
+ gtk_signal_connect(GTK_OBJECT(wMain.GetID()), "key_release_event",
+ GtkSignalFunc(KeyRelease), this);
+ gtk_signal_connect(GTK_OBJECT(wMain.GetID()), "focus_in_event",
+ GtkSignalFunc(FocusIn), this);
+ gtk_signal_connect(GTK_OBJECT(wMain.GetID()), "focus_out_event",
+ GtkSignalFunc(FocusOut), this);
+ gtk_signal_connect(GTK_OBJECT(wMain.GetID()), "destroy",
+ GtkSignalFunc(DestroyWindow), this);
+
+ wDraw = gtk_drawing_area_new();
+ gtk_signal_connect(GTK_OBJECT(wDraw.GetID()), "expose_event",
+ GtkSignalFunc(Expose), this);
+ gtk_signal_connect(GTK_OBJECT(wDraw.GetID()), "motion_notify_event",
+ GtkSignalFunc(Motion), this);
+ gtk_signal_connect(GTK_OBJECT(wDraw.GetID()), "button_press_event",
+ GtkSignalFunc(Press), this);
+ gtk_signal_connect(GTK_OBJECT(wDraw.GetID()), "button_release_event",
+ GtkSignalFunc(MouseRelease), this);
+ gtk_signal_connect(GTK_OBJECT(wDraw.GetID()), "selection_received",
+ GtkSignalFunc(SelectionReceived), this);
+ gtk_signal_connect(GTK_OBJECT(wDraw.GetID()), "selection_get",
+ GtkSignalFunc(SelectionGet), this);
+
+ gtk_widget_set_events(wDraw.GetID(),
+ GDK_EXPOSURE_MASK
+ | GDK_LEAVE_NOTIFY_MASK
+ | GDK_BUTTON_PRESS_MASK
+ | GDK_BUTTON_RELEASE_MASK
+ | GDK_POINTER_MOTION_MASK
+ | GDK_POINTER_MOTION_HINT_MASK
+ );
+
+ gtk_drawing_area_size(GTK_DRAWING_AREA(wDraw.GetID()), 400, 400);
+ gtk_fixed_put(GTK_FIXED(sci), wDraw.GetID(), 0, 0);
+
+ adjustmentv = gtk_adjustment_new(0.0, 0.0, 201.0, 1.0, 20.0, 20.0);
+ scrollbarv = gtk_vscrollbar_new(GTK_ADJUSTMENT(adjustmentv));
+ GTK_WIDGET_UNSET_FLAGS(scrollbarv.GetID(), GTK_CAN_FOCUS);
+ gtk_signal_connect(GTK_OBJECT(adjustmentv), "value_changed",
+ GTK_SIGNAL_FUNC(ScrollSignal), this);
+ gtk_fixed_put(GTK_FIXED(sci), scrollbarv.GetID(), 0, 0);
+
+ adjustmenth = gtk_adjustment_new(0.0, 0.0, 101.0, 1.0, 20.0, 20.0);
+ scrollbarh = gtk_hscrollbar_new(GTK_ADJUSTMENT(adjustmenth));
+ GTK_WIDGET_UNSET_FLAGS(scrollbarh.GetID(), GTK_CAN_FOCUS);
+ gtk_signal_connect(GTK_OBJECT(adjustmenth), "value_changed",
+ GTK_SIGNAL_FUNC(ScrollHSignal), this);
+ gtk_fixed_put(GTK_FIXED(sci), scrollbarh.GetID(), 0, 0);
+
+ gtk_widget_grab_focus(wMain.GetID());
+
+ static const GtkTargetEntry targets[] = {
+ { "STRING", 0, TARGET_STRING },
+ { "TEXT", 0, TARGET_TEXT },
+ { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
+ };
+ static const gint n_targets = sizeof(targets) / sizeof(targets[0]);
+
+ gtk_selection_add_targets(GTK_WIDGET(wDraw.GetID()), GDK_SELECTION_PRIMARY,
+ targets, n_targets);
+
+ if (!clipboard_atom)
+ clipboard_atom = gdk_atom_intern("CLIPBOARD", FALSE);
+
+ gtk_selection_add_targets(GTK_WIDGET(wDraw.GetID()), clipboard_atom,
+ targets, n_targets);
+
+ gtk_drag_dest_set(GTK_WIDGET(wDraw.GetID()),
+ GTK_DEST_DEFAULT_ALL, targets, n_targets,
+ static_cast<GdkDragAction>(GDK_ACTION_COPY|GDK_ACTION_MOVE));
+ gtk_signal_connect(GTK_OBJECT(wDraw.GetID()),
+ "drag_data_received",
+ GTK_SIGNAL_FUNC(DragDataReceived),
+ this);
+ gtk_signal_connect(GTK_OBJECT(wDraw.GetID()),
+ "drag_motion",
+ GTK_SIGNAL_FUNC(DragMotion),
+ this);
+ gtk_signal_connect(GTK_OBJECT(wDraw.GetID()),
+ "drag_leave",
+ GTK_SIGNAL_FUNC(DragLeave),
+ this);
+ gtk_signal_connect(GTK_OBJECT(wDraw.GetID()),
+ "drag_end",
+ GTK_SIGNAL_FUNC(DragEnd),
+ this);
+ gtk_signal_connect(GTK_OBJECT(wDraw.GetID()),
+ "drag_drop",
+ GTK_SIGNAL_FUNC(Drop),
+ this);
+ // gtk_drag_source_set not used as it stops dragging over text to select it
+ //gtk_drag_source_set(GTK_WIDGET(wDraw.GetID()),
+ // static_cast<GdkModifierType>(GDK_BUTTON1_MASK|GDK_BUTTON3_MASK),
+ // targets, n_targets,
+ // GDK_ACTION_COPY);
+ gtk_signal_connect(GTK_OBJECT(wDraw.GetID()),
+ "drag_data_get",
+ GTK_SIGNAL_FUNC(DragDataGet),
+ this);
+
+ SetTicking(true);
+}
+
+void ScintillaGTK::Finalise() {
+ SetTicking(false);
+ ScintillaBase::Finalise();
+}
+
+void ScintillaGTK::StartDrag() {
+ dragWasDropped = false;
+ static const GtkTargetEntry targets[] = {
+ { "STRING", 0, TARGET_STRING },
+ { "TEXT", 0, TARGET_TEXT },
+ { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
+ };
+ static const gint n_targets = sizeof(targets) / sizeof(targets[0]);
+ GtkTargetList *tl = gtk_target_list_new(targets, n_targets);
+ gtk_drag_begin(GTK_WIDGET(wDraw.GetID()),
+ tl,
+ static_cast<GdkDragAction>(GDK_ACTION_COPY|GDK_ACTION_MOVE),
+ evbtn.button,
+ reinterpret_cast<GdkEvent *>(&evbtn));
+}
+
+LRESULT ScintillaGTK::WndProc(UINT iMessage,WPARAM wParam,LPARAM lParam) {
+ switch (iMessage) {
+
+ case SCI_GRABFOCUS:
+ gtk_widget_grab_focus(wMain.GetID());
+ break;
+
+ default:
+ return ScintillaBase::WndProc(iMessage,wParam,lParam);
+ }
+ return 0l;
+}
+
+LRESULT ScintillaGTK::DefWndProc(UINT, WPARAM, LPARAM) {
+ return 0;
+}
+
+void ScintillaGTK::SetTicking(bool on) {
+ if (timer.ticking != on) {
+ timer.ticking = on;
+ if (timer.ticking) {
+ timer.tickerID = gtk_timeout_add(timer.tickSize, TimeOut, this);
+ } else {
+ gtk_timeout_remove(timer.tickerID);
+ }
+ }
+ timer.ticksToWait = caret.period;
+}
+
+void ScintillaGTK::SetMouseCapture(bool on) {
+ if (on) {
+ gtk_grab_add(GTK_WIDGET(wDraw.GetID()));
+ } else {
+ gtk_grab_remove(GTK_WIDGET(wDraw.GetID()));
+ }
+ capturedMouse = on;
+}
+
+bool ScintillaGTK::HaveMouseCapture() {
+ return capturedMouse;
+}
+
+// Redraw all of text area. This paint will not be abandoned.
+void ScintillaGTK::FullPaint() {
+ paintState = painting;
+ rcPaint = GetTextRectangle();
+ paintingAllText = true;
+ Surface sw;
+ sw.Init((wDraw.GetID())->window);
+ Paint(&sw, rcPaint);
+ sw.Release();
+ paintState = notPainting;
+}
+
+// Synchronously paint a rectangle of the window.
+void ScintillaGTK::SyncPaint(PRectangle rc) {
+ paintState = painting;
+ rcPaint = rc;
+ PRectangle rcText = GetTextRectangle();
+ paintingAllText = rcPaint.Contains(rcText);
+ Surface sw;
+ sw.Init((wDraw.GetID())->window);
+ Paint(&sw, rc);
+ sw.Release();
+ if (paintState == paintAbandoned) {
+ // Painting area was insufficient to cover new styling or brace highlight positions
+ FullPaint();
+ }
+ paintState = notPainting;
+}
+
+void ScintillaGTK::ScrollText(int linesToMove) {
+ //Platform::DebugPrintf("ScintillaGTK::ScrollText %d\n", linesToMove);
+ PRectangle rc = GetClientRectangle();
+ int diff = vs.lineHeight * -linesToMove;
+ WindowID wi = wDraw.GetID();
+ GdkGC *gc = gdk_gc_new(wi->window);
+
+ // Redraw exposed bit : scrolling upwards
+ if (diff > 0) {
+ gdk_draw_pixmap(wi->window,
+ gc, wi->window,
+ 0, diff,
+ 0, 0,
+ rc.Width(), rc.Height() - diff);
+ // RedrawRect(PRectangle(0,rc.Height() - diff -
+ // vs.lineHeight, rc.Width(), rc.Height()));
+ gdk_gc_unref(gc);
+ SyncPaint(PRectangle(0,rc.Height() - diff -
+ vs.lineHeight, rc.Width(), rc.Height()));
+
+ // Redraw exposed bit : scrolling downwards
+ } else {
+ gdk_draw_pixmap(wi->window,
+ gc, wi->window,
+ 0, 0,
+ 0, -diff,
+ rc.Width(), rc.Height() - diff);
+ gdk_gc_unref(gc);
+ // RedrawRect(PRectangle(0,0,rc.Width(),-diff + vs.lineHeight));
+ SyncPaint(PRectangle(0,0,rc.Width(),-diff + vs.lineHeight));
+ }
+}
+
+
+void ScintillaGTK::SetVerticalScrollPos() {
+ gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmentv), topLine);
+}
+
+void ScintillaGTK::SetHorizontalScrollPos() {
+ gtk_adjustment_set_value(GTK_ADJUSTMENT(adjustmenth), xOffset / 2);
+}
+
+bool ScintillaGTK::ModifyScrollBars(int nMax, int nPage) {
+ bool modified = false;
+ int pageScroll = LinesToScroll();
+
+ if (GTK_ADJUSTMENT(adjustmentv)->upper != (nMax+1) ||
+ GTK_ADJUSTMENT(adjustmentv)->page_size != nPage ||
+ GTK_ADJUSTMENT(adjustmentv)->page_increment != pageScroll) {
+ GTK_ADJUSTMENT(adjustmentv)->upper = nMax + 1;
+ GTK_ADJUSTMENT(adjustmentv)->page_size = nPage;
+ GTK_ADJUSTMENT(adjustmentv)->page_increment = pageScroll;
+ gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmentv));
+ modified = true;
+ }
+
+ if (GTK_ADJUSTMENT(adjustmenth)->upper != 2000 ||
+ GTK_ADJUSTMENT(adjustmenth)->page_size != 200) {
+ GTK_ADJUSTMENT(adjustmenth)->upper = 2000;
+ GTK_ADJUSTMENT(adjustmenth)->page_size = 200;
+ gtk_adjustment_changed(GTK_ADJUSTMENT(adjustmenth));
+ modified = true;
+ }
+ return modified;
+}
+
+void ScintillaGTK::NotifyChange() {
+ gtk_signal_emit(GTK_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL],
+ MAKELONG(ctrlID, EN_CHANGE), wMain.GetID());
+}
+
+void ScintillaGTK::NotifyFocus(bool focus) {
+ gtk_signal_emit(GTK_OBJECT(sci), scintilla_signals[COMMAND_SIGNAL],
+ MAKELONG(ctrlID, focus ? EN_SETFOCUS : EN_KILLFOCUS), wMain.GetID());
+}
+
+void ScintillaGTK::NotifyParent(SCNotification scn) {
+ scn.nmhdr.hwndFrom = wMain.GetID();
+ scn.nmhdr.idFrom = ctrlID;
+ gtk_signal_emit(GTK_OBJECT(sci), scintilla_signals[NOTIFY_SIGNAL],
+ ctrlID, &scn);
+}
+
+void ScintillaGTK::NotifyKey(int key, int modifiers) {
+ SCNotification scn;
+ scn.nmhdr.code = SCN_KEY;
+ scn.ch = key;
+ scn.modifiers = modifiers;
+
+ NotifyParent(scn);
+}
+
+int ScintillaGTK::KeyDefault(int key, int modifiers) {
+ if (!(modifiers & SCI_CTRL) && !(modifiers & SCI_ALT) && (key < 128)) {
+ AddChar(key);
+ } else {
+ // Pass up to container in case it is an accelerator
+ NotifyKey(key, modifiers);
+ }
+ //Platform::DebugPrintf("SK-key: %d %x %x\n",event->keyval, event->state, GTK_WIDGET_FLAGS(widget));
+ return 1;
+}
+
+void ScintillaGTK::Copy() {
+ if (currentPos != anchor) {
+ delete []pasteBuffer;
+ pasteBuffer = CopySelectionRange();
+ pasteBufferIsRectangular = selType == selRectangle;
+ gtk_selection_owner_set(GTK_WIDGET(wDraw.GetID()),
+ clipboard_atom,
+ GDK_CURRENT_TIME);
+ }
+}
+
+void ScintillaGTK::Paste() {
+ gtk_selection_convert(GTK_WIDGET(wDraw.GetID()),
+ clipboard_atom,
+ gdk_atom_intern("STRING", FALSE), GDK_CURRENT_TIME);
+}
+
+void ScintillaGTK::CreateCallTipWindow(PRectangle rc) {
+ ct.wCallTip = gtk_window_new(GTK_WINDOW_POPUP);
+ ct.wDraw = gtk_drawing_area_new();
+ gtk_container_add(GTK_CONTAINER(ct.wCallTip.GetID()), ct.wDraw.GetID());
+ gtk_signal_connect(GTK_OBJECT(ct.wDraw.GetID()), "expose_event",
+ GtkSignalFunc(ScintillaGTK::ExposeCT), &ct);
+ gtk_widget_set_events(ct.wDraw.GetID(), GDK_EXPOSURE_MASK);
+ gtk_drawing_area_size(GTK_DRAWING_AREA(ct.wDraw.GetID()),
+ rc.Width(), rc.Height());
+ ct.wDraw.Show();
+}
+
+void ScintillaGTK::AddToPopUp(const char *label, int cmd, bool enabled) {
+ char fulllabel[200];
+ strcpy(fulllabel, "/");
+ strcat(fulllabel, label);
+ GtkItemFactoryEntry itemEntry = {
+ fulllabel, NULL,
+ GTK_SIGNAL_FUNC(ScintillaGTK::PopUpCB), cmd,
+ const_cast<gchar *>(label[0] ? "<Item>" : "<Separator>")
+ };
+ gtk_item_factory_create_item(GTK_ITEM_FACTORY(popup.GetID()),
+ &itemEntry, this, 1);
+ if (cmd) {
+ GtkWidget *item = gtk_item_factory_get_widget_by_action(
+ popup.GetID(), cmd);
+ if (item)
+ gtk_widget_set_sensitive(item, enabled);
+ }
+}
+
+void ScintillaGTK::ClaimSelection() {
+ // X Windows has a 'primary selection' as well as the clipboard.
+ // Whenever the user selects some text, we become the primary selection
+ if (currentPos != anchor) {
+ gtk_selection_owner_set(GTK_WIDGET(wDraw.GetID()),
+ GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
+ } else if (gdk_selection_owner_get(GDK_SELECTION_PRIMARY) ==
+ GTK_WIDGET(wDraw.GetID())->window) {
+ gtk_selection_owner_set(NULL, GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
+ }
+}
+
+void ScintillaGTK::ReceivedSelection(GtkSelectionData *selection_data) {
+ if (selection_data->type == GDK_TARGET_STRING) {
+//Platform::DebugPrintf("Received String Selection %x %d\n", selection_data->selection, selection_data->length);
+ if (((selection_data->selection == clipboard_atom)||
+ (selection_data->selection == GDK_SELECTION_PRIMARY)) &&
+ (selection_data->length > 0)) {
+ //if (selection_data->length > 0) {
+ char *ptr = reinterpret_cast<char *>(selection_data->data);
+ unsigned int len = selection_data->length;
+ for (unsigned int i=0; i<selection_data->length; i++) {
+ if ((len == selection_data->length) && (0 == ptr[i]))
+ len = i;
+ }
+ pdoc->BeginUndoAction();
+ int selStart = SelectionStart();
+ ClearSelection();
+ // Check for "\n\0" ending to string indicating that selection is rectangular
+ bool isRectangular = ((selection_data->length > 1) &&
+ (ptr[selection_data->length-1] == 0 && ptr[selection_data->length-2] == '\n'));
+ if (isRectangular) {
+ PasteRectangular(selStart, ptr, len);
+ } else {
+ pdoc->InsertString(currentPos, ptr, len);
+ SetEmptySelection(currentPos + len);
+ }
+ pdoc->EndUndoAction();
+ }
+ }
+ Redraw();
+}
+
+void ScintillaGTK::ReceivedDrop(GtkSelectionData *selection_data) {
+ dragWasDropped = true;
+ if (selection_data->type == GDK_TARGET_STRING) {
+ if (selection_data->length > 0) {
+ char *ptr = reinterpret_cast<char *>(selection_data->data);
+ // 3rd argument is false because the deletion of the moved data is handle by GetSelection
+ bool isRectangular = ((selection_data->length > 1) &&
+ (ptr[selection_data->length-1] == 0 && ptr[selection_data->length-2] == '\n'));
+ DropAt(posDrop, ptr, false, isRectangular);
+ }
+ }
+ Redraw();
+}
+
+void ScintillaGTK::GetSelection(GtkSelectionData *selection_data, guint info, char *text, bool isRectangular) {
+//Platform::DebugPrintf("GetSelection %d\n", info);
+ char *selBuffer = text;
+ if (selection_data->selection == GDK_SELECTION_PRIMARY) {
+//Platform::DebugPrintf("GetSelection PRIMARY\n");
+ selBuffer = CopySelectionRange();
+ }
+
+ if (info == TARGET_STRING) {
+ int len = strlen(selBuffer);
+ // Here is a somewhat evil kludge.
+ // As I can not work out how to store data on the clipboard in multiple formats
+ // and need some way to mark the clipping as being stream or rectangular,
+ // the terminating \0 is included in the length for rectangular clippings.
+ // All other tested aplications behave benignly by ignoring the \0.
+ if (isRectangular)
+ len++;
+//Platform::DebugPrintf("GetSelection STRING %d %s %d\n", selection_data->type,
+//isRectangular ? "rect" : "stream", len);
+ gtk_selection_data_set(selection_data, GDK_SELECTION_TYPE_STRING,
+ 8, reinterpret_cast<unsigned char *>(selBuffer),
+ len);
+ } else if ((info == TARGET_TEXT) || (info == TARGET_COMPOUND_TEXT)) {
+//Platform::DebugPrintf("GetSelection TEXT\n");
+//if (info == TARGET_COMPOUND_TEXT)
+//Platform::DebugPrintf("GetSelection COMPOUND\n");
+ guchar *text;
+ GdkAtom encoding;
+ gint format;
+ gint new_length;
+
+ gdk_string_to_compound_text(reinterpret_cast<char *>(selBuffer),
+ &encoding, &format, &text, &new_length);
+ gtk_selection_data_set(selection_data, encoding, format, text, new_length);
+ gdk_free_compound_text(text);
+ }
+
+//Platform::DebugPrintf("GetSelection FREE\n");
+ if (selection_data->selection == GDK_SELECTION_PRIMARY) {
+ delete []selBuffer;
+ }
+//Platform::DebugPrintf("GetSelection END\n");
+}
+
+void ScintillaGTK::Resize(int width, int height) {
+ //Platform::DebugPrintf("Resize %d %d\n", width, height);
+ DropGraphics();
+ GtkAllocation alloc;
+
+ // Not always needed, but some themes can have different sizes of scrollbars
+ int scrollBarWidth = GTK_WIDGET(scrollbarv.GetID())->requisition.width;
+ int scrollBarHeight = GTK_WIDGET(scrollbarh.GetID())->requisition.height;
+
+ // These allocations should never produce negative sizes as they would wrap around to huge
+ // unsigned numbers inside GTK+ causing warnings.
+
+ alloc.x = 0;
+ alloc.y = 0;
+ alloc.width = Platform::Maximum(1, width - scrollBarWidth) + 1;
+ alloc.height = Platform::Maximum(1, height - scrollBarHeight) + 1;
+ gtk_widget_size_allocate(GTK_WIDGET(wDraw.GetID()), &alloc);
+
+ alloc.x = 0;
+ alloc.y = height - scrollBarHeight + 1;
+ alloc.width = Platform::Maximum(1, width - scrollBarWidth) + 1;
+ alloc.height = scrollBarHeight;
+ gtk_widget_size_allocate(GTK_WIDGET(scrollbarh.GetID()), &alloc);
+
+ alloc.x = width - scrollBarWidth + 1;
+ alloc.y = 0;
+ alloc.width = scrollBarWidth;
+ alloc.height = Platform::Maximum(1, height - scrollBarHeight) + 1;
+ gtk_widget_size_allocate(GTK_WIDGET(scrollbarv.GetID()), &alloc);
+
+ SetScrollBars();
+}
+
+gint ScintillaGTK::MoveResize(GtkWidget *, GtkAllocation *allocation, ScintillaGTK *sciThis) {
+ // Platform::DebugPrintf("sci move resize %d %d\n", allocation->width, allocation->height);
+ sciThis->Resize(allocation->width, allocation->height);
+ return TRUE;
+}
+
+gint ScintillaGTK::Press(GtkWidget *, GdkEventButton *event, ScintillaGTK *sciThis) {
+ //Platform::DebugPrintf("Press %x time=%d state = %x button = %x\n",sciThis,event->time, event->state, event->button);
+ sciThis->evbtn = *event;
+ Point pt;
+ pt.x = int(event->x);
+ pt.y = int(event->y);
+ gtk_widget_grab_focus(sciThis->wMain.GetID());
+ if (event->button == 1) {
+ //sciThis->ButtonDown(pt, event->time,
+ // event->state & GDK_SHIFT_MASK,
+ // event->state & GDK_CONTROL_MASK,
+ // event->state & GDK_MOD1_MASK);
+ // Instead of sending literal modifiers use control instead of alt
+ // Ths s because all the window managers seem to grab alt + click for moving
+ sciThis->ButtonDown(pt, event->time,
+ event->state & GDK_SHIFT_MASK,
+ event->state & GDK_CONTROL_MASK,
+ event->state & GDK_CONTROL_MASK);
+ } else if (event->button == 2) {
+ // Grab the primary selection
+ gtk_selection_convert(GTK_WIDGET(sciThis->wDraw.GetID()),
+ GDK_SELECTION_PRIMARY,
+ gdk_atom_intern("STRING", FALSE), event->time);
+ } else if (event->button == 3) {
+ // PopUp menu
+ // Convert to screen
+ int ox = 0;
+ int oy = 0;
+ gdk_window_get_origin(sciThis->wDraw.GetID()->window, &ox, &oy);
+ sciThis->ContextMenu(Point(pt.x + ox, pt.y + oy));
+ }
+ return TRUE;
+}
+
+gint ScintillaGTK::MouseRelease(GtkWidget *, GdkEventButton *event, ScintillaGTK *sciThis) {
+ //Platform::DebugPrintf("Release %x %d %d\n",sciThis,event->time,event->state);
+ if (event->button == 1) {
+ Point pt;
+ pt.x = int(event->x);
+ pt.y = int(event->y);
+ //Platform::DebugPrintf("Up %x %x %d %d %d\n",
+ // sciThis,event->window,event->time, pt.x, pt.y);
+ if (event->window != sciThis->wDraw.GetID()->window)
+ // If mouse released on scroll bar then the position is relative to the
+ // scrollbar, not the drawing window so just repeat the most recent point.
+ pt = sciThis->ptMouseLast;
+ sciThis->ButtonUp(pt, event->time, event->state & 4);
+ }
+ return TRUE;
+}
+
+gint ScintillaGTK::Motion(GtkWidget *, GdkEventMotion *event, ScintillaGTK *sciThis) {
+ //Platform::DebugPrintf("Move %x %d\n",sciThis,event->time);
+ int x = 0;
+ int y = 0;
+ GdkModifierType state;
+ if (event->is_hint) {
+ gdk_window_get_pointer(event->window, &x, &y, &state);
+ } else {
+ x = static_cast<int>(event->x);
+ y = static_cast<int>(event->y);
+ state = static_cast<GdkModifierType>(event->state);
+ }
+ //Platform::DebugPrintf("Move %x %x %d %c %d %d\n",
+ // sciThis,event->window,event->time,event->is_hint? 'h' :'.', x, y);
+ if (state & GDK_BUTTON1_MASK) {
+ Point pt;
+ pt.x = x;
+ pt.y = y;
+ sciThis->ButtonMove(pt);
+ }
+ return TRUE;
+}
+
+// Map the keypad keys to their equivalent functions
+static int KeyTranslate(int keyIn) {
+ switch (keyIn) {
+ case GDK_ISO_Left_Tab: return GDK_Tab;
+ case GDK_KP_Down: return GDK_Down;
+ case GDK_KP_Up: return GDK_Up;
+ case GDK_KP_Left: return GDK_Left;
+ case GDK_KP_Right: return GDK_Right;
+ case GDK_KP_Home: return GDK_Home;
+ case GDK_KP_End: return GDK_End;
+ case GDK_KP_Page_Up: return GDK_Page_Up;
+ case GDK_KP_Page_Down: return GDK_Page_Down;
+ case GDK_KP_Delete: return GDK_Delete;
+ case GDK_KP_Insert: return GDK_Insert;
+ case GDK_KP_Enter: return GDK_Return;
+ default: return keyIn;
+ }
+}
+
+gint ScintillaGTK::KeyPress(GtkWidget *, GdkEventKey *event, ScintillaGTK *sciThis) {
+ //Platform::DebugPrintf("SC-key: %d %x %x\n",event->keyval, event->state, GTK_WIDGET_FLAGS(widget));
+ bool shift = event->state & GDK_SHIFT_MASK;
+ bool ctrl = event->state & GDK_CONTROL_MASK;
+ bool alt = event->state & GDK_MOD1_MASK;
+ int key = event->keyval;
+ if (ctrl && (key < 128))
+ key = toupper(key);
+ else if (key >= GDK_KP_Multiply && key <= GDK_KP_9)
+ key &= 0x7F;
+ else
+ key = KeyTranslate(key);
+
+ sciThis->KeyDown(key, shift, ctrl, alt);
+ //Platform::DebugPrintf("SK-key: %d %x %x\n",event->keyval, event->state, GTK_WIDGET_FLAGS(widget));
+ return 1;
+}
+
+gint ScintillaGTK::KeyRelease(GtkWidget *, GdkEventKey *event, ScintillaGTK *sciThis) {
+ //Platform::DebugPrintf("SC-keyrel: %d %x %3s\n",event->keyval, event->state, event->string);
+ return TRUE;
+}
+
+gint ScintillaGTK::DestroyWindow(GtkWidget *, ScintillaGTK *sciThis) {
+//Platform::DebugPrintf("Destroying window %x %x\n", sciThis, widget);
+ sciThis->Finalise();
+ delete sciThis;
+ return TRUE;
+}
+
+gint ScintillaGTK::Expose(GtkWidget *, GdkEventExpose *ose, ScintillaGTK *sciThis) {
+ if (sciThis->firstExpose) {
+ sciThis->wDraw.SetCursor(Window::cursorText);
+ sciThis->firstExpose = false;
+ }
+
+ sciThis->paintState = painting;
+
+ sciThis->rcPaint.left = ose->area.x;
+ sciThis->rcPaint.top = ose->area.y;
+ sciThis->rcPaint.right = ose->area.x + ose->area.width;
+ sciThis->rcPaint.bottom = ose->area.y + ose->area.height;
+
+ PRectangle rcText = sciThis->GetTextRectangle();
+ sciThis->paintingAllText = sciThis->rcPaint.Contains(rcText);
+ Surface surfaceWindow;
+ surfaceWindow.Init((sciThis->wDraw.GetID())->window);
+ sciThis->Paint(&surfaceWindow, sciThis->rcPaint);
+ surfaceWindow.Release();
+ if (sciThis->paintState == paintAbandoned) {
+ // Painting area was insufficient to cover new styling or brace highlight positions
+ sciThis->FullPaint();
+ }
+ sciThis->paintState = notPainting;
+
+ return TRUE;
+}
+
+void ScintillaGTK::ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) {
+ //Platform::DebugPrintf("Scrolly %g %x\n",adj->value,p);
+ sciThis->ScrollTo((int)adj->value);
+}
+
+void ScintillaGTK::ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis) {
+ //Platform::DebugPrintf("Scrollyh %g %x\n",adj->value,p);
+ sciThis->HorizontalScrollTo((int)adj->value * 2);
+}
+
+void ScintillaGTK::SelectionReceived(GtkWidget *,
+ GtkSelectionData *selection_data, guint, ScintillaGTK *sciThis) {
+ //Platform::DebugPrintf("Selection received\n");
+ sciThis->ReceivedSelection(selection_data);
+}
+
+void ScintillaGTK::SelectionGet(GtkWidget *,
+ GtkSelectionData *selection_data, guint info, guint, ScintillaGTK *sciThis) {
+ //Platform::DebugPrintf("Selection get\n");
+ sciThis->GetSelection(selection_data, info, sciThis->pasteBuffer, sciThis->pasteBufferIsRectangular);
+}
+
+void ScintillaGTK::DragBegin(GtkWidget *, GdkDragContext *,
+ ScintillaGTK *) {
+ //Platform::DebugPrintf("DragBegin\n");
+}
+
+gboolean ScintillaGTK::DragMotion(GtkWidget *, GdkDragContext *context,
+ gint x, gint y, guint dragtime, ScintillaGTK *sciThis) {
+ //Platform::DebugPrintf("DragMotion %d %d %x %x %x\n", x, y,
+ // context->actions, context->suggested_action, sciThis);
+ Point npt(x, y);
+ sciThis->inDragDrop = true;
+ sciThis->SetDragPosition(sciThis->PositionFromLocation(npt));
+ gdk_drag_status(context, context->suggested_action, dragtime);
+ return TRUE;
+}
+
+void ScintillaGTK::DragLeave(GtkWidget *, GdkDragContext *context,
+ guint, ScintillaGTK *sciThis) {
+ sciThis->SetDragPosition(invalidPosition);
+ //Platform::DebugPrintf("DragLeave %x\n", sciThis);
+}
+
+void ScintillaGTK::DragEnd(GtkWidget *, GdkDragContext *context,
+ ScintillaGTK *sciThis) {
+ // If drag did not result in drop here or elsewhere
+ if (!sciThis->dragWasDropped)
+ sciThis->SetEmptySelection(sciThis->posDrag);
+ sciThis->SetDragPosition(invalidPosition);
+ //Platform::DebugPrintf("DragEnd %x %d\n", sciThis, sciThis->dragWasDropped);
+}
+
+gboolean ScintillaGTK::Drop(GtkWidget *, GdkDragContext *context,
+ gint, gint, guint, ScintillaGTK *sciThis) {
+ //Platform::DebugPrintf("Drop %x\n", sciThis);
+ sciThis->SetDragPosition(invalidPosition);
+ return TRUE;
+}
+
+void ScintillaGTK::DragDataReceived(GtkWidget *, GdkDragContext *context,
+ gint, gint, GtkSelectionData *selection_data, guint info, guint,
+ ScintillaGTK *sciThis) {
+ sciThis->ReceivedDrop(selection_data);
+ sciThis->SetDragPosition(invalidPosition);
+}
+
+void ScintillaGTK::DragDataGet(GtkWidget *, GdkDragContext *context,
+ GtkSelectionData *selection_data, guint info, guint, ScintillaGTK *sciThis) {
+ sciThis->dragWasDropped = true;
+ if (sciThis->currentPos != sciThis->anchor) {
+ sciThis->GetSelection(selection_data, info, sciThis->dragChars, sciThis->dragIsRectangle);
+ }
+ if (context->action == GDK_ACTION_MOVE) {
+ int selStart = sciThis->SelectionStart();
+ int selEnd = sciThis->SelectionEnd();
+ if (sciThis->posDrop > selStart) {
+ if (sciThis->posDrop > selEnd)
+ sciThis->posDrop = sciThis->posDrop - (selEnd-selStart);
+ else
+ sciThis->posDrop = selStart;
+ sciThis->posDrop = sciThis->pdoc->ClampPositionIntoDocument(sciThis->posDrop);
+ }
+ sciThis->ClearSelection();
+ }
+ sciThis->SetDragPosition(invalidPosition);
+}
+
+int ScintillaGTK::TimeOut(ScintillaGTK *sciThis) {
+ sciThis->Tick();
+ return 1;
+}
+
+void ScintillaGTK::PopUpCB(ScintillaGTK *sciThis, guint action, GtkWidget *) {
+ if (action) {
+ sciThis->Command(action);
+ }
+}
+
+gint ScintillaGTK::ExposeCT(GtkWidget *widget, GdkEventExpose *ose, CallTip *ctip) {
+ Surface surfaceWindow;
+ //surfaceWindow.Init((ct->wCallTip.GetID())->window);
+ surfaceWindow.Init(widget->window);
+ ctip->PaintCT(&surfaceWindow);
+ surfaceWindow.Release();
+ return TRUE;
+}
+
+long scintilla_send_message(ScintillaObject *sci, int iMessage, int wParam, int lParam) {
+ ScintillaGTK *psci = reinterpret_cast<ScintillaGTK *>(sci->pscin);
+ return psci->WndProc(iMessage, wParam, lParam);
+}
+
+static void scintilla_class_init (ScintillaClass *klass);
+static void scintilla_init (ScintillaObject *sci);
+
+guint scintilla_get_type() {
+ static guint scintilla_type = 0;
+
+ if (!scintilla_type) {
+ GtkTypeInfo scintilla_info = {
+ "Scintilla",
+ sizeof (ScintillaObject),
+ sizeof (ScintillaClass),
+ (GtkClassInitFunc) scintilla_class_init,
+ (GtkObjectInitFunc) scintilla_init,
+ (GtkArgSetFunc) NULL,
+ (GtkArgGetFunc) NULL
+ };
+
+ scintilla_type = gtk_type_unique(gtk_fixed_get_type(), &scintilla_info);
+ }
+
+ return scintilla_type;
+}
+
+static void scintilla_class_init(ScintillaClass *klass) {
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass*) klass;
+
+ scintilla_signals[COMMAND_SIGNAL] = gtk_signal_new(
+ "command",
+ GTK_RUN_LAST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET(ScintillaClass, command),
+ gtk_marshal_NONE__INT_POINTER,
+ GTK_TYPE_NONE,
+ 2, GTK_TYPE_INT, GTK_TYPE_POINTER);
+
+ scintilla_signals[NOTIFY_SIGNAL] = gtk_signal_new(
+ "notify",
+ GTK_RUN_LAST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET(ScintillaClass, notify),
+ gtk_marshal_NONE__INT_POINTER,
+ GTK_TYPE_NONE,
+ 2, GTK_TYPE_INT, GTK_TYPE_POINTER);
+
+ gtk_object_class_add_signals(object_class,
+ reinterpret_cast<unsigned int *>(scintilla_signals), LAST_SIGNAL);
+
+ klass->command = NULL;
+ klass->notify = NULL;
+}
+
+static void scintilla_init(ScintillaObject *sci) {
+ GTK_WIDGET_SET_FLAGS(sci, GTK_CAN_FOCUS);
+ sci->pscin = new ScintillaGTK(sci);
+}
+
+GtkWidget* scintilla_new() {
+ return GTK_WIDGET(gtk_type_new(scintilla_get_type()));
+}
+
+void scintilla_set_id(ScintillaObject *sci,int id) {
+ ScintillaGTK *psci = reinterpret_cast<ScintillaGTK *>(sci->pscin);
+ psci->ctrlID = id;
+}