1/* gtkatspitextbuffer.c - GtkTextBuffer-related utilities for AT-SPI
2 *
3 * Copyright (c) 2020 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.Free
17 */
18
19#include "config.h"
20#include "gtkatspitextbufferprivate.h"
21#include "gtkatspipangoprivate.h"
22#include "gtktextviewprivate.h"
23
24static const char *
25gtk_justification_to_string (GtkJustification just)
26{
27 switch (just)
28 {
29 case GTK_JUSTIFY_LEFT:
30 return "left";
31 case GTK_JUSTIFY_RIGHT:
32 return "right";
33 case GTK_JUSTIFY_CENTER:
34 return "center";
35 case GTK_JUSTIFY_FILL:
36 return "fill";
37 default:
38 g_assert_not_reached ();
39 }
40}
41
42static const char *
43gtk_text_direction_to_string (GtkTextDirection direction)
44{
45 switch (direction)
46 {
47 case GTK_TEXT_DIR_NONE:
48 return "none";
49 case GTK_TEXT_DIR_LTR:
50 return "ltr";
51 case GTK_TEXT_DIR_RTL:
52 return "rtl";
53 default:
54 g_assert_not_reached ();
55 }
56}
57
58void
59gtk_text_view_add_default_attributes (GtkTextView *view,
60 GVariantBuilder *builder)
61{
62 GtkTextAttributes *text_attrs;
63 PangoFontDescription *font;
64 char *value;
65
66 text_attrs = gtk_text_view_get_default_attributes (text_view: view);
67
68 font = text_attrs->font;
69
70 if (font)
71 gtk_pango_get_font_attributes (font, builder);
72
73 g_variant_builder_add (builder, format_string: "{ss}", "justification",
74 gtk_justification_to_string (just: text_attrs->justification));
75 g_variant_builder_add (builder, format_string: "{ss}", "direction",
76 gtk_text_direction_to_string (direction: text_attrs->direction));
77 g_variant_builder_add (builder, format_string: "{ss}", "wrap-mode",
78 pango_wrap_mode_to_string (mode: (PangoWrapMode)text_attrs->wrap_mode));
79 g_variant_builder_add (builder, format_string: "{ss}", "editable",
80 text_attrs->editable ? "true" : "false");
81 g_variant_builder_add (builder, format_string: "{ss}", "invisible",
82 text_attrs->invisible ? "true" : "false");
83 g_variant_builder_add (builder, format_string: "{ss}", "bg-full-height",
84 text_attrs->bg_full_height ? "true" : "false");
85 g_variant_builder_add (builder, format_string: "{ss}", "strikethrough",
86 text_attrs->appearance.strikethrough ? "true" : "false");
87 g_variant_builder_add (builder, format_string: "{ss}", "underline",
88 pango_underline_to_string (underline: text_attrs->appearance.underline));
89
90 value = g_strdup_printf (format: "%u,%u,%u",
91 (guint)(text_attrs->appearance.bg_rgba->red * 65535),
92 (guint)(text_attrs->appearance.bg_rgba->green * 65535),
93 (guint)(text_attrs->appearance.bg_rgba->blue * 65535));
94 g_variant_builder_add (builder, format_string: "{ss}", "bg-color", value);
95 g_free (mem: value);
96
97 value = g_strdup_printf (format: "%u,%u,%u",
98 (guint)(text_attrs->appearance.fg_rgba->red * 65535),
99 (guint)(text_attrs->appearance.fg_rgba->green * 65535),
100 (guint)(text_attrs->appearance.fg_rgba->blue * 65535));
101 g_variant_builder_add (builder, format_string: "{ss}", "bg-color", value);
102 g_free (mem: value);
103
104 value = g_strdup_printf (format: "%g", text_attrs->font_scale);
105 g_variant_builder_add (builder, format_string: "{ss}", "scale", value);
106 g_free (mem: value);
107
108 value = g_strdup (str: (gchar *)(text_attrs->language));
109 g_variant_builder_add (builder, format_string: "{ss}", "language", value);
110 g_free (mem: value);
111
112 value = g_strdup_printf (format: "%i", text_attrs->appearance.rise);
113 g_variant_builder_add (builder, format_string: "{ss}", "rise", value);
114 g_free (mem: value);
115
116 value = g_strdup_printf (format: "%i", text_attrs->pixels_inside_wrap);
117 g_variant_builder_add (builder, format_string: "{ss}", "pixels-inside-wrap", value);
118 g_free (mem: value);
119
120 value = g_strdup_printf (format: "%i", text_attrs->pixels_below_lines);
121 g_variant_builder_add (builder, format_string: "{ss}", "pixels-below-lines", value);
122 g_free (mem: value);
123
124 value = g_strdup_printf (format: "%i", text_attrs->pixels_above_lines);
125 g_variant_builder_add (builder, format_string: "{ss}", "pixels-above-lines", value);
126 g_free (mem: value);
127
128 value = g_strdup_printf (format: "%i", text_attrs->indent);
129 g_variant_builder_add (builder, format_string: "{ss}", "indent", value);
130 g_free (mem: value);
131
132 value = g_strdup_printf (format: "%i", text_attrs->left_margin);
133 g_variant_builder_add (builder, format_string: "{ss}", "left-margin", value);
134 g_free (mem: value);
135
136 value = g_strdup_printf (format: "%i", text_attrs->right_margin);
137 g_variant_builder_add (builder, format_string: "{ss}", "right-margin", value);
138 g_free (mem: value);
139
140 gtk_text_attributes_unref (values: text_attrs);
141}
142
143void
144gtk_text_buffer_get_run_attributes (GtkTextBuffer *buffer,
145 GVariantBuilder *builder,
146 int offset,
147 int *start_offset,
148 int *end_offset)
149{
150 GtkTextIter iter;
151 GSList *tags, *temp_tags;
152 double scale = 1;
153 gboolean val_set = FALSE;
154
155 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: offset);
156
157 gtk_text_iter_forward_to_tag_toggle (iter: &iter, NULL);
158 *end_offset = gtk_text_iter_get_offset (iter: &iter);
159
160 gtk_text_iter_backward_to_tag_toggle (iter: &iter, NULL);
161 *start_offset = gtk_text_iter_get_offset (iter: &iter);
162
163 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: offset);
164
165 tags = gtk_text_iter_get_tags (iter: &iter);
166 tags = g_slist_reverse (list: tags);
167
168 temp_tags = tags;
169 while (temp_tags && !val_set)
170 {
171 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
172 PangoStyle style;
173
174 g_object_get (object: tag,
175 first_property_name: "style-set", &val_set,
176 "style", &style,
177 NULL);
178 if (val_set)
179 g_variant_builder_add (builder, format_string: "{ss}", "style", pango_style_to_string (style));
180 temp_tags = temp_tags->next;
181 }
182 val_set = FALSE;
183
184 temp_tags = tags;
185 while (temp_tags && !val_set)
186 {
187 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
188 PangoVariant variant;
189
190 g_object_get (object: tag,
191 first_property_name: "variant-set", &val_set,
192 "variant", &variant,
193 NULL);
194 if (val_set)
195 g_variant_builder_add (builder, format_string: "{ss}", "variant", pango_variant_to_string (variant));
196 temp_tags = temp_tags->next;
197 }
198 val_set = FALSE;
199
200 temp_tags = tags;
201 while (temp_tags && !val_set)
202 {
203 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
204 PangoStretch stretch;
205
206 g_object_get (object: tag,
207 first_property_name: "stretch-set", &val_set,
208 "stretch", &stretch,
209 NULL);
210 if (val_set)
211 g_variant_builder_add (builder, format_string: "{ss}", "stretch", pango_stretch_to_string (stretch));
212 temp_tags = temp_tags->next;
213 }
214 val_set = FALSE;
215
216 temp_tags = tags;
217 while (temp_tags && !val_set)
218 {
219 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
220 GtkJustification justification;
221
222 g_object_get (object: tag,
223 first_property_name: "justification-set", &val_set,
224 "justification", &justification,
225 NULL);
226 if (val_set)
227 g_variant_builder_add (builder, format_string: "{ss}", "justification", gtk_justification_to_string (just: justification));
228 temp_tags = temp_tags->next;
229 }
230 val_set = FALSE;
231
232 temp_tags = tags;
233 while (temp_tags && !val_set)
234 {
235 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
236 GtkTextDirection direction;
237
238 g_object_get (object: tag, first_property_name: "direction", &direction, NULL);
239 if (direction != GTK_TEXT_DIR_NONE)
240 {
241 val_set = TRUE;
242 g_variant_builder_add (builder, format_string: "{ss}", "direction", gtk_text_direction_to_string (direction));
243 }
244 temp_tags = temp_tags->next;
245 }
246 val_set = FALSE;
247
248 temp_tags = tags;
249 while (temp_tags && !val_set)
250 {
251 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
252 GtkWrapMode wrap_mode;
253
254 g_object_get (object: tag,
255 first_property_name: "wrap-mode-set", &val_set,
256 "wrap-mode", &wrap_mode,
257 NULL);
258 if (val_set)
259 g_variant_builder_add (builder, format_string: "{ss}", "wrap-mode", pango_wrap_mode_to_string (mode: (PangoWrapMode)wrap_mode));
260 temp_tags = temp_tags->next;
261 }
262 val_set = FALSE;
263
264 temp_tags = tags;
265 while (temp_tags && !val_set)
266 {
267 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
268
269 g_object_get (object: tag, first_property_name: "foreground-set", &val_set, NULL);
270 if (val_set)
271 {
272 GdkRGBA *rgba;
273 char *value;
274
275 g_object_get (object: tag, first_property_name: "foreground", &rgba, NULL);
276 value = g_strdup_printf (format: "%u,%u,%u",
277 (guint) rgba->red * 65535,
278 (guint) rgba->green * 65535,
279 (guint) rgba->blue * 65535);
280 gdk_rgba_free (rgba);
281 g_variant_builder_add (builder, format_string: "{ss}", "fg-color", value);
282 g_free (mem: value);
283 }
284 temp_tags = temp_tags->next;
285 }
286 val_set = FALSE;
287
288 temp_tags = tags;
289 while (temp_tags && !val_set)
290 {
291 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
292
293 g_object_get (object: tag, first_property_name: "background-set", &val_set, NULL);
294 if (val_set)
295 {
296 GdkRGBA *rgba;
297 char *value;
298
299 g_object_get (object: tag, first_property_name: "background-rgba", &rgba, NULL);
300 value = g_strdup_printf (format: "%u,%u,%u",
301 (guint) rgba->red * 65535,
302 (guint) rgba->green * 65535,
303 (guint) rgba->blue * 65535);
304 gdk_rgba_free (rgba);
305 g_variant_builder_add (builder, format_string: "{ss}", "bg-color", value);
306 g_free (mem: value);
307 }
308 temp_tags = temp_tags->next;
309 }
310 val_set = FALSE;
311
312 temp_tags = tags;
313 while (temp_tags && !val_set)
314 {
315 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
316
317 g_object_get (object: tag, first_property_name: "family-set", &val_set, NULL);
318
319 if (val_set)
320 {
321 char *value;
322 g_object_get (object: tag, first_property_name: "family", &value, NULL);
323 g_variant_builder_add (builder, format_string: "{ss}", "family-name", value);
324 g_free (mem: value);
325 }
326 temp_tags = temp_tags->next;
327 }
328 val_set = FALSE;
329
330 temp_tags = tags;
331 while (temp_tags && !val_set)
332 {
333 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
334
335 g_object_get (object: tag, first_property_name: "language-set", &val_set, NULL);
336
337 if (val_set)
338 {
339 char *value;
340 g_object_get (object: tag, first_property_name: "language", &value, NULL);
341 g_variant_builder_add (builder, format_string: "{ss}", "language", value);
342 g_free (mem: value);
343 }
344 temp_tags = temp_tags->next;
345 }
346 val_set = FALSE;
347
348 temp_tags = tags;
349 while (temp_tags && !val_set)
350 {
351 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
352 int weight;
353
354 g_object_get (object: tag,
355 first_property_name: "weight-set", &val_set,
356 "weight", &weight,
357 NULL);
358
359 if (val_set)
360 {
361 char *value;
362 value = g_strdup_printf (format: "%d", weight);
363 g_variant_builder_add (builder, format_string: "{ss}", "weight", value);
364 g_free (mem: value);
365 }
366 temp_tags = temp_tags->next;
367 }
368 val_set = FALSE;
369
370 /* scale is special as the effective value is the product
371 * of all specified values
372 */
373 temp_tags = tags;
374 while (temp_tags)
375 {
376 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
377 gboolean scale_set;
378
379 g_object_get (object: tag, first_property_name: "scale-set", &scale_set, NULL);
380 if (scale_set)
381 {
382 double font_scale;
383 g_object_get (object: tag, first_property_name: "scale", &font_scale, NULL);
384 val_set = TRUE;
385 scale *= font_scale;
386 }
387 temp_tags = temp_tags->next;
388 }
389 if (val_set)
390 {
391 char *value = g_strdup_printf (format: "%g", scale);
392 g_variant_builder_add (builder, format_string: "{ss}", "scale", value);
393 g_free (mem: value);
394 }
395 val_set = FALSE;
396
397 temp_tags = tags;
398 while (temp_tags && !val_set)
399 {
400 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
401 int size;
402
403 g_object_get (object: tag,
404 first_property_name: "size-set", &val_set,
405 "size", &size,
406 NULL);
407 if (val_set)
408 {
409 char *value = g_strdup_printf (format: "%i", size);
410 g_variant_builder_add (builder, format_string: "{ss}", "size", value);
411 g_free (mem: value);
412 }
413 temp_tags = temp_tags->next;
414 }
415 val_set = FALSE;
416
417 temp_tags = tags;
418 while (temp_tags && !val_set)
419 {
420 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
421 gboolean strikethrough;
422
423 g_object_get (object: tag,
424 first_property_name: "strikethrough-set", &val_set,
425 "strikethrough", &strikethrough,
426 NULL);
427 if (val_set)
428 g_variant_builder_add (builder, format_string: "{ss}", "strikethrough", strikethrough ? "true" : "false");
429 temp_tags = temp_tags->next;
430 }
431 val_set = FALSE;
432
433 temp_tags = tags;
434 while (temp_tags && !val_set)
435 {
436 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
437 PangoUnderline underline;
438
439 g_object_get (object: tag,
440 first_property_name: "underline-set", &val_set,
441 "underline", &underline,
442 NULL);
443 if (val_set)
444 g_variant_builder_add (builder, format_string: "{ss}", "underline",
445 pango_underline_to_string (underline));
446 temp_tags = temp_tags->next;
447 }
448 val_set = FALSE;
449
450 temp_tags = tags;
451 while (temp_tags && !val_set)
452 {
453 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
454 int rise;
455
456 g_object_get (object: tag,
457 first_property_name: "rise-set", &val_set,
458 "rise", &rise,
459 NULL);
460 if (val_set)
461 {
462 char *value = g_strdup_printf (format: "%i", rise);
463 g_variant_builder_add (builder, format_string: "{ss}", "rise", value);
464 g_free (mem: value);
465 }
466 temp_tags = temp_tags->next;
467 }
468 val_set = FALSE;
469
470 temp_tags = tags;
471 while (temp_tags && !val_set)
472 {
473 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
474 gboolean bg_full_height;
475
476 g_object_get (object: tag,
477 first_property_name: "background-full-height-set", &val_set,
478 "background-full-height", &bg_full_height,
479 NULL);
480 if (val_set)
481 g_variant_builder_add (builder, format_string: "{ss}", "bg-full-height", bg_full_height ? "true" : "false");
482 temp_tags = temp_tags->next;
483 }
484 val_set = FALSE;
485
486 temp_tags = tags;
487 while (temp_tags && !val_set)
488 {
489 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
490 int pixels;
491
492 g_object_get (object: tag,
493 first_property_name: "pixels-inside-wrap-set", &val_set,
494 "pixels-inside-wrap", &pixels,
495 NULL);
496 if (val_set)
497 {
498 char *value = g_strdup_printf (format: "%i", pixels);
499 g_variant_builder_add (builder, format_string: "{ss}", "pixels-inside-wrap", value);
500 g_free (mem: value);
501 }
502 temp_tags = temp_tags->next;
503 }
504 val_set = FALSE;
505
506 temp_tags = tags;
507 while (temp_tags && !val_set)
508 {
509 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
510 int pixels;
511
512 g_object_get (object: tag,
513 first_property_name: "pixels-below-lines-set", &val_set,
514 "pixels-below-lines", &pixels,
515 NULL);
516 if (val_set)
517 {
518 char *value = g_strdup_printf (format: "%i", pixels);
519 g_variant_builder_add (builder, format_string: "{ss}", "pixels-below-lines", value);
520 g_free (mem: value);
521 }
522 temp_tags = temp_tags->next;
523 }
524 val_set = FALSE;
525
526 temp_tags = tags;
527 while (temp_tags && !val_set)
528 {
529 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
530 int pixels;
531
532 g_object_get (object: tag,
533 first_property_name: "pixels-above-lines-set", &val_set,
534 "pixels-above-lines", &pixels,
535 NULL);
536 if (val_set)
537 {
538 char *value = g_strdup_printf (format: "%i", pixels);
539 g_variant_builder_add (builder, format_string: "{ss}", "pixels-above-lines", value);
540 g_free (mem: value);
541 }
542 temp_tags = temp_tags->next;
543 }
544 val_set = FALSE;
545
546 temp_tags = tags;
547 while (temp_tags && !val_set)
548 {
549 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
550 gboolean editable;
551
552 g_object_get (object: tag,
553 first_property_name: "editable-set", &val_set,
554 "editable", &editable,
555 NULL);
556 if (val_set)
557 g_variant_builder_add (builder, format_string: "{ss}", "editable", editable ? "true" : "false");
558 temp_tags = temp_tags->next;
559 }
560 val_set = FALSE;
561
562 temp_tags = tags;
563 while (temp_tags && !val_set)
564 {
565 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
566 gboolean invisible;
567
568 g_object_get (object: tag,
569 first_property_name: "invisible-set", &val_set,
570 "invisible", &invisible,
571 NULL);
572 if (val_set)
573 g_variant_builder_add (builder, format_string: "{ss}", "invisible", invisible ? "true" : "false");
574 temp_tags = temp_tags->next;
575 }
576 val_set = FALSE;
577
578 temp_tags = tags;
579 while (temp_tags && !val_set)
580 {
581 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
582 int indent;
583
584 g_object_get (object: tag,
585 first_property_name: "indent-set", &val_set,
586 "indent", &indent,
587 NULL);
588 if (val_set)
589 {
590 char *value = g_strdup_printf (format: "%i", indent);
591 g_variant_builder_add (builder, format_string: "{ss}", "indent", value);
592 g_free (mem: value);
593 }
594 temp_tags = temp_tags->next;
595 }
596 val_set = FALSE;
597
598 temp_tags = tags;
599 while (temp_tags && !val_set)
600 {
601 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
602 int margin;
603
604 g_object_get (object: tag,
605 first_property_name: "right-margin-set", &val_set,
606 "right-margin", &margin,
607 NULL);
608 if (val_set)
609 {
610 char *value = g_strdup_printf (format: "%i", margin);
611 g_variant_builder_add (builder, format_string: "{ss}", "right-margin", value);
612 g_free (mem: value);
613 }
614 temp_tags = temp_tags->next;
615 }
616 val_set = FALSE;
617
618 temp_tags = tags;
619 while (temp_tags && !val_set)
620 {
621 GtkTextTag *tag = GTK_TEXT_TAG (temp_tags->data);
622 int margin;
623
624 g_object_get (object: tag,
625 first_property_name: "left-margin-set", &val_set,
626 "left-margin", &margin,
627 NULL);
628 if (val_set)
629 {
630 char *value = g_strdup_printf (format: "%i", margin);
631 g_variant_builder_add (builder, format_string: "{ss}", "left-margin", value);
632 g_free (mem: value);
633 }
634 temp_tags = temp_tags->next;
635 }
636 val_set = FALSE;
637
638 g_slist_free (list: tags);
639}
640
641char *
642gtk_text_view_get_text_before (GtkTextView *view,
643 int offset,
644 AtspiTextBoundaryType boundary_type,
645 int *start_offset,
646 int *end_offset)
647{
648 GtkTextBuffer *buffer;
649 GtkTextIter pos, start, end;
650
651 buffer = gtk_text_view_get_buffer (text_view: view);
652 gtk_text_buffer_get_iter_at_offset (buffer, iter: &pos, char_offset: offset);
653 start = end = pos;
654
655 switch (boundary_type)
656 {
657 case ATSPI_TEXT_BOUNDARY_CHAR:
658 gtk_text_iter_backward_char (iter: &start);
659 break;
660
661 case ATSPI_TEXT_BOUNDARY_WORD_START:
662 if (!gtk_text_iter_starts_word (iter: &start))
663 gtk_text_iter_backward_word_start (iter: &start);
664 end = start;
665 gtk_text_iter_backward_word_start (iter: &start);
666 break;
667
668 case ATSPI_TEXT_BOUNDARY_WORD_END:
669 if (gtk_text_iter_inside_word (iter: &start) &&
670 !gtk_text_iter_starts_word (iter: &start))
671 gtk_text_iter_backward_word_start (iter: &start);
672 while (!gtk_text_iter_ends_word (iter: &start))
673 {
674 if (!gtk_text_iter_backward_char (iter: &start))
675 break;
676 }
677 end = start;
678 gtk_text_iter_backward_word_start (iter: &start);
679 while (!gtk_text_iter_ends_word (iter: &start))
680 {
681 if (!gtk_text_iter_backward_char (iter: &start))
682 break;
683 }
684 break;
685
686 case ATSPI_TEXT_BOUNDARY_SENTENCE_START:
687 if (!gtk_text_iter_starts_sentence (iter: &start))
688 gtk_text_iter_backward_sentence_start (iter: &start);
689 end = start;
690 gtk_text_iter_backward_sentence_start (iter: &start);
691 break;
692
693 case ATSPI_TEXT_BOUNDARY_SENTENCE_END:
694 if (gtk_text_iter_inside_sentence (iter: &start) &&
695 !gtk_text_iter_starts_sentence (iter: &start))
696 gtk_text_iter_backward_sentence_start (iter: &start);
697 while (!gtk_text_iter_ends_sentence (iter: &start))
698 {
699 if (!gtk_text_iter_backward_char (iter: &start))
700 break;
701 }
702 end = start;
703 gtk_text_iter_backward_sentence_start (iter: &start);
704 while (!gtk_text_iter_ends_sentence (iter: &start))
705 {
706 if (!gtk_text_iter_backward_char (iter: &start))
707 break;
708 }
709 break;
710
711 case ATSPI_TEXT_BOUNDARY_LINE_START:
712 gtk_text_view_backward_display_line_start (text_view: view, iter: &start);
713 end = start;
714 gtk_text_view_backward_display_line (text_view: view, iter: &start);
715 gtk_text_view_backward_display_line_start (text_view: view, iter: &start);
716 break;
717
718 case ATSPI_TEXT_BOUNDARY_LINE_END:
719 gtk_text_view_backward_display_line_start (text_view: view, iter: &start);
720 if (!gtk_text_iter_is_start (iter: &start))
721 {
722 gtk_text_view_backward_display_line (text_view: view, iter: &start);
723 end = start;
724 gtk_text_view_forward_display_line_end (text_view: view, iter: &end);
725 if (!gtk_text_iter_is_start (iter: &start))
726 {
727 if (gtk_text_view_backward_display_line (text_view: view, iter: &start))
728 gtk_text_view_forward_display_line_end (text_view: view, iter: &start);
729 else
730 gtk_text_iter_set_offset (iter: &start, char_offset: 0);
731 }
732 }
733 else
734 end = start;
735 break;
736
737 default:
738 g_assert_not_reached ();
739 }
740
741 *start_offset = gtk_text_iter_get_offset (iter: &start);
742 *end_offset = gtk_text_iter_get_offset (iter: &end);
743
744 return gtk_text_buffer_get_slice (buffer, start: &start, end: &end, FALSE);
745}
746
747char *
748gtk_text_view_get_text_at (GtkTextView *view,
749 int offset,
750 AtspiTextBoundaryType boundary_type,
751 int *start_offset,
752 int *end_offset)
753{
754 GtkTextBuffer *buffer;
755 GtkTextIter pos, start, end;
756
757 buffer = gtk_text_view_get_buffer (text_view: view);
758 gtk_text_buffer_get_iter_at_offset (buffer, iter: &pos, char_offset: offset);
759 start = end = pos;
760
761 switch (boundary_type)
762 {
763 case ATSPI_TEXT_BOUNDARY_CHAR:
764 gtk_text_iter_forward_char (iter: &end);
765 break;
766
767 case ATSPI_TEXT_BOUNDARY_WORD_START:
768 if (!gtk_text_iter_starts_word (iter: &start))
769 gtk_text_iter_backward_word_start (iter: &start);
770 if (gtk_text_iter_inside_word (iter: &end))
771 gtk_text_iter_forward_word_end (iter: &end);
772 while (!gtk_text_iter_starts_word (iter: &end))
773 {
774 if (!gtk_text_iter_forward_char (iter: &end))
775 break;
776 }
777 break;
778
779 case ATSPI_TEXT_BOUNDARY_WORD_END:
780 if (gtk_text_iter_inside_word (iter: &start) &&
781 !gtk_text_iter_starts_word (iter: &start))
782 gtk_text_iter_backward_word_start (iter: &start);
783 while (!gtk_text_iter_ends_word (iter: &start))
784 {
785 if (!gtk_text_iter_backward_char (iter: &start))
786 break;
787 }
788 gtk_text_iter_forward_word_end (iter: &end);
789 break;
790
791 case ATSPI_TEXT_BOUNDARY_SENTENCE_START:
792 if (!gtk_text_iter_starts_sentence (iter: &start))
793 gtk_text_iter_backward_sentence_start (iter: &start);
794 if (gtk_text_iter_inside_sentence (iter: &end))
795 gtk_text_iter_forward_sentence_end (iter: &end);
796 while (!gtk_text_iter_starts_sentence (iter: &end))
797 {
798 if (!gtk_text_iter_forward_char (iter: &end))
799 break;
800 }
801 break;
802
803 case ATSPI_TEXT_BOUNDARY_SENTENCE_END:
804 if (gtk_text_iter_inside_sentence (iter: &start) &&
805 !gtk_text_iter_starts_sentence (iter: &start))
806 gtk_text_iter_backward_sentence_start (iter: &start);
807 while (!gtk_text_iter_ends_sentence (iter: &start))
808 {
809 if (!gtk_text_iter_backward_char (iter: &start))
810 break;
811 }
812 gtk_text_iter_forward_sentence_end (iter: &end);
813 break;
814
815 case ATSPI_TEXT_BOUNDARY_LINE_START:
816 gtk_text_view_backward_display_line_start (text_view: view, iter: &start);
817 gtk_text_view_forward_display_line (text_view: view, iter: &end);
818 break;
819
820 case ATSPI_TEXT_BOUNDARY_LINE_END:
821 gtk_text_view_backward_display_line_start (text_view: view, iter: &start);
822 if (!gtk_text_iter_is_start (iter: &start))
823 {
824 gtk_text_view_backward_display_line (text_view: view, iter: &start);
825 gtk_text_view_forward_display_line_end (text_view: view, iter: &start);
826 }
827 gtk_text_view_forward_display_line_end (text_view: view, iter: &end);
828 break;
829
830 default:
831 g_assert_not_reached ();
832 }
833
834 *start_offset = gtk_text_iter_get_offset (iter: &start);
835 *end_offset = gtk_text_iter_get_offset (iter: &end);
836
837 return gtk_text_buffer_get_slice (buffer, start: &start, end: &end, FALSE);
838}
839
840char *
841gtk_text_view_get_text_after (GtkTextView *view,
842 int offset,
843 AtspiTextBoundaryType boundary_type,
844 int *start_offset,
845 int *end_offset)
846{
847 GtkTextBuffer *buffer;
848 GtkTextIter pos, start, end;
849
850 buffer = gtk_text_view_get_buffer (text_view: view);
851 gtk_text_buffer_get_iter_at_offset (buffer, iter: &pos, char_offset: offset);
852 start = end = pos;
853
854 switch (boundary_type)
855 {
856 case ATSPI_TEXT_BOUNDARY_CHAR:
857 gtk_text_iter_forward_char (iter: &start);
858 gtk_text_iter_forward_chars (iter: &end, count: 2);
859 break;
860
861 case ATSPI_TEXT_BOUNDARY_WORD_START:
862 if (gtk_text_iter_inside_word (iter: &end))
863 gtk_text_iter_forward_word_end (iter: &end);
864 while (!gtk_text_iter_starts_word (iter: &end))
865 {
866 if (!gtk_text_iter_forward_char (iter: &end))
867 break;
868 }
869 start = end;
870 if (!gtk_text_iter_is_end (iter: &end))
871 {
872 gtk_text_iter_forward_word_end (iter: &end);
873 while (!gtk_text_iter_starts_word (iter: &end))
874 {
875 if (!gtk_text_iter_forward_char (iter: &end))
876 break;
877 }
878 }
879 break;
880
881 case ATSPI_TEXT_BOUNDARY_WORD_END:
882 gtk_text_iter_forward_word_end (iter: &end);
883 start = end;
884 if (!gtk_text_iter_is_end (iter: &end))
885 gtk_text_iter_forward_word_end (iter: &end);
886 break;
887
888 case ATSPI_TEXT_BOUNDARY_SENTENCE_START:
889 if (gtk_text_iter_inside_sentence (iter: &end))
890 gtk_text_iter_forward_sentence_end (iter: &end);
891 while (!gtk_text_iter_starts_sentence (iter: &end))
892 {
893 if (!gtk_text_iter_forward_char (iter: &end))
894 break;
895 }
896 start = end;
897 if (!gtk_text_iter_is_end (iter: &end))
898 {
899 gtk_text_iter_forward_sentence_end (iter: &end);
900 while (!gtk_text_iter_starts_sentence (iter: &end))
901 {
902 if (!gtk_text_iter_forward_char (iter: &end))
903 break;
904 }
905 }
906 break;
907
908 case ATSPI_TEXT_BOUNDARY_SENTENCE_END:
909 gtk_text_iter_forward_sentence_end (iter: &end);
910 start = end;
911 if (!gtk_text_iter_is_end (iter: &end))
912 gtk_text_iter_forward_sentence_end (iter: &end);
913 break;
914
915 case ATSPI_TEXT_BOUNDARY_LINE_START:
916 gtk_text_view_forward_display_line (text_view: view, iter: &end);
917 start = end;
918 gtk_text_view_forward_display_line (text_view: view, iter: &end);
919 break;
920
921 case ATSPI_TEXT_BOUNDARY_LINE_END:
922 gtk_text_view_forward_display_line_end (text_view: view, iter: &end);
923 start = end;
924 gtk_text_view_forward_display_line (text_view: view, iter: &end);
925 gtk_text_view_forward_display_line_end (text_view: view, iter: &end);
926 break;
927
928 default:
929 g_assert_not_reached ();
930 }
931
932 *start_offset = gtk_text_iter_get_offset (iter: &start);
933 *end_offset = gtk_text_iter_get_offset (iter: &end);
934
935 return gtk_text_buffer_get_slice (buffer, start: &start, end: &end, FALSE);
936}
937
938char *
939gtk_text_view_get_string_at (GtkTextView *view,
940 int offset,
941 AtspiTextGranularity granularity,
942 int *start_offset,
943 int *end_offset)
944{
945 GtkTextBuffer *buffer;
946 GtkTextIter pos, start, end;
947
948 buffer = gtk_text_view_get_buffer (text_view: view);
949 gtk_text_buffer_get_iter_at_offset (buffer, iter: &pos, char_offset: offset);
950 start = end = pos;
951
952 if (granularity == ATSPI_TEXT_GRANULARITY_CHAR)
953 {
954 gtk_text_iter_forward_char (iter: &end);
955 }
956 else if (granularity == ATSPI_TEXT_GRANULARITY_WORD)
957 {
958 if (!gtk_text_iter_starts_word (iter: &start))
959 gtk_text_iter_backward_word_start (iter: &start);
960 gtk_text_iter_forward_word_end (iter: &end);
961 }
962 else if (granularity == ATSPI_TEXT_GRANULARITY_SENTENCE)
963 {
964 if (!gtk_text_iter_starts_sentence (iter: &start))
965 gtk_text_iter_backward_sentence_start (iter: &start);
966 gtk_text_iter_forward_sentence_end (iter: &end);
967 }
968 else if (granularity == ATSPI_TEXT_GRANULARITY_LINE)
969 {
970 if (!gtk_text_view_starts_display_line (text_view: view, iter: &start))
971 gtk_text_view_backward_display_line (text_view: view, iter: &start);
972 gtk_text_view_forward_display_line_end (text_view: view, iter: &end);
973 }
974 else if (granularity == ATSPI_TEXT_GRANULARITY_PARAGRAPH)
975 {
976 gtk_text_iter_set_line_offset (iter: &start, char_on_line: 0);
977 gtk_text_iter_forward_to_line_end (iter: &end);
978 }
979
980 *start_offset = gtk_text_iter_get_offset (iter: &start);
981 *end_offset = gtk_text_iter_get_offset (iter: &end);
982
983 return gtk_text_buffer_get_slice (buffer, start: &start, end: &end, FALSE);
984}
985

source code of gtk/gtk/a11y/gtkatspitextbuffer.c