1 // Scintilla source code edit control
2 // ScintillaGTK.h - GTK+ specific subclass of ScintillaBase
3 // Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
4 // The License.txt file describes the conditions under which this software may be distributed.
5 
6 #ifndef SCINTILLAGTK_H
7 #define SCINTILLAGTK_H
8 
9 namespace Scintilla {
10 
11 class ScintillaGTKAccessible;
12 
13 #define OBJECT_CLASS GObjectClass
14 
15 class ScintillaGTK : public ScintillaBase {
16 	friend class ScintillaGTKAccessible;
17 
18 	_ScintillaObject *sci;
19 	Window wText;
20 	Window scrollbarv;
21 	Window scrollbarh;
22 	GtkAdjustment *adjustmentv;
23 	GtkAdjustment *adjustmenth;
24 	Window wSelection;
25 	int verticalScrollBarWidth;
26 	int horizontalScrollBarHeight;
27 
28 	SelectionText primary;
29 
30 	GdkEvent *evbtn;
31 	guint buttonMouse;
32 	bool capturedMouse;
33 	bool dragWasDropped;
34 	int lastKey;
35 	int rectangularSelectionModifier;
36 
37 	GtkWidgetClass *parentClass;
38 
39 	static inline GdkAtom atomUTF8 {};
40 	static inline GdkAtom atomUTF8Mime {};
41 	static inline GdkAtom atomString {};
42 	static inline GdkAtom atomUriList {};
43 	static inline GdkAtom atomDROPFILES_DND {};
44 	GdkAtom atomSought;
45 
46 #if PLAT_GTK_WIN32
47 	CLIPFORMAT cfColumnSelect;
48 #endif
49 
50 	bool preeditInitialized;
51 	Window wPreedit;
52 	Window wPreeditDraw;
53 	GtkIMContext *im_context;
54 	GUnicodeScript lastNonCommonScript;
55 
56 	// Wheel mouse support
57 	unsigned int linesPerScroll;
58 	gint64 lastWheelMouseTime;
59 	gint lastWheelMouseDirection;
60 	gint wheelMouseIntensity;
61 	gdouble smoothScrollY;
62 	gdouble smoothScrollX;
63 
64 #if GTK_CHECK_VERSION(3,0,0)
65 	cairo_rectangle_list_t *rgnUpdate;
66 #else
67 	GdkRegion *rgnUpdate;
68 #endif
69 	bool repaintFullWindow;
70 
71 	guint styleIdleID;
72 	int accessibilityEnabled;
73 	AtkObject *accessible;
74 
75 public:
76 	explicit ScintillaGTK(_ScintillaObject *sci_);
77 	// Deleted so ScintillaGTK objects can not be copied.
78 	ScintillaGTK(const ScintillaGTK &) = delete;
79 	ScintillaGTK(ScintillaGTK &&) = delete;
80 	ScintillaGTK &operator=(const ScintillaGTK &) = delete;
81 	ScintillaGTK &operator=(ScintillaGTK &&) = delete;
82 	virtual ~ScintillaGTK();
83 	static ScintillaGTK *FromWidget(GtkWidget *widget) noexcept;
84 	static void ClassInit(OBJECT_CLASS *object_class, GtkWidgetClass *widget_class, GtkContainerClass *container_class);
85 private:
86 	void Init();
87 	void Finalise() override;
88 	bool AbandonPaint() override;
89 	void DisplayCursor(Window::Cursor c) override;
90 	bool DragThreshold(Point ptStart, Point ptNow) override;
91 	void StartDrag() override;
92 	Sci::Position TargetAsUTF8(char *text) const;
93 	Sci::Position EncodedFromUTF8(const char *utf8, char *encoded) const;
94 	bool ValidCodePage(int codePage) const override;
95 public: 	// Public for scintilla_send_message
96 	sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) override;
97 private:
98 	sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) override;
99 	struct TimeThunk {
100 		TickReason reason;
101 		ScintillaGTK *scintilla;
102 		guint timer;
TimeThunkTimeThunk103 		TimeThunk() noexcept : reason(tickCaret), scintilla(nullptr), timer(0) {}
104 	};
105 	TimeThunk timers[tickDwell+1];
106 	bool FineTickerRunning(TickReason reason) override;
107 	void FineTickerStart(TickReason reason, int millis, int tolerance) override;
108 	void FineTickerCancel(TickReason reason) override;
109 	bool SetIdle(bool on) override;
110 	void SetMouseCapture(bool on) override;
111 	bool HaveMouseCapture() override;
112 	bool PaintContains(PRectangle rc) override;
113 	void FullPaint();
114 	PRectangle GetClientRectangle() const override;
115 	void ScrollText(Sci::Line linesToMove) override;
116 	void SetVerticalScrollPos() override;
117 	void SetHorizontalScrollPos() override;
118 	bool ModifyScrollBars(Sci::Line nMax, Sci::Line nPage) override;
119 	void ReconfigureScrollBars() override;
120 	void NotifyChange() override;
121 	void NotifyFocus(bool focus) override;
122 	void NotifyParent(SCNotification scn) override;
123 	void NotifyKey(int key, int modifiers);
124 	void NotifyURIDropped(const char *list);
125 	const char *CharacterSetID() const;
126 	CaseFolder *CaseFolderForEncoding() override;
127 	std::string CaseMapString(const std::string &s, int caseMapping) override;
128 	int KeyDefault(int key, int modifiers) override;
129 	void CopyToClipboard(const SelectionText &selectedText) override;
130 	void Copy() override;
131 	void RequestSelection(GdkAtom atomSelection);
132 	void Paste() override;
133 	void CreateCallTipWindow(PRectangle rc) override;
134 	void AddToPopUp(const char *label, int cmd = 0, bool enabled = true) override;
135 	bool OwnPrimarySelection();
136 	void ClaimSelection() override;
137 	static bool IsStringAtom(GdkAtom type);
138 	void GetGtkSelectionText(GtkSelectionData *selectionData, SelectionText &selText);
139 	void InsertSelection(GtkClipboard *clipBoard, GtkSelectionData *selectionData);
140 public:	// Public for SelectionReceiver
141 	GObject *MainObject() const noexcept;
142 	void ReceivedClipboard(GtkClipboard *clipBoard, GtkSelectionData *selection_data) noexcept;
143 private:
144 	void ReceivedSelection(GtkSelectionData *selection_data);
145 	void ReceivedDrop(GtkSelectionData *selection_data);
146 	static void GetSelection(GtkSelectionData *selection_data, guint info, SelectionText *text);
147 	void StoreOnClipboard(SelectionText *clipText);
148 	static void ClipboardGetSelection(GtkClipboard *clip, GtkSelectionData *selection_data, guint info, void *data);
149 	static void ClipboardClearSelection(GtkClipboard *clip, void *data);
150 
151 	void UnclaimSelection(GdkEventSelection *selection_event);
152 	static void PrimarySelection(GtkWidget *widget, GtkSelectionData *selection_data, guint info, guint time_stamp, ScintillaGTK *sciThis);
153 	static gboolean PrimaryClear(GtkWidget *widget, GdkEventSelection *event, ScintillaGTK *sciThis);
154 	void Resize(int width, int height);
155 
156 	// Callback functions
157 	void RealizeThis(GtkWidget *widget);
158 	static void Realize(GtkWidget *widget);
159 	void UnRealizeThis(GtkWidget *widget);
160 	static void UnRealize(GtkWidget *widget);
161 	void MapThis();
162 	static void Map(GtkWidget *widget);
163 	void UnMapThis();
164 	static void UnMap(GtkWidget *widget);
165 	gint FocusInThis(GtkWidget *widget);
166 	static gint FocusIn(GtkWidget *widget, GdkEventFocus *event);
167 	gint FocusOutThis(GtkWidget *widget);
168 	static gint FocusOut(GtkWidget *widget, GdkEventFocus *event);
169 	static void SizeRequest(GtkWidget *widget, GtkRequisition *requisition);
170 #if GTK_CHECK_VERSION(3,0,0)
171 	static void GetPreferredWidth(GtkWidget *widget, gint *minimalWidth, gint *naturalWidth);
172 	static void GetPreferredHeight(GtkWidget *widget, gint *minimalHeight, gint *naturalHeight);
173 #endif
174 	static void SizeAllocate(GtkWidget *widget, GtkAllocation *allocation);
175 #if GTK_CHECK_VERSION(3,0,0)
176 	gboolean DrawTextThis(cairo_t *cr);
177 	static gboolean DrawText(GtkWidget *widget, cairo_t *cr, ScintillaGTK *sciThis);
178 	gboolean DrawThis(cairo_t *cr);
179 	static gboolean DrawMain(GtkWidget *widget, cairo_t *cr);
180 #else
181 	gboolean ExposeTextThis(GtkWidget *widget, GdkEventExpose *ose);
182 	static gboolean ExposeText(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis);
183 	gboolean Expose(GtkWidget *widget, GdkEventExpose *ose);
184 	static gboolean ExposeMain(GtkWidget *widget, GdkEventExpose *ose);
185 #endif
186 	void ForAll(GtkCallback callback, gpointer callback_data);
187 	static void MainForAll(GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data);
188 
189 	static void ScrollSignal(GtkAdjustment *adj, ScintillaGTK *sciThis);
190 	static void ScrollHSignal(GtkAdjustment *adj, ScintillaGTK *sciThis);
191 	gint PressThis(GdkEventButton *event);
192 	static gint Press(GtkWidget *widget, GdkEventButton *event);
193 	static gint MouseRelease(GtkWidget *widget, GdkEventButton *event);
194 	static gint ScrollEvent(GtkWidget *widget, GdkEventScroll *event);
195 	static gint Motion(GtkWidget *widget, GdkEventMotion *event);
196 	gboolean KeyThis(GdkEventKey *event);
197 	static gboolean KeyPress(GtkWidget *widget, GdkEventKey *event);
198 	static gboolean KeyRelease(GtkWidget *widget, GdkEventKey *event);
199 #if GTK_CHECK_VERSION(3,0,0)
200 	gboolean DrawPreeditThis(GtkWidget *widget, cairo_t *cr);
201 	static gboolean DrawPreedit(GtkWidget *widget, cairo_t *cr, ScintillaGTK *sciThis);
202 #else
203 	gboolean ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose);
204 	static gboolean ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, ScintillaGTK *sciThis);
205 #endif
206 	AtkObject *GetAccessibleThis(GtkWidget *widget);
207 	static AtkObject *GetAccessible(GtkWidget *widget);
208 
209 	bool KoreanIME();
210 	void CommitThis(char *commitStr);
211 	static void Commit(GtkIMContext *context, char *str, ScintillaGTK *sciThis);
212 	void PreeditChangedInlineThis();
213 	void PreeditChangedWindowedThis();
214 	static void PreeditChanged(GtkIMContext *context, ScintillaGTK *sciThis);
215 	void MoveImeCarets(int pos);
216 	void DrawImeIndicator(int indicator, int len);
217 	void SetCandidateWindowPos();
218 
219 	static void StyleSetText(GtkWidget *widget, GtkStyle *previous, void *);
220 	static void RealizeText(GtkWidget *widget, void *);
221 	static void Dispose(GObject *object);
222 	static void Destroy(GObject *object);
223 	static void SelectionReceived(GtkWidget *widget, GtkSelectionData *selection_data,
224 				      guint time);
225 	static void SelectionGet(GtkWidget *widget, GtkSelectionData *selection_data,
226 				 guint info, guint time);
227 	static gint SelectionClear(GtkWidget *widget, GdkEventSelection *selection_event);
228 	gboolean DragMotionThis(GdkDragContext *context, gint x, gint y, guint dragtime);
229 	static gboolean DragMotion(GtkWidget *widget, GdkDragContext *context,
230 				   gint x, gint y, guint dragtime);
231 	static void DragLeave(GtkWidget *widget, GdkDragContext *context,
232 			      guint time);
233 	static void DragEnd(GtkWidget *widget, GdkDragContext *context);
234 	static gboolean Drop(GtkWidget *widget, GdkDragContext *context,
235 			     gint x, gint y, guint time);
236 	static void DragDataReceived(GtkWidget *widget, GdkDragContext *context,
237 				     gint x, gint y, GtkSelectionData *selection_data, guint info, guint time);
238 	static void DragDataGet(GtkWidget *widget, GdkDragContext *context,
239 				GtkSelectionData *selection_data, guint info, guint time);
240 	static gboolean TimeOut(gpointer ptt);
241 	static gboolean IdleCallback(gpointer pSci);
242 	static gboolean StyleIdle(gpointer pSci);
243 	void IdleWork() override;
244 	void QueueIdleWork(WorkNeeded::workItems items, Sci::Position upTo) override;
245 	void SetDocPointer(Document *document) override;
246 	static void PopUpCB(GtkMenuItem *menuItem, ScintillaGTK *sciThis);
247 
248 #if GTK_CHECK_VERSION(3,0,0)
249 	static gboolean DrawCT(GtkWidget *widget, cairo_t *cr, CallTip *ctip);
250 #else
251 	static gboolean ExposeCT(GtkWidget *widget, GdkEventExpose *ose, CallTip *ctip);
252 #endif
253 	static gboolean PressCT(GtkWidget *widget, GdkEventButton *event, ScintillaGTK *sciThis);
254 
255 	static sptr_t DirectFunction(sptr_t ptr,
256 				     unsigned int iMessage, uptr_t wParam, sptr_t lParam);
257 };
258 
259 // helper class to watch a GObject lifetime and get notified when it dies
260 class GObjectWatcher {
261 	GObject *weakRef;
262 
WeakNotifyThis(GObject * obj G_GNUC_UNUSED)263 	void WeakNotifyThis(GObject *obj G_GNUC_UNUSED) {
264 		PLATFORM_ASSERT(obj == weakRef);
265 
266 		Destroyed();
267 		weakRef = nullptr;
268 	}
269 
WeakNotify(gpointer data,GObject * obj)270 	static void WeakNotify(gpointer data, GObject *obj) {
271 		static_cast<GObjectWatcher *>(data)->WeakNotifyThis(obj);
272 	}
273 
274 public:
GObjectWatcher(GObject * obj)275 	GObjectWatcher(GObject *obj) :
276 		weakRef(obj) {
277 		g_object_weak_ref(weakRef, WeakNotify, this);
278 	}
279 
280 	// Deleted so GObjectWatcher objects can not be copied.
281 	GObjectWatcher(const GObjectWatcher&) = delete;
282 	GObjectWatcher(GObjectWatcher&&) = delete;
283 	GObjectWatcher&operator=(const GObjectWatcher&) = delete;
284 	GObjectWatcher&operator=(GObjectWatcher&&) = delete;
285 
~GObjectWatcher()286 	virtual ~GObjectWatcher() {
287 		if (weakRef) {
288 			g_object_weak_unref(weakRef, WeakNotify, this);
289 		}
290 	}
291 
Destroyed()292 	virtual void Destroyed() {}
293 
IsDestroyed()294 	bool IsDestroyed() const {
295 		return weakRef != nullptr;
296 	}
297 };
298 
299 std::string ConvertText(const char *s, size_t len, const char *charSetDest,
300 			const char *charSetSource, bool transliterations, bool silent=false);
301 
302 }
303 
304 #endif
305