geany  1.38
About: Geany is a text editor (using GTK2) with basic features of an integrated development environment (syntax highlighting, code folding, symbol name auto-completion, ...). F: office T: editor programming GTK+ IDE
  Fossies Dox: geany-1.38.tar.bz2  ("unofficial" and yet experimental doxygen-generated source code documentation)  

ScintillaGTKAccessible.cxx
Go to the documentation of this file.
1/* Scintilla source code edit control */
2/* ScintillaGTKAccessible.cxx - GTK+ accessibility for ScintillaGTK */
3/* Copyright 2016 by Colomban Wendling <colomban@geany.org>
4 * The License.txt file describes the conditions under which this software may be distributed. */
5
6// REFERENCES BETWEEN THE DIFFERENT OBJECTS
7//
8// ScintillaGTKAccessible is the actual implementation, as a C++ class.
9// ScintillaObjectAccessible is the GObject derived from AtkObject that
10// implements the various ATK interfaces, through ScintillaGTKAccessible.
11// This follows the same pattern as ScintillaGTK and ScintillaObject.
12//
13// ScintillaGTK owns a strong reference to the ScintillaObjectAccessible, and
14// is both responsible for creating and destroying that object.
15//
16// ScintillaObjectAccessible owns a strong reference to ScintillaGTKAccessible,
17// and is responsible for creating and destroying that object.
18//
19// ScintillaGTKAccessible has weak references to both the ScintillaGTK and
20// the ScintillaObjectAccessible objects associated, but does not own any
21// strong references to those objects.
22//
23// The chain of ownership is as follows:
24// ScintillaGTK -> ScintillaObjectAccessible -> ScintillaGTKAccessible
25
26// DETAILS ON THE GOBJECT TYPE IMPLEMENTATION
27//
28// On GTK < 3.2, we need to use the AtkObjectFactory. We need to query
29// the factory to see what type we should derive from, thus making use of
30// dynamic inheritance. It's tricky, but it works so long as it's done
31// carefully enough.
32//
33// On GTK 3.2 through 3.6, we need to hack around because GTK stopped
34// registering its accessible types in the factory, so we can't query
35// them that way. Unfortunately, the accessible types aren't exposed
36// yet (not until 3.8), so there's no proper way to know which type to
37// inherit from. To work around this, we instantiate the parent's
38// AtkObject temporarily, and use it's type. It means creating an extra
39// throwaway object and being able to pass the type information up to the
40// type registration code, but it's the only solution I could find.
41//
42// On GTK 3.8 onward, we use the proper exposed GtkContainerAccessible as
43// parent, and so a straightforward class.
44//
45// To hide and contain the complexity in type creation arising from the
46// hackish support for GTK 3.2 to 3.8, the actual implementation for the
47// widget's get_accessible() is located in the accessibility layer itself.
48
49// Initially based on GtkTextViewAccessible from GTK 3.20
50// Inspiration for the GTK < 3.2 part comes from Evince 2.24, thanks.
51
52// FIXME: optimize character/byte offset conversion (with a cache?)
53
54#include <cstddef>
55#include <cstdlib>
56#include <cassert>
57#include <cstring>
58
59#include <stdexcept>
60#include <new>
61#include <string>
62#include <vector>
63#include <map>
64#include <algorithm>
65#include <memory>
66
67#include <glib.h>
68#include <gtk/gtk.h>
69
70// whether we have widget_set() and widget_unset()
71#define HAVE_WIDGET_SET_UNSET (GTK_CHECK_VERSION(3, 3, 6))
72// whether GTK accessibility is available through the ATK factory
73#define HAVE_GTK_FACTORY (! GTK_CHECK_VERSION(3, 1, 9))
74// whether we have gtk-a11y.h and the public GTK accessible types
75#define HAVE_GTK_A11Y_H (GTK_CHECK_VERSION(3, 7, 6))
76
77#if HAVE_GTK_A11Y_H
78# include <gtk/gtk-a11y.h>
79#endif
80
81#if defined(_WIN32)
82// On Win32 use windows.h to access CLIPFORMAT
83#undef NOMINMAX
84#define NOMINMAX
85#include <windows.h>
86#endif
87
88// ScintillaGTK.h and stuff it needs
89#include "Platform.h"
90
91#include "ILoader.h"
92#include "ILexer.h"
93#include "Scintilla.h"
94#include "ScintillaWidget.h"
95#include "StringCopy.h"
96#include "CharacterCategory.h"
97#include "Position.h"
98#include "UniqueString.h"
99#include "SplitVector.h"
100#include "Partitioning.h"
101#include "RunStyles.h"
102#include "ContractionState.h"
103#include "CellBuffer.h"
104#include "CallTip.h"
105#include "KeyMap.h"
106#include "Indicator.h"
107#include "LineMarker.h"
108#include "Style.h"
109#include "ViewStyle.h"
110#include "CharClassify.h"
111#include "Decoration.h"
112#include "CaseFolder.h"
113#include "Document.h"
114#include "CaseConvert.h"
115#include "UniConversion.h"
116#include "Selection.h"
117#include "PositionCache.h"
118#include "EditModel.h"
119#include "MarginView.h"
120#include "EditView.h"
121#include "Editor.h"
122#include "AutoComplete.h"
123#include "ScintillaBase.h"
124
125#include "ScintillaGTK.h"
127
128using namespace Scintilla;
129
132};
133
134typedef GtkAccessible ScintillaObjectAccessible;
135typedef GtkAccessibleClass ScintillaObjectAccessibleClass;
136
137#define SCINTILLA_OBJECT_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SCINTILLA_TYPE_OBJECT_ACCESSIBLE, ScintillaObjectAccessible))
138#define SCINTILLA_TYPE_OBJECT_ACCESSIBLE (scintilla_object_accessible_get_type(0))
139
140// We can't use priv member because of dynamic inheritance, so we don't actually know the offset. Meh.
141#define SCINTILLA_OBJECT_ACCESSIBLE_GET_PRIVATE(inst) (G_TYPE_INSTANCE_GET_PRIVATE((inst), SCINTILLA_TYPE_OBJECT_ACCESSIBLE, ScintillaObjectAccessiblePrivate))
142
143static GType scintilla_object_accessible_get_type(GType parent_type);
144
145ScintillaGTKAccessible *ScintillaGTKAccessible::FromAccessible(GtkAccessible *accessible) {
146 // FIXME: do we need the check below? GTK checks that in all methods, so maybe
147 GtkWidget *widget = gtk_accessible_get_widget(accessible);
148 if (! widget) {
149 return nullptr;
150 }
151
153}
154
155ScintillaGTKAccessible::ScintillaGTKAccessible(GtkAccessible *accessible_, GtkWidget *widget_) :
156 accessible(accessible_),
157 sci(ScintillaGTK::FromWidget(widget_)),
158 old_pos(-1) {
159 SetAccessibility(true);
160 g_signal_connect(widget_, "sci-notify", G_CALLBACK(SciNotify), this);
161}
162
164 if (gtk_accessible_get_widget(accessible)) {
165 g_signal_handlers_disconnect_matched(sci->sci, G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
166 }
167}
168
170 g_return_val_if_fail(startByte >= 0, nullptr);
171 // FIXME: should we swap start/end if necessary?
172 g_return_val_if_fail(endByte >= startByte, nullptr);
173
174 gchar *utf8Text = nullptr;
175 const char *charSetBuffer;
176
177 // like TargetAsUTF8, but avoids a double conversion
178 if (sci->IsUnicodeMode() || ! *(charSetBuffer = sci->CharacterSetID())) {
179 int len = endByte - startByte;
180 utf8Text = (char *) g_malloc(len + 1);
181 sci->pdoc->GetCharRange(utf8Text, startByte, len);
182 utf8Text[len] = '\0';
183 } else {
184 // Need to convert
185 std::string s = sci->RangeText(startByte, endByte);
186 std::string tmputf = ConvertText(&s[0], s.length(), "UTF-8", charSetBuffer, false);
187 size_t len = tmputf.length();
188 utf8Text = (char *) g_malloc(len + 1);
189 memcpy(utf8Text, tmputf.c_str(), len);
190 utf8Text[len] = '\0';
191 }
192
193 return utf8Text;
194}
195
196gchar *ScintillaGTKAccessible::GetText(int startChar, int endChar) {
197 Sci::Position startByte, endByte;
198 if (endChar == -1) {
199 startByte = ByteOffsetFromCharacterOffset(startChar);
200 endByte = sci->pdoc->Length();
201 } else {
202 ByteRangeFromCharacterRange(startChar, endChar, startByte, endByte);
203 }
204 return GetTextRangeUTF8(startByte, endByte);
205}
206
208 AtkTextBoundary boundaryType, int *startChar, int *endChar) {
209 g_return_val_if_fail(charOffset >= 0, nullptr);
210
211 Sci::Position startByte, endByte;
212 Sci::Position byteOffset = ByteOffsetFromCharacterOffset(charOffset);
213
214 switch (boundaryType) {
215 case ATK_TEXT_BOUNDARY_CHAR:
216 startByte = PositionAfter(byteOffset);
217 endByte = PositionAfter(startByte);
218 // FIXME: optimize conversion back, as we can reasonably assume +1 char?
219 break;
220
221 case ATK_TEXT_BOUNDARY_WORD_START:
222 startByte = sci->WndProc(SCI_WORDENDPOSITION, byteOffset, 1);
223 startByte = sci->WndProc(SCI_WORDENDPOSITION, startByte, 0);
224 endByte = sci->WndProc(SCI_WORDENDPOSITION, startByte, 1);
225 endByte = sci->WndProc(SCI_WORDENDPOSITION, endByte, 0);
226 break;
227
228 case ATK_TEXT_BOUNDARY_WORD_END:
229 startByte = sci->WndProc(SCI_WORDENDPOSITION, byteOffset, 0);
230 startByte = sci->WndProc(SCI_WORDENDPOSITION, startByte, 1);
231 endByte = sci->WndProc(SCI_WORDENDPOSITION, startByte, 0);
232 endByte = sci->WndProc(SCI_WORDENDPOSITION, endByte, 1);
233 break;
234
235 case ATK_TEXT_BOUNDARY_LINE_START: {
236 int line = sci->WndProc(SCI_LINEFROMPOSITION, byteOffset, 0);
237 startByte = sci->WndProc(SCI_POSITIONFROMLINE, line + 1, 0);
238 endByte = sci->WndProc(SCI_POSITIONFROMLINE, line + 2, 0);
239 break;
240 }
241
242 case ATK_TEXT_BOUNDARY_LINE_END: {
243 int line = sci->WndProc(SCI_LINEFROMPOSITION, byteOffset, 0);
244 startByte = sci->WndProc(SCI_GETLINEENDPOSITION, line, 0);
245 endByte = sci->WndProc(SCI_GETLINEENDPOSITION, line + 1, 0);
246 break;
247 }
248
249 default:
250 *startChar = *endChar = -1;
251 return nullptr;
252 }
253
254 CharacterRangeFromByteRange(startByte, endByte, startChar, endChar);
255 return GetTextRangeUTF8(startByte, endByte);
256}
257
259 AtkTextBoundary boundaryType, int *startChar, int *endChar) {
260 g_return_val_if_fail(charOffset >= 0, nullptr);
261
262 Sci::Position startByte, endByte;
263 Sci::Position byteOffset = ByteOffsetFromCharacterOffset(charOffset);
264
265 switch (boundaryType) {
266 case ATK_TEXT_BOUNDARY_CHAR:
267 endByte = PositionBefore(byteOffset);
268 startByte = PositionBefore(endByte);
269 break;
270
271 case ATK_TEXT_BOUNDARY_WORD_START:
272 endByte = sci->WndProc(SCI_WORDSTARTPOSITION, byteOffset, 0);
273 endByte = sci->WndProc(SCI_WORDSTARTPOSITION, endByte, 1);
274 startByte = sci->WndProc(SCI_WORDSTARTPOSITION, endByte, 0);
275 startByte = sci->WndProc(SCI_WORDSTARTPOSITION, startByte, 1);
276 break;
277
278 case ATK_TEXT_BOUNDARY_WORD_END:
279 endByte = sci->WndProc(SCI_WORDSTARTPOSITION, byteOffset, 1);
280 endByte = sci->WndProc(SCI_WORDSTARTPOSITION, endByte, 0);
281 startByte = sci->WndProc(SCI_WORDSTARTPOSITION, endByte, 1);
282 startByte = sci->WndProc(SCI_WORDSTARTPOSITION, startByte, 0);
283 break;
284
285 case ATK_TEXT_BOUNDARY_LINE_START: {
286 int line = sci->WndProc(SCI_LINEFROMPOSITION, byteOffset, 0);
287 endByte = sci->WndProc(SCI_POSITIONFROMLINE, line, 0);
288 if (line > 0) {
289 startByte = sci->WndProc(SCI_POSITIONFROMLINE, line - 1, 0);
290 } else {
291 startByte = endByte;
292 }
293 break;
294 }
295
296 case ATK_TEXT_BOUNDARY_LINE_END: {
297 int line = sci->WndProc(SCI_LINEFROMPOSITION, byteOffset, 0);
298 if (line > 0) {
299 endByte = sci->WndProc(SCI_GETLINEENDPOSITION, line - 1, 0);
300 } else {
301 endByte = 0;
302 }
303 if (line > 1) {
304 startByte = sci->WndProc(SCI_GETLINEENDPOSITION, line - 2, 0);
305 } else {
306 startByte = endByte;
307 }
308 break;
309 }
310
311 default:
312 *startChar = *endChar = -1;
313 return nullptr;
314 }
315
316 CharacterRangeFromByteRange(startByte, endByte, startChar, endChar);
317 return GetTextRangeUTF8(startByte, endByte);
318}
319
321 AtkTextBoundary boundaryType, int *startChar, int *endChar) {
322 g_return_val_if_fail(charOffset >= 0, nullptr);
323
324 Sci::Position startByte, endByte;
325 Sci::Position byteOffset = ByteOffsetFromCharacterOffset(charOffset);
326
327 switch (boundaryType) {
328 case ATK_TEXT_BOUNDARY_CHAR:
329 startByte = byteOffset;
330 endByte = sci->WndProc(SCI_POSITIONAFTER, byteOffset, 0);
331 break;
332
333 case ATK_TEXT_BOUNDARY_WORD_START:
334 startByte = sci->WndProc(SCI_WORDSTARTPOSITION, byteOffset, 1);
335 endByte = sci->WndProc(SCI_WORDENDPOSITION, byteOffset, 1);
336 if (! sci->WndProc(SCI_ISRANGEWORD, startByte, endByte)) {
337 // if the cursor was not on a word, forward back
338 startByte = sci->WndProc(SCI_WORDSTARTPOSITION, startByte, 0);
339 startByte = sci->WndProc(SCI_WORDSTARTPOSITION, startByte, 1);
340 }
341 endByte = sci->WndProc(SCI_WORDENDPOSITION, endByte, 0);
342 break;
343
344 case ATK_TEXT_BOUNDARY_WORD_END:
345 startByte = sci->WndProc(SCI_WORDSTARTPOSITION, byteOffset, 1);
346 endByte = sci->WndProc(SCI_WORDENDPOSITION, byteOffset, 1);
347 if (! sci->WndProc(SCI_ISRANGEWORD, startByte, endByte)) {
348 // if the cursor was not on a word, forward back
349 endByte = sci->WndProc(SCI_WORDENDPOSITION, endByte, 0);
350 endByte = sci->WndProc(SCI_WORDENDPOSITION, endByte, 1);
351 }
352 startByte = sci->WndProc(SCI_WORDSTARTPOSITION, startByte, 0);
353 break;
354
355 case ATK_TEXT_BOUNDARY_LINE_START: {
356 int line = sci->WndProc(SCI_LINEFROMPOSITION, byteOffset, 0);
357 startByte = sci->WndProc(SCI_POSITIONFROMLINE, line, 0);
358 endByte = sci->WndProc(SCI_POSITIONFROMLINE, line + 1, 0);
359 break;
360 }
361
362 case ATK_TEXT_BOUNDARY_LINE_END: {
363 int line = sci->WndProc(SCI_LINEFROMPOSITION, byteOffset, 0);
364 if (line > 0) {
365 startByte = sci->WndProc(SCI_GETLINEENDPOSITION, line - 1, 0);
366 } else {
367 startByte = 0;
368 }
369 endByte = sci->WndProc(SCI_GETLINEENDPOSITION, line, 0);
370 break;
371 }
372
373 default:
374 *startChar = *endChar = -1;
375 return nullptr;
376 }
377
378 CharacterRangeFromByteRange(startByte, endByte, startChar, endChar);
379 return GetTextRangeUTF8(startByte, endByte);
380}
381
382#if ATK_CHECK_VERSION(2, 10, 0)
383gchar *ScintillaGTKAccessible::GetStringAtOffset(int charOffset,
384 AtkTextGranularity granularity, int *startChar, int *endChar) {
385 g_return_val_if_fail(charOffset >= 0, nullptr);
386
387 Sci::Position startByte, endByte;
388 Sci::Position byteOffset = ByteOffsetFromCharacterOffset(charOffset);
389
390 switch (granularity) {
391 case ATK_TEXT_GRANULARITY_CHAR:
392 startByte = byteOffset;
393 endByte = sci->WndProc(SCI_POSITIONAFTER, byteOffset, 0);
394 break;
395 case ATK_TEXT_GRANULARITY_WORD:
396 startByte = sci->WndProc(SCI_WORDSTARTPOSITION, byteOffset, 1);
397 endByte = sci->WndProc(SCI_WORDENDPOSITION, byteOffset, 1);
398 break;
399 case ATK_TEXT_GRANULARITY_LINE: {
400 gint line = sci->WndProc(SCI_LINEFROMPOSITION, byteOffset, 0);
401 startByte = sci->WndProc(SCI_POSITIONFROMLINE, line, 0);
402 endByte = sci->WndProc(SCI_GETLINEENDPOSITION, line, 0);
403 break;
404 }
405 default:
406 *startChar = *endChar = -1;
407 return nullptr;
408 }
409
410 CharacterRangeFromByteRange(startByte, endByte, startChar, endChar);
411 return GetTextRangeUTF8(startByte, endByte);
412}
413#endif
414
416 g_return_val_if_fail(charOffset >= 0, 0);
417
418 Sci::Position startByte = ByteOffsetFromCharacterOffset(charOffset);
419 Sci::Position endByte = PositionAfter(startByte);
420 gchar *ch = GetTextRangeUTF8(startByte, endByte);
421 gunichar unichar = g_utf8_get_char_validated(ch, -1);
422 g_free(ch);
423
424 return unichar;
425}
426
428 return sci->pdoc->CountCharacters(0, sci->pdoc->Length());
429}
430
433}
434
437 return TRUE;
438}
439
440gint ScintillaGTKAccessible::GetOffsetAtPoint(gint x, gint y, AtkCoordType coords) {
441 gint x_widget, y_widget, x_window, y_window;
442 GtkWidget *widget = gtk_accessible_get_widget(accessible);
443
444 GdkWindow *window = gtk_widget_get_window(widget);
445 gdk_window_get_origin(window, &x_widget, &y_widget);
446 if (coords == ATK_XY_SCREEN) {
447 x = x - x_widget;
448 y = y - y_widget;
449 } else if (coords == ATK_XY_WINDOW) {
450 window = gdk_window_get_toplevel(window);
451 gdk_window_get_origin(window, &x_window, &y_window);
452
453 x = x - x_widget + x_window;
454 y = y - y_widget + y_window;
455 } else {
456 return -1;
457 }
458
459 // FIXME: should we handle scrolling?
461}
462
464 gint *x, gint *y, gint *width, gint *height, AtkCoordType coords) {
465 *x = *y = *height = *width = 0;
466
467 Sci::Position byteOffset = ByteOffsetFromCharacterOffset(charOffset);
468
469 // FIXME: should we handle scrolling?
470 *x = sci->WndProc(SCI_POINTXFROMPOSITION, 0, byteOffset);
471 *y = sci->WndProc(SCI_POINTYFROMPOSITION, 0, byteOffset);
472
473 int line = sci->WndProc(SCI_LINEFROMPOSITION, byteOffset, 0);
474 *height = sci->WndProc(SCI_TEXTHEIGHT, line, 0);
475
476 int nextByteOffset = PositionAfter(byteOffset);
477 int next_x = sci->WndProc(SCI_POINTXFROMPOSITION, 0, nextByteOffset);
478 if (next_x > *x) {
479 *width = next_x - *x;
480 } else if (nextByteOffset > byteOffset) {
481 /* maybe next position was on the next line or something.
482 * just compute the expected character width */
483 int style = StyleAt(byteOffset, true);
484 int len = nextByteOffset - byteOffset;
485 char *ch = new char[len + 1];
486 sci->pdoc->GetCharRange(ch, byteOffset, len);
487 ch[len] = '\0';
488 *width = sci->TextWidth(style, ch);
489 delete[] ch;
490 }
491
492 GtkWidget *widget = gtk_accessible_get_widget(accessible);
493 GdkWindow *window = gtk_widget_get_window(widget);
494 int x_widget, y_widget;
495 gdk_window_get_origin(window, &x_widget, &y_widget);
496 if (coords == ATK_XY_SCREEN) {
497 *x += x_widget;
498 *y += y_widget;
499 } else if (coords == ATK_XY_WINDOW) {
500 window = gdk_window_get_toplevel(window);
501 int x_window, y_window;
502 gdk_window_get_origin(window, &x_window, &y_window);
503
504 *x += x_widget - x_window;
505 *y += y_widget - y_window;
506 } else {
507 *x = *y = *height = *width = 0;
508 }
509}
510
511static AtkAttributeSet *AddTextAttribute(AtkAttributeSet *attributes, AtkTextAttribute attr, gchar *value) {
512 AtkAttribute *at = g_new(AtkAttribute, 1);
513 at->name = g_strdup(atk_text_attribute_get_name(attr));
514 at->value = value;
515
516 return g_slist_prepend(attributes, at);
517}
518
519static AtkAttributeSet *AddTextIntAttribute(AtkAttributeSet *attributes, AtkTextAttribute attr, gint i) {
520 return AddTextAttribute(attributes, attr, g_strdup(atk_text_attribute_get_value(attr, i)));
521}
522
523static AtkAttributeSet *AddTextColorAttribute(AtkAttributeSet *attributes, AtkTextAttribute attr, const ColourDesired &colour) {
524 return AddTextAttribute(attributes, attr,
525 g_strdup_printf("%u,%u,%u", colour.GetRed() * 257, colour.GetGreen() * 257, colour.GetBlue() * 257));
526}
527
528AtkAttributeSet *ScintillaGTKAccessible::GetAttributesForStyle(unsigned int styleNum) {
529 AtkAttributeSet *attr_set = nullptr;
530
531 if (styleNum >= sci->vs.styles.size())
532 return nullptr;
533 Style &style = sci->vs.styles[styleNum];
534
535 attr_set = AddTextAttribute(attr_set, ATK_TEXT_ATTR_FAMILY_NAME, g_strdup(style.fontName));
536 attr_set = AddTextAttribute(attr_set, ATK_TEXT_ATTR_SIZE, g_strdup_printf("%d", style.size / SC_FONT_SIZE_MULTIPLIER));
537 attr_set = AddTextIntAttribute(attr_set, ATK_TEXT_ATTR_WEIGHT, CLAMP(style.weight, 100, 1000));
538 attr_set = AddTextIntAttribute(attr_set, ATK_TEXT_ATTR_STYLE, style.italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
539 attr_set = AddTextIntAttribute(attr_set, ATK_TEXT_ATTR_UNDERLINE, style.underline ? PANGO_UNDERLINE_SINGLE : PANGO_UNDERLINE_NONE);
540 attr_set = AddTextColorAttribute(attr_set, ATK_TEXT_ATTR_FG_COLOR, style.fore);
541 attr_set = AddTextColorAttribute(attr_set, ATK_TEXT_ATTR_BG_COLOR, style.back);
542 attr_set = AddTextIntAttribute(attr_set, ATK_TEXT_ATTR_INVISIBLE, style.visible ? 0 : 1);
543 attr_set = AddTextIntAttribute(attr_set, ATK_TEXT_ATTR_EDITABLE, style.changeable ? 1 : 0);
544
545 return attr_set;
546}
547
548AtkAttributeSet *ScintillaGTKAccessible::GetRunAttributes(int charOffset, int *startChar, int *endChar) {
549 g_return_val_if_fail(charOffset >= -1, nullptr);
550
551 Sci::Position byteOffset;
552 if (charOffset == -1) {
553 byteOffset = sci->WndProc(SCI_GETCURRENTPOS, 0, 0);
554 } else {
555 byteOffset = ByteOffsetFromCharacterOffset(charOffset);
556 }
557 int length = sci->pdoc->Length();
558
559 g_return_val_if_fail(byteOffset <= length, nullptr);
560
561 const char style = StyleAt(byteOffset, true);
562 // compute the range for this style
563 Sci::Position startByte = byteOffset;
564 // when going backwards, we know the style is already computed
565 while (startByte > 0 && sci->pdoc->StyleAt((startByte) - 1) == style)
566 (startByte)--;
567 Sci::Position endByte = byteOffset + 1;
568 while (endByte < length && StyleAt(endByte, true) == style)
569 (endByte)++;
570
571 CharacterRangeFromByteRange(startByte, endByte, startChar, endChar);
572 return GetAttributesForStyle((unsigned int) style);
573}
574
576 return GetAttributesForStyle(0);
577}
578
580 return sci->sel.Empty() ? 0 : sci->sel.Count();
581}
582
583gchar *ScintillaGTKAccessible::GetSelection(gint selection_num, int *startChar, int *endChar) {
584 if (selection_num < 0 || (unsigned int) selection_num >= sci->sel.Count())
585 return nullptr;
586
587 Sci::Position startByte = sci->sel.Range(selection_num).Start().Position();
588 Sci::Position endByte = sci->sel.Range(selection_num).End().Position();
589
590 CharacterRangeFromByteRange(startByte, endByte, startChar, endChar);
591 return GetTextRangeUTF8(startByte, endByte);
592}
593
594gboolean ScintillaGTKAccessible::AddSelection(int startChar, int endChar) {
595 size_t n_selections = sci->sel.Count();
596 Sci::Position startByte, endByte;
597 ByteRangeFromCharacterRange(startChar, endChar, startByte, endByte);
598 // use WndProc() to set the selections so it notifies as needed
599 if (n_selections > 1 || ! sci->sel.Empty()) {
600 sci->WndProc(SCI_ADDSELECTION, startByte, endByte);
601 } else {
602 sci->WndProc(SCI_SETSELECTION, startByte, endByte);
603 }
604
605 return TRUE;
606}
607
608gboolean ScintillaGTKAccessible::RemoveSelection(gint selection_num) {
609 size_t n_selections = sci->sel.Count();
610 if (selection_num < 0 || (unsigned int) selection_num >= n_selections)
611 return FALSE;
612
613 if (n_selections > 1) {
614 sci->WndProc(SCI_DROPSELECTIONN, selection_num, 0);
615 } else if (sci->sel.Empty()) {
616 return FALSE;
617 } else {
619 }
620
621 return TRUE;
622}
623
624gboolean ScintillaGTKAccessible::SetSelection(gint selection_num, int startChar, int endChar) {
625 if (selection_num < 0 || (unsigned int) selection_num >= sci->sel.Count())
626 return FALSE;
627
628 Sci::Position startByte, endByte;
629 ByteRangeFromCharacterRange(startChar, endChar, startByte, endByte);
630
631 sci->WndProc(SCI_SETSELECTIONNSTART, selection_num, startByte);
632 sci->WndProc(SCI_SETSELECTIONNEND, selection_num, endByte);
633
634 return TRUE;
635}
636
638 iface->get_text = GetText;
639 iface->get_text_after_offset = GetTextAfterOffset;
640 iface->get_text_at_offset = GetTextAtOffset;
641 iface->get_text_before_offset = GetTextBeforeOffset;
642#if ATK_CHECK_VERSION(2, 10, 0)
643 iface->get_string_at_offset = GetStringAtOffset;
644#endif
645 iface->get_character_at_offset = GetCharacterAtOffset;
646 iface->get_character_count = GetCharacterCount;
647 iface->get_caret_offset = GetCaretOffset;
648 iface->set_caret_offset = SetCaretOffset;
649 iface->get_offset_at_point = GetOffsetAtPoint;
650 iface->get_character_extents = GetCharacterExtents;
651 iface->get_n_selections = GetNSelections;
652 iface->get_selection = GetSelection;
653 iface->add_selection = AddSelection;
654 iface->remove_selection = RemoveSelection;
655 iface->set_selection = SetSelection;
656 iface->get_run_attributes = GetRunAttributes;
657 iface->get_default_attributes = GetDefaultAttributes;
658}
659
660/* atkeditabletext.h */
661
662void ScintillaGTKAccessible::SetTextContents(const gchar *contents) {
663 // FIXME: it's probably useless to check for READONLY here, SETTEXT probably does it just fine?
664 if (! sci->pdoc->IsReadOnly()) {
665 sci->WndProc(SCI_SETTEXT, 0, (sptr_t) contents);
666 }
667}
668
669bool ScintillaGTKAccessible::InsertStringUTF8(Sci::Position bytePos, const gchar *utf8, Sci::Position lengthBytes) {
670 if (sci->pdoc->IsReadOnly()) {
671 return false;
672 }
673
674 // like EncodedFromUTF8(), but avoids an extra copy
675 // FIXME: update target?
676 const char *charSetBuffer;
677 if (sci->IsUnicodeMode() || ! *(charSetBuffer = sci->CharacterSetID())) {
678 sci->pdoc->InsertString(bytePos, utf8, lengthBytes);
679 } else {
680 // conversion needed
681 std::string encoded = ConvertText(utf8, lengthBytes, charSetBuffer, "UTF-8", true);
682 sci->pdoc->InsertString(bytePos, encoded.c_str(), encoded.length());
683 }
684
685 return true;
686}
687
688void ScintillaGTKAccessible::InsertText(const gchar *text, int lengthBytes, int *charPosition) {
689 Sci::Position bytePosition = ByteOffsetFromCharacterOffset(*charPosition);
690
691 // FIXME: should we update the target?
692 if (InsertStringUTF8(bytePosition, text, lengthBytes)) {
693 (*charPosition) += sci->pdoc->CountCharacters(bytePosition, lengthBytes);
694 }
695}
696
697void ScintillaGTKAccessible::CopyText(int startChar, int endChar) {
698 Sci::Position startByte, endByte;
699 ByteRangeFromCharacterRange(startChar, endChar, startByte, endByte);
700 sci->CopyRangeToClipboard(startByte, endByte);
701}
702
703void ScintillaGTKAccessible::CutText(int startChar, int endChar) {
704 g_return_if_fail(endChar >= startChar);
705
706 if (! sci->pdoc->IsReadOnly()) {
707 // FIXME: have a byte variant of those and convert only once?
708 CopyText(startChar, endChar);
709 DeleteText(startChar, endChar);
710 }
711}
712
713void ScintillaGTKAccessible::DeleteText(int startChar, int endChar) {
714 g_return_if_fail(endChar >= startChar);
715
716 if (! sci->pdoc->IsReadOnly()) {
717 Sci::Position startByte, endByte;
718 ByteRangeFromCharacterRange(startChar, endChar, startByte, endByte);
719
720 if (! sci->RangeContainsProtected(startByte, endByte)) {
721 // FIXME: restore the target?
722 sci->pdoc->DeleteChars(startByte, endByte - startByte);
723 }
724 }
725}
726
727void ScintillaGTKAccessible::PasteText(int charPosition) {
728 if (sci->pdoc->IsReadOnly())
729 return;
730
731 // Helper class holding the position for the asynchronous paste operation.
732 // We can only hope that when the callback gets called scia is still valid, but ScintillaGTK
733 // has always done that without problems, so let's guess it's a fairly safe bet.
734 struct Helper : GObjectWatcher {
736 Sci::Position bytePosition;
737
738 void Destroyed() override {
739 scia = nullptr;
740 }
741
742 Helper(ScintillaGTKAccessible *scia_, Sci::Position bytePos_) :
743 GObjectWatcher(G_OBJECT(scia_->sci->sci)),
744 scia(scia_),
745 bytePosition(bytePos_) {
746 }
747
748 void TextReceived(GtkClipboard *, const gchar *text) {
749 if (text) {
750 size_t len = strlen(text);
751 std::string convertedText;
752 if (len > 0 && scia->sci->convertPastes) {
753 // Convert line endings of the paste into our local line-endings mode
754 convertedText = Document::TransformLineEnds(text, len, scia->sci->pdoc->eolMode);
755 len = convertedText.length();
756 text = convertedText.c_str();
757 }
758 scia->InsertStringUTF8(bytePosition, text, static_cast<Sci::Position>(len));
759 }
760 }
761
762 static void TextReceivedCallback(GtkClipboard *clipboard, const gchar *text, gpointer data) {
763 Helper *helper = static_cast<Helper*>(data);
764 try {
765 if (helper->scia != nullptr) {
766 helper->TextReceived(clipboard, text);
767 }
768 } catch (...) {}
769 delete helper;
770 }
771 };
772
773 Helper *helper = new Helper(this, ByteOffsetFromCharacterOffset(charPosition));
774 GtkWidget *widget = gtk_accessible_get_widget(accessible);
775 GtkClipboard *clipboard = gtk_widget_get_clipboard(widget, GDK_SELECTION_CLIPBOARD);
776 gtk_clipboard_request_text(clipboard, helper->TextReceivedCallback, helper);
777}
778
780 iface->set_text_contents = SetTextContents;
781 iface->insert_text = InsertText;
782 iface->copy_text = CopyText;
783 iface->cut_text = CutText;
784 iface->delete_text = DeleteText;
785 iface->paste_text = PasteText;
786 //~ iface->set_run_attributes = SetRunAttributes;
787}
788
791}
792
793// Callbacks
794
797 if (old_pos != pos) {
798 int charPosition = CharacterOffsetFromByteOffset(pos);
799 g_signal_emit_by_name(accessible, "text-caret-moved", charPosition);
800 old_pos = pos;
801 }
802
803 size_t n_selections = sci->sel.Count();
804 size_t prev_n_selections = old_sels.size();
805 bool selection_changed = n_selections != prev_n_selections;
806
807 old_sels.resize(n_selections);
808 for (size_t i = 0; i < n_selections; i++) {
809 SelectionRange &sel = sci->sel.Range(i);
810
811 if (i < prev_n_selections && ! selection_changed) {
812 SelectionRange &old_sel = old_sels[i];
813 // do not consider a caret move to be a selection change
814 selection_changed = ((! old_sel.Empty() || ! sel.Empty()) && ! (old_sel == sel));
815 }
816
817 old_sels[i] = sel;
818 }
819
820 if (selection_changed)
821 g_signal_emit_by_name(accessible, "text-selection-changed");
822}
823
825 if (!Enabled()) {
826 return;
827 }
828
829 if (oldDoc == newDoc) {
830 return;
831 }
832
833 if (oldDoc) {
834 int charLength = oldDoc->CountCharacters(0, oldDoc->Length());
835 g_signal_emit_by_name(accessible, "text-changed::delete", 0, charLength);
836 }
837
838 if (newDoc) {
839 PLATFORM_ASSERT(newDoc == sci->pdoc);
840
841 int charLength = newDoc->CountCharacters(0, newDoc->Length());
842 g_signal_emit_by_name(accessible, "text-changed::insert", 0, charLength);
843
844 if ((oldDoc ? oldDoc->IsReadOnly() : false) != newDoc->IsReadOnly()) {
846 }
847
848 // update cursor and selection
849 old_pos = -1;
850 old_sels.clear();
851 UpdateCursor();
852 }
853}
854
856 bool readonly = sci->pdoc->IsReadOnly();
857 atk_object_notify_state_change(ATK_OBJECT(accessible), ATK_STATE_EDITABLE, ! readonly);
858#if ATK_CHECK_VERSION(2, 16, 0)
859 atk_object_notify_state_change(ATK_OBJECT(accessible), ATK_STATE_READ_ONLY, readonly);
860#endif
861}
862
864 // Called by ScintillaGTK when application has enabled or disabled accessibility
865 if (enabled)
867 else
869}
870
871void ScintillaGTKAccessible::Notify(GtkWidget *, gint, SCNotification *nt) {
872 if (!Enabled())
873 return;
874 switch (nt->nmhdr.code) {
875 case SCN_MODIFIED: {
877 int startChar = CharacterOffsetFromByteOffset(nt->position);
878 int lengthChar = sci->pdoc->CountCharacters(nt->position, nt->position + nt->length);
879 g_signal_emit_by_name(accessible, "text-changed::insert", startChar, lengthChar);
880 UpdateCursor();
881 }
883 int startChar = CharacterOffsetFromByteOffset(nt->position);
884 int lengthChar = sci->pdoc->CountCharacters(nt->position, nt->position + nt->length);
885 g_signal_emit_by_name(accessible, "text-changed::delete", startChar, lengthChar);
886 }
888 UpdateCursor();
889 }
891 g_signal_emit_by_name(accessible, "text-attributes-changed");
892 }
893 } break;
894 case SCN_UPDATEUI: {
895 if (nt->updated & SC_UPDATE_SELECTION) {
896 UpdateCursor();
897 }
898 } break;
899 }
900}
901
902// ATK method wrappers
903
904// wraps a call from the accessible object to the ScintillaGTKAccessible, and avoid leaking any exception
905#define WRAPPER_METHOD_BODY(accessible, call, defret) \
906 try { \
907 ScintillaGTKAccessible *thisAccessible = FromAccessible(reinterpret_cast<GtkAccessible*>(accessible)); \
908 if (thisAccessible) { \
909 return thisAccessible->call; \
910 } else { \
911 return defret; \
912 } \
913 } catch (...) { \
914 return defret; \
915 }
916
917// AtkText
918gchar *ScintillaGTKAccessible::AtkTextIface::GetText(AtkText *text, int start_offset, int end_offset) {
919 WRAPPER_METHOD_BODY(text, GetText(start_offset, end_offset), nullptr);
920}
921gchar *ScintillaGTKAccessible::AtkTextIface::GetTextAfterOffset(AtkText *text, int offset, AtkTextBoundary boundary_type, int *start_offset, int *end_offset) {
922 WRAPPER_METHOD_BODY(text, GetTextAfterOffset(offset, boundary_type, start_offset, end_offset), nullptr)
923}
924gchar *ScintillaGTKAccessible::AtkTextIface::GetTextBeforeOffset(AtkText *text, int offset, AtkTextBoundary boundary_type, int *start_offset, int *end_offset) {
925 WRAPPER_METHOD_BODY(text, GetTextBeforeOffset(offset, boundary_type, start_offset, end_offset), nullptr)
926}
927gchar *ScintillaGTKAccessible::AtkTextIface::GetTextAtOffset(AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset) {
928 WRAPPER_METHOD_BODY(text, GetTextAtOffset(offset, boundary_type, start_offset, end_offset), nullptr)
929}
930#if ATK_CHECK_VERSION(2, 10, 0)
931gchar *ScintillaGTKAccessible::AtkTextIface::GetStringAtOffset(AtkText *text, gint offset, AtkTextGranularity granularity, gint *start_offset, gint *end_offset) {
932 WRAPPER_METHOD_BODY(text, GetStringAtOffset(offset, granularity, start_offset, end_offset), nullptr)
933}
934#endif
937}
940}
943}
946}
947gint ScintillaGTKAccessible::AtkTextIface::GetOffsetAtPoint(AtkText *text, gint x, gint y, AtkCoordType coords) {
948 WRAPPER_METHOD_BODY(text, GetOffsetAtPoint(x, y, coords), -1)
949}
950void ScintillaGTKAccessible::AtkTextIface::GetCharacterExtents(AtkText *text, gint offset, gint *x, gint *y, gint *width, gint *height, AtkCoordType coords) {
951 WRAPPER_METHOD_BODY(text, GetCharacterExtents(offset, x, y, width, height, coords), )
952}
953AtkAttributeSet *ScintillaGTKAccessible::AtkTextIface::GetRunAttributes(AtkText *text, gint offset, gint *start_offset, gint *end_offset) {
954 WRAPPER_METHOD_BODY(text, GetRunAttributes(offset, start_offset, end_offset), nullptr)
955}
958}
961}
962gchar *ScintillaGTKAccessible::AtkTextIface::GetSelection(AtkText *text, gint selection_num, gint *start_pos, gint *end_pos) {
963 WRAPPER_METHOD_BODY(text, GetSelection(selection_num, start_pos, end_pos), nullptr)
964}
965gboolean ScintillaGTKAccessible::AtkTextIface::AddSelection(AtkText *text, gint start, gint end) {
966 WRAPPER_METHOD_BODY(text, AddSelection(start, end), FALSE)
967}
968gboolean ScintillaGTKAccessible::AtkTextIface::RemoveSelection(AtkText *text, gint selection_num) {
969 WRAPPER_METHOD_BODY(text, RemoveSelection(selection_num), FALSE)
970}
971gboolean ScintillaGTKAccessible::AtkTextIface::SetSelection(AtkText *text, gint selection_num, gint start, gint end) {
972 WRAPPER_METHOD_BODY(text, SetSelection(selection_num, start, end), FALSE)
973}
974// AtkEditableText
975void ScintillaGTKAccessible::AtkEditableTextIface::SetTextContents(AtkEditableText *text, const gchar *contents) {
977}
978void ScintillaGTKAccessible::AtkEditableTextIface::InsertText(AtkEditableText *text, const gchar *contents, gint length, gint *position) {
979 WRAPPER_METHOD_BODY(text, InsertText(contents, length, position), )
980}
981void ScintillaGTKAccessible::AtkEditableTextIface::CopyText(AtkEditableText *text, gint start, gint end) {
982 WRAPPER_METHOD_BODY(text, CopyText(start, end), )
983}
984void ScintillaGTKAccessible::AtkEditableTextIface::CutText(AtkEditableText *text, gint start, gint end) {
985 WRAPPER_METHOD_BODY(text, CutText(start, end), )
986}
987void ScintillaGTKAccessible::AtkEditableTextIface::DeleteText(AtkEditableText *text, gint start, gint end) {
988 WRAPPER_METHOD_BODY(text, DeleteText(start, end), )
989}
992}
993
994// GObject glue
995
996#if HAVE_GTK_FACTORY
998#endif
999
1003
1004
1005// @p parent_type is only required on GTK 3.2 to 3.6, and only on the first call
1006static GType scintilla_object_accessible_get_type(GType parent_type G_GNUC_UNUSED) {
1007 static volatile gsize type_id_result = 0;
1008
1009 if (g_once_init_enter(&type_id_result)) {
1010 GTypeInfo tinfo = {
1011 0, /* class size */
1012 (GBaseInitFunc) nullptr, /* base init */
1013 (GBaseFinalizeFunc) nullptr, /* base finalize */
1014 (GClassInitFunc) scintilla_object_accessible_class_init, /* class init */
1015 (GClassFinalizeFunc) nullptr, /* class finalize */
1016 nullptr, /* class data */
1017 0, /* instance size */
1018 0, /* nb preallocs */
1019 (GInstanceInitFunc) scintilla_object_accessible_init, /* instance init */
1020 nullptr /* value table */
1021 };
1022
1023 const GInterfaceInfo atk_text_info = {
1024 (GInterfaceInitFunc) ScintillaGTKAccessible::AtkTextIface::init,
1025 (GInterfaceFinalizeFunc) nullptr,
1026 nullptr
1027 };
1028
1029 const GInterfaceInfo atk_editable_text_info = {
1031 (GInterfaceFinalizeFunc) nullptr,
1032 nullptr
1033 };
1034
1035#if HAVE_GTK_A11Y_H
1036 // good, we have gtk-a11y.h, we can use that
1037 GType derived_atk_type = GTK_TYPE_CONTAINER_ACCESSIBLE;
1038 tinfo.class_size = sizeof (GtkContainerAccessibleClass);
1039 tinfo.instance_size = sizeof (GtkContainerAccessible);
1040#else // ! HAVE_GTK_A11Y_H
1041# if HAVE_GTK_FACTORY
1042 // Figure out the size of the class and instance we are deriving from through the registry
1043 GType derived_type = g_type_parent(SCINTILLA_TYPE_OBJECT);
1044 AtkObjectFactory *factory = atk_registry_get_factory(atk_get_default_registry(), derived_type);
1045 GType derived_atk_type = atk_object_factory_get_accessible_type(factory);
1046# else // ! HAVE_GTK_FACTORY
1047 // We're kind of screwed and can't determine the parent (no registry, and no public type)
1048 // Hack your way around by requiring the caller to give us our parent type. The caller
1049 // might be able to trick its way into doing that, by e.g. instantiating the parent's
1050 // accessible type and get its GType. It's ugly but we can't do better on GTK 3.2 to 3.6.
1051 g_assert(parent_type != 0);
1052
1053 GType derived_atk_type = parent_type;
1054# endif // ! HAVE_GTK_FACTORY
1055
1056 GTypeQuery query;
1057 g_type_query(derived_atk_type, &query);
1058 tinfo.class_size = query.class_size;
1059 tinfo.instance_size = query.instance_size;
1060#endif // ! HAVE_GTK_A11Y_H
1061
1062 GType type_id = g_type_register_static(derived_atk_type, "ScintillaObjectAccessible", &tinfo, (GTypeFlags) 0);
1063 g_type_add_interface_static(type_id, ATK_TYPE_TEXT, &atk_text_info);
1064 g_type_add_interface_static(type_id, ATK_TYPE_EDITABLE_TEXT, &atk_editable_text_info);
1065
1066 g_once_init_leave(&type_id_result, type_id);
1067 }
1068
1069 return type_id_result;
1070}
1071
1072static AtkObject *scintilla_object_accessible_new(GType parent_type, GObject *obj) {
1073 g_return_val_if_fail(SCINTILLA_IS_OBJECT(obj), nullptr);
1074
1075 AtkObject *accessible = (AtkObject *) g_object_new(scintilla_object_accessible_get_type(parent_type),
1076#if HAVE_WIDGET_SET_UNSET
1077 "widget", obj,
1078#endif
1079 nullptr);
1080 atk_object_initialize(accessible, obj);
1081
1082 return accessible;
1083}
1084
1085// implementation for gtk_widget_get_accessible().
1086// See the comment at the top of the file for details on the implementation
1087// @p widget the widget.
1088// @p cache pointer to store the AtkObject between repeated calls. Might or might not be filled.
1089// @p widget_parent_class pointer to the widget's parent class (to chain up method calls).
1090AtkObject *ScintillaGTKAccessible::WidgetGetAccessibleImpl(GtkWidget *widget, AtkObject **cache, gpointer widget_parent_class G_GNUC_UNUSED) {
1091 if (*cache != nullptr) {
1092 return *cache;
1093 }
1094
1095#if HAVE_GTK_A11Y_H // just instantiate the accessible
1096 *cache = scintilla_object_accessible_new(0, G_OBJECT(widget));
1097#elif HAVE_GTK_FACTORY // register in the factory and let GTK instantiate
1098 static volatile gsize registered = 0;
1099
1100 if (g_once_init_enter(&registered)) {
1101 // Figure out whether accessibility is enabled by looking at the type of the accessible
1102 // object which would be created for the parent type of ScintillaObject.
1103 GType derived_type = g_type_parent(SCINTILLA_TYPE_OBJECT);
1104
1105 AtkRegistry *registry = atk_get_default_registry();
1106 AtkObjectFactory *factory = atk_registry_get_factory(registry, derived_type);
1107 GType derived_atk_type = atk_object_factory_get_accessible_type(factory);
1108 if (g_type_is_a(derived_atk_type, GTK_TYPE_ACCESSIBLE)) {
1109 atk_registry_set_factory_type(registry, SCINTILLA_TYPE_OBJECT,
1111 }
1112 g_once_init_leave(&registered, 1);
1113 }
1114 AtkObject *obj = GTK_WIDGET_CLASS(widget_parent_class)->get_accessible(widget);
1115 *cache = static_cast<AtkObject*>(g_object_ref(obj));
1116#else // no public API, no factory, so guess from the parent and instantiate
1117 static GType parent_atk_type = 0;
1118
1119 if (parent_atk_type == 0) {
1120 AtkObject *parent_obj = GTK_WIDGET_CLASS(widget_parent_class)->get_accessible(widget);
1121 if (parent_obj) {
1122 parent_atk_type = G_OBJECT_TYPE(parent_obj);
1123
1124 // Figure out whether accessibility is enabled by looking at the type of the accessible
1125 // object which would be created for the parent type of ScintillaObject.
1126 if (g_type_is_a(parent_atk_type, GTK_TYPE_ACCESSIBLE)) {
1127 *cache = scintilla_object_accessible_new(parent_atk_type, G_OBJECT(widget));
1128 } else {
1129 *cache = static_cast<AtkObject*>(g_object_ref(parent_obj));
1130 }
1131 }
1132 }
1133#endif
1134 return *cache;
1135}
1136
1138 AtkStateSet *state_set = ATK_OBJECT_CLASS(scintilla_object_accessible_parent_class)->ref_state_set(accessible);
1139
1140 GtkWidget *widget = gtk_accessible_get_widget(GTK_ACCESSIBLE(accessible));
1141 if (widget == nullptr) {
1142 atk_state_set_add_state(state_set, ATK_STATE_DEFUNCT);
1143 } else {
1144 if (! scintilla_send_message(SCINTILLA_OBJECT(widget), SCI_GETREADONLY, 0, 0))
1145 atk_state_set_add_state(state_set, ATK_STATE_EDITABLE);
1146#if ATK_CHECK_VERSION(2, 16, 0)
1147 else
1148 atk_state_set_add_state(state_set, ATK_STATE_READ_ONLY);
1149#endif
1150 atk_state_set_add_state(state_set, ATK_STATE_MULTI_LINE);
1151 atk_state_set_add_state(state_set, ATK_STATE_MULTISELECTABLE);
1152 atk_state_set_add_state(state_set, ATK_STATE_SELECTABLE_TEXT);
1153 /*atk_state_set_add_state(state_set, ATK_STATE_SUPPORTS_AUTOCOMPLETION);*/
1154 }
1155
1156 return state_set;
1157}
1158
1160 GtkWidget *widget = gtk_accessible_get_widget(accessible);
1161 if (widget == nullptr)
1162 return;
1163
1165 if (priv->pscin)
1166 delete priv->pscin;
1167 priv->pscin = new ScintillaGTKAccessible(accessible, widget);
1168}
1169
1170#if HAVE_WIDGET_SET_UNSET
1171static void scintilla_object_accessible_widget_unset(GtkAccessible *accessible) {
1172 GtkWidget *widget = gtk_accessible_get_widget(accessible);
1173 if (widget == nullptr)
1174 return;
1175
1177 delete priv->pscin;
1178 priv->pscin = 0;
1179}
1180#endif
1181
1182static void scintilla_object_accessible_initialize(AtkObject *obj, gpointer data) {
1183 ATK_OBJECT_CLASS(scintilla_object_accessible_parent_class)->initialize(obj, data);
1184
1185#if ! HAVE_WIDGET_SET_UNSET
1186 scintilla_object_accessible_widget_set(GTK_ACCESSIBLE(obj));
1187#endif
1188
1189 obj->role = ATK_ROLE_TEXT;
1190}
1191
1192static void scintilla_object_accessible_finalize(GObject *object) {
1194
1195 if (priv->pscin) {
1196 delete priv->pscin;
1197 priv->pscin = nullptr;
1198 }
1199
1200 G_OBJECT_CLASS(scintilla_object_accessible_parent_class)->finalize(object);
1201}
1202
1204 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
1205 AtkObjectClass *object_class = ATK_OBJECT_CLASS(klass);
1206
1207#if HAVE_WIDGET_SET_UNSET
1208 GtkAccessibleClass *accessible_class = GTK_ACCESSIBLE_CLASS(klass);
1209 accessible_class->widget_set = scintilla_object_accessible_widget_set;
1210 accessible_class->widget_unset = scintilla_object_accessible_widget_unset;
1211#endif
1212
1213 object_class->ref_state_set = scintilla_object_accessible_ref_state_set;
1214 object_class->initialize = scintilla_object_accessible_initialize;
1215
1216 gobject_class->finalize = scintilla_object_accessible_finalize;
1217
1218 scintilla_object_accessible_parent_class = g_type_class_peek_parent(klass);
1219
1220 g_type_class_add_private(klass, sizeof (ScintillaObjectAccessiblePrivate));
1221}
1222
1225
1226 priv->pscin = nullptr;
1227}
1228
1229#if HAVE_GTK_FACTORY
1230// Object factory
1231typedef AtkObjectFactory ScintillaObjectAccessibleFactory;
1232typedef AtkObjectFactoryClass ScintillaObjectAccessibleFactoryClass;
1233
1234G_DEFINE_TYPE(ScintillaObjectAccessibleFactory, scintilla_object_accessible_factory, ATK_TYPE_OBJECT_FACTORY)
1235
1237}
1238
1241}
1242
1244 return scintilla_object_accessible_new(0, obj);
1245}
1246
1247static void scintilla_object_accessible_factory_class_init(AtkObjectFactoryClass * klass) {
1250}
1251#endif
Defines the auto completion list box.
Interface to the call tip control.
Performs Unicode case conversions.
Classes for case folding.
Manages the text of the document.
Character classifications used by Document and RESearch.
Returns the Unicode general category of a character.
Manages visibility of lines for folding and wrapping.
Visual elements added over text.
Text document that handles notifications, DBCS, styling, words and end of line.
Defines the editor state that must be visible to EditorView.
Defines the appearance of the main text area of the editor window.
Defines the main editor class.
Interface between Scintilla and lexers.
Interface for loading into a Scintilla document from a background thread.
Defines the style of indicators which are text decorations such as underlining.
Defines a mapping between keystrokes and commands.
Defines the look of a line marker in the margin .
Defines the appearance of the editor margin.
Data structure used to partition an interval.
Interface to platform facilities.
#define PLATFORM_ASSERT(c)
Definition: Platform.h:544
Classes for caching layout information.
Defines global type name Position in the Sci internal namespace.
Data structure used to store sparse styles.
Defines an enhanced subclass of Editor with calltips, autocomplete and context menu.
#define SCINTILLA_OBJECT_ACCESSIBLE_GET_PRIVATE(inst)
GtkAccessibleClass ScintillaObjectAccessibleClass
static AtkAttributeSet * AddTextIntAttribute(AtkAttributeSet *attributes, AtkTextAttribute attr, gint i)
static void scintilla_object_accessible_class_init(ScintillaObjectAccessibleClass *klass)
static GType scintilla_object_accessible_get_type(GType parent_type)
static AtkStateSet * scintilla_object_accessible_ref_state_set(AtkObject *accessible)
AtkObjectFactoryClass ScintillaObjectAccessibleFactoryClass
#define SCINTILLA_TYPE_OBJECT_ACCESSIBLE
static void scintilla_object_accessible_initialize(AtkObject *obj, gpointer data)
static AtkObject * scintilla_object_accessible_new(GType parent_type, GObject *obj)
static void scintilla_object_accessible_widget_set(GtkAccessible *accessible)
static void scintilla_object_accessible_init(ScintillaObjectAccessible *accessible)
static GType scintilla_object_accessible_factory_get_type(void)
static AtkAttributeSet * AddTextColorAttribute(AtkAttributeSet *attributes, AtkTextAttribute attr, const ColourDesired &colour)
static AtkObject * scintilla_object_accessible_factory_create_accessible(GObject *obj)
GtkAccessible ScintillaObjectAccessible
static GType scintilla_object_accessible_factory_get_accessible_type(void)
static void scintilla_object_accessible_factory_class_init(AtkObjectFactoryClass *klass)
static void scintilla_object_accessible_finalize(GObject *object)
#define WRAPPER_METHOD_BODY(accessible, call, defret)
static AtkAttributeSet * AddTextAttribute(AtkAttributeSet *attributes, AtkTextAttribute attr, gchar *value)
static gpointer scintilla_object_accessible_parent_class
AtkObjectFactory ScintillaObjectAccessibleFactory
static void scintilla_object_accessible_factory_init(ScintillaObjectAccessibleFactory *)
sptr_t scintilla_send_message(ScintillaObject *sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam)
Interface to the edit control.
intptr_t sptr_t
Definition: Scintilla.h:35
#define SCI_POSITIONFROMLINE
Definition: Scintilla.h:439
#define SC_LINECHARACTERINDEX_UTF32
Definition: Scintilla.h:1160
#define SC_MOD_INSERTTEXT
Definition: Scintilla.h:1061
#define SCI_DROPSELECTIONN
Definition: Scintilla.h:933
#define SC_FONT_SIZE_MULTIPLIER
Definition: Scintilla.h:257
#define SCI_WORDENDPOSITION
Definition: Scintilla.h:546
#define SCI_CLEARSELECTIONS
Definition: Scintilla.h:930
#define SCI_POINTXFROMPOSITION
Definition: Scintilla.h:436
#define SC_ACCESSIBILITY_ENABLED
Definition: Scintilla.h:621
#define SCI_GETCURRENTPOS
Definition: Scintilla.h:57
#define SCI_LINEFROMPOSITION
Definition: Scintilla.h:438
#define SCI_TEXTHEIGHT
Definition: Scintilla.h:592
#define SCI_SETTEXT
Definition: Scintilla.h:454
#define SC_MOD_CHANGESTYLE
Definition: Scintilla.h:1063
#define SC_UPDATE_SELECTION
Definition: Scintilla.h:1086
#define SCI_GETREADONLY
Definition: Scintilla.h:398
#define SCI_POSITIONAFTER
Definition: Scintilla.h:781
#define SCI_POINTYFROMPOSITION
Definition: Scintilla.h:437
#define SCN_MODIFIED
Definition: Scintilla.h:1134
#define SCI_GOTOPOS
Definition: Scintilla.h:84
#define SCI_WORDSTARTPOSITION
Definition: Scintilla.h:545
#define SC_MOD_DELETETEXT
Definition: Scintilla.h:1062
#define SCN_UPDATEUI
Definition: Scintilla.h:1133
#define SCI_SETSELECTIONNEND
Definition: Scintilla.h:947
#define SCI_SETSELECTIONNSTART
Definition: Scintilla.h:944
#define SCI_CHARPOSITIONFROMPOINTCLOSE
Definition: Scintilla.h:917
#define SCI_GETLINEENDPOSITION
Definition: Scintilla.h:395
#define SC_MOD_BEFOREDELETE
Definition: Scintilla.h:1072
#define SCI_SETSELECTION
Definition: Scintilla.h:931
#define SCI_ADDSELECTION
Definition: Scintilla.h:932
#define SCI_ISRANGEWORD
Definition: Scintilla.h:547
Classes maintaining the selection.
Main data structure for holding arrays that handle insertions and deletions efficiently.
Safe string copy function which always NUL terminates.
Defines the font and colour style for a class of text.
Functions to handle UTF-8 and UTF-16 strings.
Define UniqueString, a unique_ptr based string type for storage in containers and an allocator for Un...
Store information on how the document is to be viewed.
constexpr unsigned char GetRed() const noexcept
Definition: Platform.h:206
constexpr unsigned char GetBlue() const noexcept
Definition: Platform.h:212
constexpr unsigned char GetGreen() const noexcept
Definition: Platform.h:209
bool DeleteChars(Sci::Position pos, Sci::Position len)
Definition: Document.cxx:1204
char SCI_METHOD StyleAt(Sci_Position position) const override
Definition: Document.h:395
Sci_Position SCI_METHOD Length() const override
Definition: Document.h:430
void ReleaseLineCharacterIndex(int lineCharacterIndex)
Definition: Document.cxx:2179
Sci::Position InsertString(Sci::Position position, const char *s, Sci::Position insertLength)
Insert a string with a length.
Definition: Document.cxx:1246
static std::string TransformLineEnds(const char *s, size_t len, int eolModeWanted)
Definition: Document.cxx:1632
bool IsReadOnly() const noexcept
Definition: Document.h:384
void SCI_METHOD GetCharRange(char *buffer, Sci_Position position, Sci_Position lengthRetrieve) const override
Definition: Document.h:392
void AllocateLineCharacterIndex(int lineCharacterIndex)
Definition: Document.cxx:2175
Sci::Position CountCharacters(Sci::Position startPos, Sci::Position endPos) const noexcept
Definition: Document.cxx:1565
Document * pdoc
Definition: EditModel.h:53
bool IsUnicodeMode() const noexcept
Definition: Editor.cxx:5628
long TextWidth(uptr_t style, const char *text)
Definition: Editor.cxx:1823
void CopyRangeToClipboard(Sci::Position start, Sci::Position end)
Definition: Editor.cxx:4243
ViewStyle vs
Definition: Editor.h:171
std::string RangeText(Sci::Position start, Sci::Position end) const
Definition: Editor.cxx:4199
bool RangeContainsProtected(Sci::Position start, Sci::Position end) const noexcept
Definition: Editor.cxx:789
bool convertPastes
Definition: Editor.h:261
static void CopyText(AtkEditableText *text, gint start, gint end)
static void DeleteText(AtkEditableText *text, gint start, gint end)
static void SetTextContents(AtkEditableText *text, const gchar *contents)
static void PasteText(AtkEditableText *text, gint position)
static void CutText(AtkEditableText *text, gint start, gint end)
static void InsertText(AtkEditableText *text, const gchar *contents, gint length, gint *position)
static AtkAttributeSet * GetRunAttributes(AtkText *text, gint offset, gint *start_offset, gint *end_offset)
static gboolean AddSelection(AtkText *text, gint start, gint end)
static gchar * GetTextAtOffset(AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset)
static void GetCharacterExtents(AtkText *text, gint offset, gint *x, gint *y, gint *width, gint *height, AtkCoordType coords)
static gunichar GetCharacterAtOffset(AtkText *text, gint offset)
static gint GetOffsetAtPoint(AtkText *text, gint x, gint y, AtkCoordType coords)
static gboolean SetSelection(AtkText *text, gint selection_num, gint start, gint end)
static gboolean SetCaretOffset(AtkText *text, gint offset)
static AtkAttributeSet * GetDefaultAttributes(AtkText *text)
static gchar * GetTextBeforeOffset(AtkText *text, int offset, AtkTextBoundary boundary_type, int *start_offset, int *end_offset)
static gboolean RemoveSelection(AtkText *text, gint selection_num)
static gchar * GetSelection(AtkText *text, gint selection_num, gint *start_pos, gint *end_pos)
static gchar * GetTextAfterOffset(AtkText *text, int offset, AtkTextBoundary boundary_type, int *start_offset, int *end_offset)
static gchar * GetText(AtkText *text, int start_offset, int end_offset)
gchar * GetSelection(gint selection_num, int *startChar, int *endChar)
gchar * GetTextAfterOffset(int charOffset, AtkTextBoundary boundaryType, int *startChar, int *endChar)
void ChangeDocument(Document *oldDoc, Document *newDoc)
bool InsertStringUTF8(Sci::Position bytePos, const gchar *utf8, Sci::Position lengthBytes)
gchar * GetTextBeforeOffset(int charOffset, AtkTextBoundary boundaryType, int *startChar, int *endChar)
void InsertText(const gchar *text, int lengthBytes, int *charPosition)
gchar * GetTextRangeUTF8(Sci::Position startByte, Sci::Position endByte)
Sci::Position ByteOffsetFromCharacterOffset(Sci::Position startByte, int characterOffset)
AtkAttributeSet * GetRunAttributes(int charOffset, int *startChar, int *endChar)
void Notify(GtkWidget *widget, gint code, SCNotification *nt)
void SetTextContents(const gchar *contents)
void CutText(int startChar, int endChar)
void CharacterRangeFromByteRange(Sci::Position startByte, Sci::Position endByte, int *startChar, int *endChar)
gboolean AddSelection(int startChar, int endChar)
static AtkObject * WidgetGetAccessibleImpl(GtkWidget *widget, AtkObject **cache, gpointer widget_parent_class)
static void SciNotify(GtkWidget *widget, gint code, SCNotification *nt, gpointer data)
std::vector< SelectionRange > old_sels
ScintillaGTKAccessible(GtkAccessible *accessible_, GtkWidget *widget_)
gchar * GetTextAtOffset(int charOffset, AtkTextBoundary boundaryType, int *startChar, int *endChar)
gint GetOffsetAtPoint(gint x, gint y, AtkCoordType coords)
AtkAttributeSet * GetAttributesForStyle(unsigned int styleNum)
void DeleteText(int startChar, int endChar)
gboolean SetSelection(gint selection_num, int startChar, int endChar)
void CopyText(int startChar, int endChar)
Sci::Position PositionBefore(Sci::Position pos)
int StyleAt(Sci::Position position, bool ensureStyle=false)
void GetCharacterExtents(int charOffset, gint *x, gint *y, gint *width, gint *height, AtkCoordType coords)
void ByteRangeFromCharacterRange(int startChar, int endChar, Sci::Position &startByte, Sci::Position &endByte)
gboolean RemoveSelection(int selection_num)
Sci::Position CharacterOffsetFromByteOffset(Sci::Position byteOffset)
gunichar GetCharacterAtOffset(int charOffset)
Sci::Position PositionAfter(Sci::Position pos)
gchar * GetText(int startChar, int endChar)
sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) override
_ScintillaObject * sci
Definition: ScintillaGTK.h:18
const char * CharacterSetID() const
Sci::Position Position() const noexcept
Definition: Selection.h:34
size_t Count() const noexcept
Definition: Selection.cxx:237
SelectionRange & Range(size_t r) noexcept
Definition: Selection.cxx:250
bool Empty() const noexcept
Definition: Selection.cxx:282
ColourDesired back
Definition: Style.h:62
ColourDesired fore
Definition: Style.h:61
bool visible
Definition: Style.h:67
bool changeable
Definition: Style.h:68
bool underline
Definition: Style.h:64
std::vector< Style > styles
Definition: ViewStyle.h:84
gchar * text
Definition: editor.c:83
ScintillaObject * sci
Definition: editor.c:88
gint pos
Definition: editor.c:87
vString * line
Definition: geany_cobol.c:133
ptrdiff_t Position
Definition: Position.h:19
Styling buffer using one element for each run rather than using a filled buffer.
Definition: Converter.h:9
std::string ConvertText(const char *s, size_t len, const char *charSetDest, const char *charSetSource, bool transliterations, bool silent)
static GeanyProjectPrivate priv
Definition: project.c:56
gint position[2]
Definition: search.c:120
Sci_Position position
Definition: Scintilla.h:1230
Sci_NotifyHeader nmhdr
Definition: Scintilla.h:1229
int modificationType
Definition: Scintilla.h:1244
Sci_Position length
Definition: Scintilla.h:1248
unsigned int code
Definition: Scintilla.h:1225
const char * fontName
Definition: Style.h:14
bool Empty() const noexcept
Definition: Selection.h:100
SelectionPosition Start() const noexcept
Definition: Selection.h:124
SelectionPosition End() const noexcept
Definition: Selection.h:127