diff options
Diffstat (limited to 'gtk/ScintillaGTK.cxx')
| -rw-r--r-- | gtk/ScintillaGTK.cxx | 1003 | 
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; +} | 
