1 | /* GAIL - The GNOME Accessibility Implementation Library |
---|
2 | * Copyright 2001, 2002, 2003 Sun Microsystems Inc. |
---|
3 | * |
---|
4 | * This library is free software; you can redistribute it and/or |
---|
5 | * modify it under the terms of the GNU Lesser General Public |
---|
6 | * License as published by the Free Software Foundation; either |
---|
7 | * version 2 of the License, or (at your option) any later version. |
---|
8 | * |
---|
9 | * This library is distributed in the hope that it will be useful, |
---|
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
12 | * Lesser General Public License for more details. |
---|
13 | * |
---|
14 | * You should have received a copy of the GNU Lesser General Public |
---|
15 | * License along with this library; if not, write to the |
---|
16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
17 | * Boston, MA 02111-1307, USA. |
---|
18 | */ |
---|
19 | |
---|
20 | #include <string.h> |
---|
21 | #include <stdlib.h> |
---|
22 | #include <gtk/gtk.h> |
---|
23 | #include "gailtextview.h" |
---|
24 | #include <libgail-util/gailmisc.h> |
---|
25 | |
---|
26 | static void gail_text_view_class_init (GailTextViewClass *klass); |
---|
27 | static void gail_text_view_init (GailTextView *text_view); |
---|
28 | |
---|
29 | static void gail_text_view_real_initialize (AtkObject *obj, |
---|
30 | gpointer data); |
---|
31 | static void gail_text_view_real_notify_gtk (GObject *obj, |
---|
32 | GParamSpec *pspec); |
---|
33 | |
---|
34 | static void gail_text_view_finalize (GObject *object); |
---|
35 | |
---|
36 | static void atk_text_interface_init (AtkTextIface *iface); |
---|
37 | |
---|
38 | /* atkobject.h */ |
---|
39 | |
---|
40 | static AtkStateSet* gail_text_view_ref_state_set (AtkObject *accessible); |
---|
41 | |
---|
42 | /* atktext.h */ |
---|
43 | |
---|
44 | static gchar* gail_text_view_get_text_after_offset (AtkText *text, |
---|
45 | gint offset, |
---|
46 | AtkTextBoundary boundary_type, |
---|
47 | gint *start_offset, |
---|
48 | gint *end_offset); |
---|
49 | static gchar* gail_text_view_get_text_at_offset (AtkText *text, |
---|
50 | gint offset, |
---|
51 | AtkTextBoundary boundary_type, |
---|
52 | gint *start_offset, |
---|
53 | gint *end_offset); |
---|
54 | static gchar* gail_text_view_get_text_before_offset (AtkText *text, |
---|
55 | gint offset, |
---|
56 | AtkTextBoundary boundary_type, |
---|
57 | gint *start_offset, |
---|
58 | gint *end_offset); |
---|
59 | static gchar* gail_text_view_get_text (AtkText*text, |
---|
60 | gint start_offset, |
---|
61 | gint end_offset); |
---|
62 | static gunichar gail_text_view_get_character_at_offset (AtkText *text, |
---|
63 | gint offset); |
---|
64 | static gint gail_text_view_get_character_count (AtkText *text); |
---|
65 | static gint gail_text_view_get_caret_offset (AtkText *text); |
---|
66 | static gboolean gail_text_view_set_caret_offset (AtkText *text, |
---|
67 | gint offset); |
---|
68 | static gint gail_text_view_get_offset_at_point (AtkText *text, |
---|
69 | gint x, |
---|
70 | gint y, |
---|
71 | AtkCoordType coords); |
---|
72 | static gint gail_text_view_get_n_selections (AtkText *text); |
---|
73 | static gchar* gail_text_view_get_selection (AtkText *text, |
---|
74 | gint selection_num, |
---|
75 | gint *start_offset, |
---|
76 | gint *end_offset); |
---|
77 | static gboolean gail_text_view_add_selection (AtkText *text, |
---|
78 | gint start_offset, |
---|
79 | gint end_offset); |
---|
80 | static gboolean gail_text_view_remove_selection (AtkText *text, |
---|
81 | gint selection_num); |
---|
82 | static gboolean gail_text_view_set_selection (AtkText *text, |
---|
83 | gint selection_num, |
---|
84 | gint start_offset, |
---|
85 | gint end_offset); |
---|
86 | static void gail_text_view_get_character_extents (AtkText *text, |
---|
87 | gint offset, |
---|
88 | gint *x, |
---|
89 | gint *y, |
---|
90 | gint *width, |
---|
91 | gint *height, |
---|
92 | AtkCoordType coords); |
---|
93 | static AtkAttributeSet * gail_text_view_get_run_attributes |
---|
94 | (AtkText *text, |
---|
95 | gint offset, |
---|
96 | gint *start_offset, |
---|
97 | gint *end_offset); |
---|
98 | static AtkAttributeSet * gail_text_view_get_default_attributes |
---|
99 | (AtkText *text); |
---|
100 | /* atkeditabletext.h */ |
---|
101 | |
---|
102 | static void atk_editable_text_interface_init (AtkEditableTextIface *iface); |
---|
103 | static gboolean gail_text_view_set_run_attributes (AtkEditableText *text, |
---|
104 | AtkAttributeSet *attrib_set, |
---|
105 | gint start_offset, |
---|
106 | gint end_offset); |
---|
107 | static void gail_text_view_set_text_contents (AtkEditableText *text, |
---|
108 | const gchar *string); |
---|
109 | static void gail_text_view_insert_text (AtkEditableText *text, |
---|
110 | const gchar *string, |
---|
111 | gint length, |
---|
112 | gint *position); |
---|
113 | static void gail_text_view_copy_text (AtkEditableText *text, |
---|
114 | gint start_pos, |
---|
115 | gint end_pos); |
---|
116 | static void gail_text_view_cut_text (AtkEditableText *text, |
---|
117 | gint start_pos, |
---|
118 | gint end_pos); |
---|
119 | static void gail_text_view_delete_text (AtkEditableText *text, |
---|
120 | gint start_pos, |
---|
121 | gint end_pos); |
---|
122 | static void gail_text_view_paste_text (AtkEditableText *text, |
---|
123 | gint position); |
---|
124 | static void gail_text_view_paste_received (GtkClipboard *clipboard, |
---|
125 | const gchar *text, |
---|
126 | gpointer data); |
---|
127 | |
---|
128 | /* Callbacks */ |
---|
129 | |
---|
130 | static void _gail_text_view_insert_text_cb (GtkTextBuffer *buffer, |
---|
131 | GtkTextIter *arg1, |
---|
132 | gchar *arg2, |
---|
133 | gint arg3, |
---|
134 | gpointer user_data); |
---|
135 | static void _gail_text_view_delete_range_cb (GtkTextBuffer *buffer, |
---|
136 | GtkTextIter *arg1, |
---|
137 | GtkTextIter *arg2, |
---|
138 | gpointer user_data); |
---|
139 | static void _gail_text_view_changed_cb (GtkTextBuffer *buffer, |
---|
140 | gpointer user_data); |
---|
141 | static void _gail_text_view_mark_set_cb (GtkTextBuffer *buffer, |
---|
142 | GtkTextIter *arg1, |
---|
143 | GtkTextMark *arg2, |
---|
144 | gpointer user_data); |
---|
145 | static gchar* get_text_near_offset (AtkText *text, |
---|
146 | GailOffsetType function, |
---|
147 | AtkTextBoundary boundary_type, |
---|
148 | gint offset, |
---|
149 | gint *start_offset, |
---|
150 | gint *end_offset); |
---|
151 | static gint get_insert_offset (GtkTextBuffer *buffer); |
---|
152 | static gint get_selection_bound (GtkTextBuffer *buffer); |
---|
153 | static void emit_text_caret_moved (GailTextView *gail_text_view, |
---|
154 | gint insert_offset); |
---|
155 | static gint insert_idle_handler (gpointer data); |
---|
156 | |
---|
157 | static GailWidgetClass *parent_class = NULL; |
---|
158 | |
---|
159 | typedef struct _GailTextViewPaste GailTextViewPaste; |
---|
160 | |
---|
161 | struct _GailTextViewPaste |
---|
162 | { |
---|
163 | GtkTextBuffer* buffer; |
---|
164 | gint position; |
---|
165 | }; |
---|
166 | |
---|
167 | GType |
---|
168 | gail_text_view_get_type (void) |
---|
169 | { |
---|
170 | static GType type = 0; |
---|
171 | |
---|
172 | if (!type) |
---|
173 | { |
---|
174 | static const GTypeInfo tinfo = |
---|
175 | { |
---|
176 | sizeof (GailTextViewClass), |
---|
177 | (GBaseInitFunc) NULL, /* base init */ |
---|
178 | (GBaseFinalizeFunc) NULL, /* base finalize */ |
---|
179 | (GClassInitFunc) gail_text_view_class_init, /* class init */ |
---|
180 | (GClassFinalizeFunc) NULL, /* class finalize */ |
---|
181 | NULL, /* class data */ |
---|
182 | sizeof (GailTextView), /* instance size */ |
---|
183 | 0, /* nb preallocs */ |
---|
184 | (GInstanceInitFunc) gail_text_view_init, /* instance init */ |
---|
185 | NULL /* value table */ |
---|
186 | }; |
---|
187 | |
---|
188 | static const GInterfaceInfo atk_editable_text_info = |
---|
189 | { |
---|
190 | (GInterfaceInitFunc) atk_editable_text_interface_init, |
---|
191 | (GInterfaceFinalizeFunc) NULL, |
---|
192 | NULL |
---|
193 | }; |
---|
194 | |
---|
195 | static const GInterfaceInfo atk_text_info = |
---|
196 | { |
---|
197 | (GInterfaceInitFunc) atk_text_interface_init, |
---|
198 | (GInterfaceFinalizeFunc) NULL, |
---|
199 | NULL |
---|
200 | }; |
---|
201 | |
---|
202 | type = g_type_register_static (GAIL_TYPE_CONTAINER, |
---|
203 | "GailTextView", &tinfo, 0); |
---|
204 | g_type_add_interface_static (type, ATK_TYPE_EDITABLE_TEXT, |
---|
205 | &atk_editable_text_info); |
---|
206 | g_type_add_interface_static (type, ATK_TYPE_TEXT, |
---|
207 | &atk_text_info); |
---|
208 | } |
---|
209 | |
---|
210 | return type; |
---|
211 | } |
---|
212 | |
---|
213 | static void |
---|
214 | gail_text_view_class_init (GailTextViewClass *klass) |
---|
215 | { |
---|
216 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
---|
217 | AtkObjectClass *class = ATK_OBJECT_CLASS (klass); |
---|
218 | GailWidgetClass *widget_class; |
---|
219 | |
---|
220 | widget_class = (GailWidgetClass*)klass; |
---|
221 | |
---|
222 | parent_class = g_type_class_peek_parent (klass); |
---|
223 | |
---|
224 | gobject_class->finalize = gail_text_view_finalize; |
---|
225 | |
---|
226 | class->ref_state_set = gail_text_view_ref_state_set; |
---|
227 | class->initialize = gail_text_view_real_initialize; |
---|
228 | |
---|
229 | widget_class->notify_gtk = gail_text_view_real_notify_gtk; |
---|
230 | } |
---|
231 | |
---|
232 | static void |
---|
233 | gail_text_view_init (GailTextView *text_view) |
---|
234 | { |
---|
235 | text_view->textutil = NULL; |
---|
236 | text_view->signal_name = NULL; |
---|
237 | text_view->previous_insert_offset = -1; |
---|
238 | text_view->previous_selection_bound = -1; |
---|
239 | text_view->insert_notify_handler = 0; |
---|
240 | } |
---|
241 | |
---|
242 | static void |
---|
243 | setup_buffer (GtkTextView *view, |
---|
244 | GailTextView *gail_view) |
---|
245 | { |
---|
246 | GtkTextBuffer *buffer; |
---|
247 | |
---|
248 | buffer = view->buffer; |
---|
249 | if (buffer == NULL) |
---|
250 | return; |
---|
251 | |
---|
252 | gail_view->textutil = gail_text_util_new (); |
---|
253 | gail_text_util_buffer_setup (gail_view->textutil, buffer); |
---|
254 | |
---|
255 | /* Set up signal callbacks */ |
---|
256 | g_signal_connect_data (buffer, "insert-text", |
---|
257 | (GCallback) _gail_text_view_insert_text_cb, view, NULL, 0); |
---|
258 | g_signal_connect_data (buffer, "delete-range", |
---|
259 | (GCallback) _gail_text_view_delete_range_cb, view, NULL, 0); |
---|
260 | g_signal_connect_data (buffer, "mark-set", |
---|
261 | (GCallback) _gail_text_view_mark_set_cb, view, NULL, 0); |
---|
262 | g_signal_connect_data (buffer, "changed", |
---|
263 | (GCallback) _gail_text_view_changed_cb, view, NULL, 0); |
---|
264 | |
---|
265 | } |
---|
266 | |
---|
267 | static void |
---|
268 | gail_text_view_real_initialize (AtkObject *obj, |
---|
269 | gpointer data) |
---|
270 | { |
---|
271 | GtkTextView *view; |
---|
272 | GailTextView *gail_view; |
---|
273 | |
---|
274 | ATK_OBJECT_CLASS (parent_class)->initialize (obj, data); |
---|
275 | |
---|
276 | view = GTK_TEXT_VIEW (data); |
---|
277 | |
---|
278 | gail_view = GAIL_TEXT_VIEW (obj); |
---|
279 | setup_buffer (view, gail_view); |
---|
280 | |
---|
281 | obj->role = ATK_ROLE_TEXT; |
---|
282 | |
---|
283 | } |
---|
284 | |
---|
285 | static void |
---|
286 | gail_text_view_finalize (GObject *object) |
---|
287 | { |
---|
288 | GailTextView *text_view = GAIL_TEXT_VIEW (object); |
---|
289 | |
---|
290 | g_object_unref (text_view->textutil); |
---|
291 | if (text_view->insert_notify_handler) |
---|
292 | g_source_remove (text_view->insert_notify_handler); |
---|
293 | |
---|
294 | G_OBJECT_CLASS (parent_class)->finalize (object); |
---|
295 | } |
---|
296 | |
---|
297 | AtkObject* |
---|
298 | gail_text_view_new (GtkWidget *widget) |
---|
299 | { |
---|
300 | GObject *object; |
---|
301 | AtkObject *accessible; |
---|
302 | |
---|
303 | g_return_val_if_fail (GTK_IS_TEXT_VIEW (widget), NULL); |
---|
304 | |
---|
305 | object = g_object_new (GAIL_TYPE_TEXT_VIEW, NULL); |
---|
306 | |
---|
307 | accessible = ATK_OBJECT (object); |
---|
308 | atk_object_initialize (accessible, widget); |
---|
309 | |
---|
310 | return accessible; |
---|
311 | } |
---|
312 | |
---|
313 | static void |
---|
314 | gail_text_view_real_notify_gtk (GObject *obj, |
---|
315 | GParamSpec *pspec) |
---|
316 | { |
---|
317 | if (!strcmp (pspec->name, "editable")) |
---|
318 | { |
---|
319 | AtkObject *atk_obj; |
---|
320 | gboolean editable; |
---|
321 | |
---|
322 | atk_obj = gtk_widget_get_accessible (GTK_WIDGET (obj)); |
---|
323 | editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (obj)); |
---|
324 | atk_object_notify_state_change (atk_obj, ATK_STATE_EDITABLE, |
---|
325 | editable); |
---|
326 | } |
---|
327 | else if (!strcmp (pspec->name, "buffer")) |
---|
328 | { |
---|
329 | AtkObject *atk_obj; |
---|
330 | |
---|
331 | atk_obj = gtk_widget_get_accessible (GTK_WIDGET (obj)); |
---|
332 | setup_buffer (GTK_TEXT_VIEW (obj), GAIL_TEXT_VIEW (atk_obj)); |
---|
333 | } |
---|
334 | else |
---|
335 | parent_class->notify_gtk (obj, pspec); |
---|
336 | } |
---|
337 | |
---|
338 | /* atkobject.h */ |
---|
339 | |
---|
340 | static AtkStateSet* |
---|
341 | gail_text_view_ref_state_set (AtkObject *accessible) |
---|
342 | { |
---|
343 | AtkStateSet *state_set; |
---|
344 | GtkTextView *text_view; |
---|
345 | GtkWidget *widget; |
---|
346 | |
---|
347 | state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible); |
---|
348 | widget = GTK_ACCESSIBLE (accessible)->widget; |
---|
349 | |
---|
350 | if (widget == NULL) |
---|
351 | return state_set; |
---|
352 | |
---|
353 | text_view = GTK_TEXT_VIEW (widget); |
---|
354 | |
---|
355 | if (gtk_text_view_get_editable (text_view)) |
---|
356 | atk_state_set_add_state (state_set, ATK_STATE_EDITABLE); |
---|
357 | atk_state_set_add_state (state_set, ATK_STATE_MULTI_LINE); |
---|
358 | |
---|
359 | return state_set; |
---|
360 | } |
---|
361 | |
---|
362 | /* atktext.h */ |
---|
363 | |
---|
364 | static void |
---|
365 | atk_text_interface_init (AtkTextIface *iface) |
---|
366 | { |
---|
367 | g_return_if_fail (iface != NULL); |
---|
368 | |
---|
369 | iface->get_text = gail_text_view_get_text; |
---|
370 | iface->get_text_after_offset = gail_text_view_get_text_after_offset; |
---|
371 | iface->get_text_at_offset = gail_text_view_get_text_at_offset; |
---|
372 | iface->get_text_before_offset = gail_text_view_get_text_before_offset; |
---|
373 | iface->get_character_at_offset = gail_text_view_get_character_at_offset; |
---|
374 | iface->get_character_count = gail_text_view_get_character_count; |
---|
375 | iface->get_caret_offset = gail_text_view_get_caret_offset; |
---|
376 | iface->set_caret_offset = gail_text_view_set_caret_offset; |
---|
377 | iface->get_offset_at_point = gail_text_view_get_offset_at_point; |
---|
378 | iface->get_character_extents = gail_text_view_get_character_extents; |
---|
379 | iface->get_n_selections = gail_text_view_get_n_selections; |
---|
380 | iface->get_selection = gail_text_view_get_selection; |
---|
381 | iface->add_selection = gail_text_view_add_selection; |
---|
382 | iface->remove_selection = gail_text_view_remove_selection; |
---|
383 | iface->set_selection = gail_text_view_set_selection; |
---|
384 | iface->get_run_attributes = gail_text_view_get_run_attributes; |
---|
385 | iface->get_default_attributes = gail_text_view_get_default_attributes; |
---|
386 | } |
---|
387 | |
---|
388 | static gchar* |
---|
389 | gail_text_view_get_text (AtkText *text, |
---|
390 | gint start_offset, |
---|
391 | gint end_offset) |
---|
392 | { |
---|
393 | GtkTextView *view; |
---|
394 | GtkTextBuffer *buffer; |
---|
395 | GtkTextIter start, end; |
---|
396 | GtkWidget *widget; |
---|
397 | |
---|
398 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
399 | if (widget == NULL) |
---|
400 | /* State is defunct */ |
---|
401 | return NULL; |
---|
402 | |
---|
403 | view = GTK_TEXT_VIEW (widget); |
---|
404 | buffer = view->buffer; |
---|
405 | gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset); |
---|
406 | gtk_text_buffer_get_iter_at_offset (buffer, &end, end_offset); |
---|
407 | |
---|
408 | return gtk_text_buffer_get_text (buffer, &start, &end, FALSE); |
---|
409 | } |
---|
410 | |
---|
411 | static gchar* |
---|
412 | gail_text_view_get_text_after_offset (AtkText *text, |
---|
413 | gint offset, |
---|
414 | AtkTextBoundary boundary_type, |
---|
415 | gint *start_offset, |
---|
416 | gint *end_offset) |
---|
417 | { |
---|
418 | GtkWidget *widget; |
---|
419 | |
---|
420 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
421 | if (widget == NULL) |
---|
422 | /* State is defunct */ |
---|
423 | return NULL; |
---|
424 | |
---|
425 | return get_text_near_offset (text, GAIL_AFTER_OFFSET, |
---|
426 | boundary_type, offset, |
---|
427 | start_offset, end_offset); |
---|
428 | } |
---|
429 | |
---|
430 | static gchar* |
---|
431 | gail_text_view_get_text_at_offset (AtkText *text, |
---|
432 | gint offset, |
---|
433 | AtkTextBoundary boundary_type, |
---|
434 | gint *start_offset, |
---|
435 | gint *end_offset) |
---|
436 | { |
---|
437 | GtkWidget *widget; |
---|
438 | |
---|
439 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
440 | if (widget == NULL) |
---|
441 | /* State is defunct */ |
---|
442 | return NULL; |
---|
443 | |
---|
444 | return get_text_near_offset (text, GAIL_AT_OFFSET, |
---|
445 | boundary_type, offset, |
---|
446 | start_offset, end_offset); |
---|
447 | } |
---|
448 | |
---|
449 | static gchar* |
---|
450 | gail_text_view_get_text_before_offset (AtkText *text, |
---|
451 | gint offset, |
---|
452 | AtkTextBoundary boundary_type, |
---|
453 | gint *start_offset, |
---|
454 | gint *end_offset) |
---|
455 | { |
---|
456 | GtkWidget *widget; |
---|
457 | |
---|
458 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
459 | if (widget == NULL) |
---|
460 | /* State is defunct */ |
---|
461 | return NULL; |
---|
462 | |
---|
463 | return get_text_near_offset (text, GAIL_BEFORE_OFFSET, |
---|
464 | boundary_type, offset, |
---|
465 | start_offset, end_offset); |
---|
466 | } |
---|
467 | |
---|
468 | static gunichar |
---|
469 | gail_text_view_get_character_at_offset (AtkText *text, |
---|
470 | gint offset) |
---|
471 | { |
---|
472 | GtkWidget *widget; |
---|
473 | GtkTextIter start, end; |
---|
474 | GtkTextBuffer *buffer; |
---|
475 | gchar *string; |
---|
476 | gunichar unichar; |
---|
477 | |
---|
478 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
479 | if (widget == NULL) |
---|
480 | return '\0'; |
---|
481 | |
---|
482 | buffer = GAIL_TEXT_VIEW (text)->textutil->buffer; |
---|
483 | if (offset >= gtk_text_buffer_get_char_count (buffer)) |
---|
484 | return '\0'; |
---|
485 | |
---|
486 | gtk_text_buffer_get_iter_at_offset (buffer, &start, offset); |
---|
487 | end = start; |
---|
488 | gtk_text_iter_forward_char (&end); |
---|
489 | string = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE); |
---|
490 | unichar = g_utf8_get_char (string); |
---|
491 | g_free(string); |
---|
492 | return unichar; |
---|
493 | } |
---|
494 | |
---|
495 | static gint |
---|
496 | gail_text_view_get_character_count (AtkText *text) |
---|
497 | { |
---|
498 | GtkTextView *view; |
---|
499 | GtkTextBuffer *buffer; |
---|
500 | GtkWidget *widget; |
---|
501 | |
---|
502 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
503 | if (widget == NULL) |
---|
504 | /* State is defunct */ |
---|
505 | return 0; |
---|
506 | |
---|
507 | view = GTK_TEXT_VIEW (widget); |
---|
508 | buffer = view->buffer; |
---|
509 | return gtk_text_buffer_get_char_count (buffer); |
---|
510 | } |
---|
511 | |
---|
512 | static gint |
---|
513 | gail_text_view_get_caret_offset (AtkText *text) |
---|
514 | { |
---|
515 | GtkTextView *view; |
---|
516 | GtkWidget *widget; |
---|
517 | |
---|
518 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
519 | if (widget == NULL) |
---|
520 | /* State is defunct */ |
---|
521 | return 0; |
---|
522 | |
---|
523 | view = GTK_TEXT_VIEW (widget); |
---|
524 | return get_insert_offset (view->buffer); |
---|
525 | } |
---|
526 | |
---|
527 | static gboolean |
---|
528 | gail_text_view_set_caret_offset (AtkText *text, |
---|
529 | gint offset) |
---|
530 | { |
---|
531 | GtkTextView *view; |
---|
532 | GtkWidget *widget; |
---|
533 | GtkTextBuffer *buffer; |
---|
534 | GtkTextIter pos_itr; |
---|
535 | |
---|
536 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
537 | if (widget == NULL) |
---|
538 | /* State is defunct */ |
---|
539 | return FALSE; |
---|
540 | |
---|
541 | view = GTK_TEXT_VIEW (widget); |
---|
542 | buffer = view->buffer; |
---|
543 | |
---|
544 | gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, offset); |
---|
545 | gtk_text_buffer_place_cursor (buffer, &pos_itr); |
---|
546 | return TRUE; |
---|
547 | } |
---|
548 | |
---|
549 | static gint |
---|
550 | gail_text_view_get_offset_at_point (AtkText *text, |
---|
551 | gint x, |
---|
552 | gint y, |
---|
553 | AtkCoordType coords) |
---|
554 | { |
---|
555 | GtkTextView *view; |
---|
556 | GtkTextBuffer *buffer; |
---|
557 | GtkTextIter loc_itr; |
---|
558 | gint x_widget, y_widget, x_window, y_window, buff_x, buff_y; |
---|
559 | GtkWidget *widget; |
---|
560 | GdkWindow *window; |
---|
561 | GdkRectangle rect; |
---|
562 | |
---|
563 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
564 | if (widget == NULL) |
---|
565 | /* State is defunct */ |
---|
566 | return -1; |
---|
567 | |
---|
568 | view = GTK_TEXT_VIEW (widget); |
---|
569 | buffer = view->buffer; |
---|
570 | |
---|
571 | window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_WIDGET); |
---|
572 | gdk_window_get_origin (window, &x_widget, &y_widget); |
---|
573 | |
---|
574 | if (coords == ATK_XY_SCREEN) |
---|
575 | { |
---|
576 | x = x - x_widget; |
---|
577 | y = y - y_widget; |
---|
578 | } |
---|
579 | else if (coords == ATK_XY_WINDOW) |
---|
580 | { |
---|
581 | window = gdk_window_get_toplevel (window); |
---|
582 | gdk_window_get_origin (window, &x_window, &y_window); |
---|
583 | |
---|
584 | x = x - x_widget + x_window; |
---|
585 | y = y - y_widget + y_window; |
---|
586 | } |
---|
587 | else |
---|
588 | return -1; |
---|
589 | |
---|
590 | gtk_text_view_window_to_buffer_coords (view, GTK_TEXT_WINDOW_WIDGET, |
---|
591 | x, y, &buff_x, &buff_y); |
---|
592 | gtk_text_view_get_visible_rect (view, &rect); |
---|
593 | /* |
---|
594 | * Clamp point to visible rectangle |
---|
595 | */ |
---|
596 | buff_x = CLAMP (buff_x, rect.x, rect.x + rect.width - 1); |
---|
597 | buff_y = CLAMP (buff_y, rect.y, rect.y + rect.height - 1); |
---|
598 | |
---|
599 | gtk_text_view_get_iter_at_location (view, &loc_itr, buff_x, buff_y); |
---|
600 | /* |
---|
601 | * The iter at a location sometimes points to the next character. |
---|
602 | * See bug 111031. We work around that |
---|
603 | */ |
---|
604 | gtk_text_view_get_iter_location (view, &loc_itr, &rect); |
---|
605 | if (buff_x < rect.x) |
---|
606 | gtk_text_iter_backward_char (&loc_itr); |
---|
607 | return gtk_text_iter_get_offset (&loc_itr); |
---|
608 | } |
---|
609 | |
---|
610 | static void |
---|
611 | gail_text_view_get_character_extents (AtkText *text, |
---|
612 | gint offset, |
---|
613 | gint *x, |
---|
614 | gint *y, |
---|
615 | gint *width, |
---|
616 | gint *height, |
---|
617 | AtkCoordType coords) |
---|
618 | { |
---|
619 | GtkTextView *view; |
---|
620 | GtkTextBuffer *buffer; |
---|
621 | GtkTextIter iter; |
---|
622 | GtkWidget *widget; |
---|
623 | GdkRectangle rectangle; |
---|
624 | GdkWindow *window; |
---|
625 | gint x_widget, y_widget, x_window, y_window; |
---|
626 | |
---|
627 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
628 | if (widget == NULL) |
---|
629 | /* State is defunct */ |
---|
630 | return; |
---|
631 | |
---|
632 | view = GTK_TEXT_VIEW (widget); |
---|
633 | buffer = view->buffer; |
---|
634 | gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset); |
---|
635 | gtk_text_view_get_iter_location (view, &iter, &rectangle); |
---|
636 | |
---|
637 | window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_WIDGET); |
---|
638 | gdk_window_get_origin (window, &x_widget, &y_widget); |
---|
639 | |
---|
640 | *height = rectangle.height; |
---|
641 | *width = rectangle.width; |
---|
642 | |
---|
643 | gtk_text_view_buffer_to_window_coords (view, GTK_TEXT_WINDOW_WIDGET, |
---|
644 | rectangle.x, rectangle.y, x, y); |
---|
645 | if (coords == ATK_XY_WINDOW) |
---|
646 | { |
---|
647 | window = gdk_window_get_toplevel (window); |
---|
648 | gdk_window_get_origin (window, &x_window, &y_window); |
---|
649 | *x += x_widget - x_window; |
---|
650 | *y += y_widget - y_window; |
---|
651 | } |
---|
652 | else if (coords == ATK_XY_SCREEN) |
---|
653 | { |
---|
654 | *x += x_widget; |
---|
655 | *y += y_widget; |
---|
656 | } |
---|
657 | else |
---|
658 | { |
---|
659 | *x = 0; |
---|
660 | *y = 0; |
---|
661 | *height = 0; |
---|
662 | *width = 0; |
---|
663 | } |
---|
664 | } |
---|
665 | |
---|
666 | static AtkAttributeSet* |
---|
667 | gail_text_view_get_run_attributes (AtkText *text, |
---|
668 | gint offset, |
---|
669 | gint *start_offset, |
---|
670 | gint *end_offset) |
---|
671 | { |
---|
672 | GtkTextView *view; |
---|
673 | GtkWidget *widget; |
---|
674 | |
---|
675 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
676 | if (widget == NULL) |
---|
677 | /* State is defunct */ |
---|
678 | return NULL; |
---|
679 | |
---|
680 | view = GTK_TEXT_VIEW (widget); |
---|
681 | |
---|
682 | return gail_misc_buffer_get_run_attributes (view->buffer, offset, |
---|
683 | start_offset, end_offset); |
---|
684 | } |
---|
685 | |
---|
686 | static AtkAttributeSet* |
---|
687 | gail_text_view_get_default_attributes (AtkText *text) |
---|
688 | { |
---|
689 | GtkTextView *view; |
---|
690 | GtkWidget *widget; |
---|
691 | GtkTextAttributes *text_attrs; |
---|
692 | AtkAttributeSet *attrib_set = NULL; |
---|
693 | PangoFontDescription *font; |
---|
694 | |
---|
695 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
696 | if (widget == NULL) |
---|
697 | /* State is defunct */ |
---|
698 | return NULL; |
---|
699 | |
---|
700 | view = GTK_TEXT_VIEW (widget); |
---|
701 | text_attrs = gtk_text_view_get_default_attributes (view); |
---|
702 | |
---|
703 | font = text_attrs->font; |
---|
704 | |
---|
705 | if (font) |
---|
706 | { |
---|
707 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
708 | ATK_TEXT_ATTR_STYLE); |
---|
709 | |
---|
710 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
711 | ATK_TEXT_ATTR_VARIANT); |
---|
712 | |
---|
713 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
714 | ATK_TEXT_ATTR_STRETCH); |
---|
715 | } |
---|
716 | |
---|
717 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
718 | ATK_TEXT_ATTR_JUSTIFICATION); |
---|
719 | |
---|
720 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
721 | ATK_TEXT_ATTR_DIRECTION); |
---|
722 | |
---|
723 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
724 | ATK_TEXT_ATTR_WRAP_MODE); |
---|
725 | |
---|
726 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
727 | ATK_TEXT_ATTR_FG_STIPPLE); |
---|
728 | |
---|
729 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
730 | ATK_TEXT_ATTR_BG_STIPPLE); |
---|
731 | |
---|
732 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
733 | ATK_TEXT_ATTR_FG_COLOR); |
---|
734 | |
---|
735 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
736 | ATK_TEXT_ATTR_BG_COLOR); |
---|
737 | |
---|
738 | if (font) |
---|
739 | { |
---|
740 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
741 | ATK_TEXT_ATTR_FAMILY_NAME); |
---|
742 | } |
---|
743 | |
---|
744 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
745 | ATK_TEXT_ATTR_LANGUAGE); |
---|
746 | |
---|
747 | if (font) |
---|
748 | { |
---|
749 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
750 | ATK_TEXT_ATTR_WEIGHT); |
---|
751 | } |
---|
752 | |
---|
753 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
754 | ATK_TEXT_ATTR_SCALE); |
---|
755 | |
---|
756 | if (font) |
---|
757 | { |
---|
758 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
759 | ATK_TEXT_ATTR_SIZE); |
---|
760 | } |
---|
761 | |
---|
762 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
763 | ATK_TEXT_ATTR_STRIKETHROUGH); |
---|
764 | |
---|
765 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
766 | ATK_TEXT_ATTR_UNDERLINE); |
---|
767 | |
---|
768 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
769 | ATK_TEXT_ATTR_RISE); |
---|
770 | |
---|
771 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
772 | ATK_TEXT_ATTR_BG_FULL_HEIGHT); |
---|
773 | |
---|
774 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
775 | ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP); |
---|
776 | |
---|
777 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
778 | ATK_TEXT_ATTR_PIXELS_BELOW_LINES); |
---|
779 | |
---|
780 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
781 | ATK_TEXT_ATTR_PIXELS_ABOVE_LINES); |
---|
782 | |
---|
783 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
784 | ATK_TEXT_ATTR_EDITABLE); |
---|
785 | |
---|
786 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
787 | ATK_TEXT_ATTR_INVISIBLE); |
---|
788 | |
---|
789 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
790 | ATK_TEXT_ATTR_INDENT); |
---|
791 | |
---|
792 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
793 | ATK_TEXT_ATTR_RIGHT_MARGIN); |
---|
794 | |
---|
795 | attrib_set = gail_misc_add_to_attr_set (attrib_set, text_attrs, |
---|
796 | ATK_TEXT_ATTR_LEFT_MARGIN); |
---|
797 | |
---|
798 | gtk_text_attributes_unref (text_attrs); |
---|
799 | return attrib_set; |
---|
800 | } |
---|
801 | |
---|
802 | static gint |
---|
803 | gail_text_view_get_n_selections (AtkText *text) |
---|
804 | { |
---|
805 | GtkTextView *view; |
---|
806 | GtkWidget *widget; |
---|
807 | GtkTextBuffer *buffer; |
---|
808 | GtkTextIter start, end; |
---|
809 | gint select_start, select_end; |
---|
810 | |
---|
811 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
812 | if (widget == NULL) |
---|
813 | /* State is defunct */ |
---|
814 | return -1; |
---|
815 | |
---|
816 | view = GTK_TEXT_VIEW (widget); |
---|
817 | buffer = view->buffer; |
---|
818 | |
---|
819 | gtk_text_buffer_get_selection_bounds (buffer, &start, &end); |
---|
820 | select_start = gtk_text_iter_get_offset (&start); |
---|
821 | select_end = gtk_text_iter_get_offset (&end); |
---|
822 | |
---|
823 | if (select_start != select_end) |
---|
824 | return 1; |
---|
825 | else |
---|
826 | return 0; |
---|
827 | } |
---|
828 | |
---|
829 | static gchar* |
---|
830 | gail_text_view_get_selection (AtkText *text, |
---|
831 | gint selection_num, |
---|
832 | gint *start_pos, |
---|
833 | gint *end_pos) |
---|
834 | { |
---|
835 | GtkTextView *view; |
---|
836 | GtkWidget *widget; |
---|
837 | GtkTextBuffer *buffer; |
---|
838 | GtkTextIter start, end; |
---|
839 | |
---|
840 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
841 | if (widget == NULL) |
---|
842 | /* State is defunct */ |
---|
843 | return NULL; |
---|
844 | |
---|
845 | /* Only let the user get the selection if one is set, and if the |
---|
846 | * selection_num is 0. |
---|
847 | */ |
---|
848 | if (selection_num != 0) |
---|
849 | return NULL; |
---|
850 | |
---|
851 | view = GTK_TEXT_VIEW (widget); |
---|
852 | buffer = view->buffer; |
---|
853 | |
---|
854 | gtk_text_buffer_get_selection_bounds (buffer, &start, &end); |
---|
855 | *start_pos = gtk_text_iter_get_offset (&start); |
---|
856 | *end_pos = gtk_text_iter_get_offset (&end); |
---|
857 | |
---|
858 | if (*start_pos != *end_pos) |
---|
859 | return gtk_text_buffer_get_text (buffer, &start, &end, FALSE); |
---|
860 | else |
---|
861 | return NULL; |
---|
862 | } |
---|
863 | |
---|
864 | static gboolean |
---|
865 | gail_text_view_add_selection (AtkText *text, |
---|
866 | gint start_pos, |
---|
867 | gint end_pos) |
---|
868 | { |
---|
869 | GtkTextView *view; |
---|
870 | GtkWidget *widget; |
---|
871 | GtkTextBuffer *buffer; |
---|
872 | GtkTextIter pos_itr; |
---|
873 | GtkTextIter start, end; |
---|
874 | gint select_start, select_end; |
---|
875 | |
---|
876 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
877 | if (widget == NULL) |
---|
878 | /* State is defunct */ |
---|
879 | return FALSE; |
---|
880 | |
---|
881 | view = GTK_TEXT_VIEW (widget); |
---|
882 | buffer = view->buffer; |
---|
883 | |
---|
884 | gtk_text_buffer_get_selection_bounds (buffer, &start, &end); |
---|
885 | select_start = gtk_text_iter_get_offset (&start); |
---|
886 | select_end = gtk_text_iter_get_offset (&end); |
---|
887 | |
---|
888 | /* If there is already a selection, then don't allow another to be added, |
---|
889 | * since GtkTextView only supports one selected region. |
---|
890 | */ |
---|
891 | if (select_start == select_end) |
---|
892 | { |
---|
893 | gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, start_pos); |
---|
894 | gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &pos_itr); |
---|
895 | gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, end_pos); |
---|
896 | gtk_text_buffer_move_mark_by_name (buffer, "insert", &pos_itr); |
---|
897 | return TRUE; |
---|
898 | } |
---|
899 | else |
---|
900 | return FALSE; |
---|
901 | } |
---|
902 | |
---|
903 | static gboolean |
---|
904 | gail_text_view_remove_selection (AtkText *text, |
---|
905 | gint selection_num) |
---|
906 | { |
---|
907 | GtkTextView *view; |
---|
908 | GtkWidget *widget; |
---|
909 | GtkTextBuffer *buffer; |
---|
910 | GtkTextMark *cursor_mark; |
---|
911 | GtkTextIter cursor_itr; |
---|
912 | GtkTextIter start, end; |
---|
913 | gint select_start, select_end; |
---|
914 | |
---|
915 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
916 | if (widget == NULL) |
---|
917 | /* State is defunct */ |
---|
918 | return FALSE; |
---|
919 | |
---|
920 | if (selection_num != 0) |
---|
921 | return FALSE; |
---|
922 | |
---|
923 | view = GTK_TEXT_VIEW (widget); |
---|
924 | buffer = view->buffer; |
---|
925 | |
---|
926 | gtk_text_buffer_get_selection_bounds(buffer, &start, &end); |
---|
927 | select_start = gtk_text_iter_get_offset(&start); |
---|
928 | select_end = gtk_text_iter_get_offset(&end); |
---|
929 | |
---|
930 | if (select_start != select_end) |
---|
931 | { |
---|
932 | /* Setting the start & end of the selected region to the caret position |
---|
933 | * turns off the selection. |
---|
934 | */ |
---|
935 | cursor_mark = gtk_text_buffer_get_insert (buffer); |
---|
936 | gtk_text_buffer_get_iter_at_mark (buffer, &cursor_itr, cursor_mark); |
---|
937 | gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &cursor_itr); |
---|
938 | return TRUE; |
---|
939 | } |
---|
940 | else |
---|
941 | return FALSE; |
---|
942 | } |
---|
943 | |
---|
944 | static gboolean |
---|
945 | gail_text_view_set_selection (AtkText *text, |
---|
946 | gint selection_num, |
---|
947 | gint start_pos, |
---|
948 | gint end_pos) |
---|
949 | { |
---|
950 | GtkTextView *view; |
---|
951 | GtkWidget *widget; |
---|
952 | GtkTextBuffer *buffer; |
---|
953 | GtkTextIter pos_itr; |
---|
954 | GtkTextIter start, end; |
---|
955 | gint select_start, select_end; |
---|
956 | |
---|
957 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
958 | if (widget == NULL) |
---|
959 | { |
---|
960 | /* State is defunct */ |
---|
961 | return FALSE; |
---|
962 | } |
---|
963 | |
---|
964 | /* Only let the user move the selection if one is set, and if the |
---|
965 | * selection_num is 0 |
---|
966 | */ |
---|
967 | if (selection_num != 0) |
---|
968 | return FALSE; |
---|
969 | |
---|
970 | view = GTK_TEXT_VIEW (widget); |
---|
971 | buffer = view->buffer; |
---|
972 | |
---|
973 | gtk_text_buffer_get_selection_bounds(buffer, &start, &end); |
---|
974 | select_start = gtk_text_iter_get_offset(&start); |
---|
975 | select_end = gtk_text_iter_get_offset(&end); |
---|
976 | |
---|
977 | if (select_start != select_end) |
---|
978 | { |
---|
979 | gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, start_pos); |
---|
980 | gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &pos_itr); |
---|
981 | gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, end_pos); |
---|
982 | gtk_text_buffer_move_mark_by_name (buffer, "insert", &pos_itr); |
---|
983 | return TRUE; |
---|
984 | } |
---|
985 | else |
---|
986 | return FALSE; |
---|
987 | } |
---|
988 | |
---|
989 | /* atkeditabletext.h */ |
---|
990 | |
---|
991 | static void |
---|
992 | atk_editable_text_interface_init (AtkEditableTextIface *iface) |
---|
993 | { |
---|
994 | g_return_if_fail (iface != NULL); |
---|
995 | |
---|
996 | iface->set_text_contents = gail_text_view_set_text_contents; |
---|
997 | iface->insert_text = gail_text_view_insert_text; |
---|
998 | iface->copy_text = gail_text_view_copy_text; |
---|
999 | iface->cut_text = gail_text_view_cut_text; |
---|
1000 | iface->delete_text = gail_text_view_delete_text; |
---|
1001 | iface->paste_text = gail_text_view_paste_text; |
---|
1002 | iface->set_run_attributes = gail_text_view_set_run_attributes; |
---|
1003 | } |
---|
1004 | |
---|
1005 | static gboolean |
---|
1006 | gail_text_view_set_run_attributes (AtkEditableText *text, |
---|
1007 | AtkAttributeSet *attrib_set, |
---|
1008 | gint start_offset, |
---|
1009 | gint end_offset) |
---|
1010 | { |
---|
1011 | GtkTextView *view; |
---|
1012 | GtkTextBuffer *buffer; |
---|
1013 | GtkWidget *widget; |
---|
1014 | GtkTextTag *tag; |
---|
1015 | GtkTextIter start; |
---|
1016 | GtkTextIter end; |
---|
1017 | gint j; |
---|
1018 | GdkColor *color; |
---|
1019 | gchar** RGB_vals; |
---|
1020 | GSList *l; |
---|
1021 | |
---|
1022 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
1023 | if (widget == NULL) |
---|
1024 | /* State is defunct */ |
---|
1025 | return FALSE; |
---|
1026 | |
---|
1027 | view = GTK_TEXT_VIEW (widget); |
---|
1028 | if (!gtk_text_view_get_editable (view)) |
---|
1029 | return FALSE; |
---|
1030 | |
---|
1031 | buffer = view->buffer; |
---|
1032 | |
---|
1033 | if (attrib_set == NULL) |
---|
1034 | return FALSE; |
---|
1035 | |
---|
1036 | gtk_text_buffer_get_iter_at_offset (buffer, &start, start_offset); |
---|
1037 | gtk_text_buffer_get_iter_at_offset (buffer, &end, end_offset); |
---|
1038 | |
---|
1039 | tag = gtk_text_buffer_create_tag (buffer, NULL, NULL); |
---|
1040 | |
---|
1041 | for (l = attrib_set; l; l = l->next) |
---|
1042 | { |
---|
1043 | gchar *name; |
---|
1044 | gchar *value; |
---|
1045 | AtkAttribute *at; |
---|
1046 | |
---|
1047 | at = l->data; |
---|
1048 | |
---|
1049 | name = at->name; |
---|
1050 | value = at->value; |
---|
1051 | |
---|
1052 | if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_LEFT_MARGIN))) |
---|
1053 | g_object_set (G_OBJECT (tag), "left_margin", atoi (value), NULL); |
---|
1054 | |
---|
1055 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_RIGHT_MARGIN))) |
---|
1056 | g_object_set (G_OBJECT (tag), "right_margin", atoi (value), NULL); |
---|
1057 | |
---|
1058 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_INDENT))) |
---|
1059 | g_object_set (G_OBJECT (tag), "indent", atoi (value), NULL); |
---|
1060 | |
---|
1061 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_ABOVE_LINES))) |
---|
1062 | g_object_set (G_OBJECT (tag), "pixels_above_lines", atoi (value), NULL); |
---|
1063 | |
---|
1064 | else if (!g_strcasecmp(name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_BELOW_LINES))) |
---|
1065 | g_object_set (G_OBJECT (tag), "pixels_below_lines", atoi (value), NULL); |
---|
1066 | |
---|
1067 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_PIXELS_INSIDE_WRAP))) |
---|
1068 | g_object_set (G_OBJECT (tag), "pixels_inside_wrap", atoi (value), NULL); |
---|
1069 | |
---|
1070 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_SIZE))) |
---|
1071 | g_object_set (G_OBJECT (tag), "size", atoi (value), NULL); |
---|
1072 | |
---|
1073 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_RISE))) |
---|
1074 | g_object_set (G_OBJECT (tag), "rise", atoi (value), NULL); |
---|
1075 | |
---|
1076 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_WEIGHT))) |
---|
1077 | g_object_set (G_OBJECT (tag), "weight", atoi (value), NULL); |
---|
1078 | |
---|
1079 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_BG_FULL_HEIGHT))) |
---|
1080 | { |
---|
1081 | g_object_set (G_OBJECT (tag), "bg_full_height", |
---|
1082 | (g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_BG_FULL_HEIGHT, 0))), |
---|
1083 | NULL); |
---|
1084 | } |
---|
1085 | |
---|
1086 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_LANGUAGE))) |
---|
1087 | g_object_set (G_OBJECT (tag), "language", value, NULL); |
---|
1088 | |
---|
1089 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_FAMILY_NAME))) |
---|
1090 | g_object_set (G_OBJECT (tag), "family", value, NULL); |
---|
1091 | |
---|
1092 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_EDITABLE))) |
---|
1093 | { |
---|
1094 | g_object_set (G_OBJECT (tag), "editable", |
---|
1095 | (g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, 0))), |
---|
1096 | NULL); |
---|
1097 | } |
---|
1098 | |
---|
1099 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_INVISIBLE))) |
---|
1100 | { |
---|
1101 | g_object_set (G_OBJECT (tag), "invisible", |
---|
1102 | (g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_EDITABLE, 0))), |
---|
1103 | NULL); |
---|
1104 | } |
---|
1105 | |
---|
1106 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_UNDERLINE))) |
---|
1107 | { |
---|
1108 | for (j = 0; j < 3; j++) |
---|
1109 | { |
---|
1110 | if (!g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_UNDERLINE, j))) |
---|
1111 | { |
---|
1112 | g_object_set (G_OBJECT (tag), "underline", j, NULL); |
---|
1113 | break; |
---|
1114 | } |
---|
1115 | } |
---|
1116 | } |
---|
1117 | |
---|
1118 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STRIKETHROUGH))) |
---|
1119 | { |
---|
1120 | g_object_set (G_OBJECT (tag), "strikethrough", |
---|
1121 | (g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STRIKETHROUGH, 0))), |
---|
1122 | NULL); |
---|
1123 | } |
---|
1124 | |
---|
1125 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_BG_COLOR))) |
---|
1126 | { |
---|
1127 | RGB_vals = g_strsplit (value, ",", 3); |
---|
1128 | color = g_malloc (sizeof (GdkColor)); |
---|
1129 | color->red = atoi (RGB_vals[0]); |
---|
1130 | color->green = atoi (RGB_vals[1]); |
---|
1131 | color->blue = atoi (RGB_vals[2]); |
---|
1132 | g_object_set (G_OBJECT (tag), "background_gdk", color, NULL); |
---|
1133 | } |
---|
1134 | |
---|
1135 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_FG_COLOR))) |
---|
1136 | { |
---|
1137 | RGB_vals = g_strsplit (value, ",", 3); |
---|
1138 | color = g_malloc (sizeof (GdkColor)); |
---|
1139 | color->red = atoi (RGB_vals[0]); |
---|
1140 | color->green = atoi (RGB_vals[1]); |
---|
1141 | color->blue = atoi (RGB_vals[2]); |
---|
1142 | g_object_set (G_OBJECT (tag), "foreground_gdk", color, NULL); |
---|
1143 | } |
---|
1144 | |
---|
1145 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STRETCH))) |
---|
1146 | { |
---|
1147 | for (j = 0; j < 9; j++) |
---|
1148 | { |
---|
1149 | if (!g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STRETCH, j))) |
---|
1150 | { |
---|
1151 | g_object_set (G_OBJECT (tag), "stretch", j, NULL); |
---|
1152 | break; |
---|
1153 | } |
---|
1154 | } |
---|
1155 | } |
---|
1156 | |
---|
1157 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_JUSTIFICATION))) |
---|
1158 | { |
---|
1159 | for (j = 0; j < 4; j++) |
---|
1160 | { |
---|
1161 | if (!g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_JUSTIFICATION, j))) |
---|
1162 | { |
---|
1163 | g_object_set (G_OBJECT (tag), "justification", j, NULL); |
---|
1164 | break; |
---|
1165 | } |
---|
1166 | } |
---|
1167 | } |
---|
1168 | |
---|
1169 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_DIRECTION))) |
---|
1170 | { |
---|
1171 | for (j = 0; j < 3; j++) |
---|
1172 | { |
---|
1173 | if (!g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_DIRECTION, j))) |
---|
1174 | { |
---|
1175 | g_object_set (G_OBJECT (tag), "direction", j, NULL); |
---|
1176 | break; |
---|
1177 | } |
---|
1178 | } |
---|
1179 | } |
---|
1180 | |
---|
1181 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_VARIANT))) |
---|
1182 | { |
---|
1183 | for (j = 0; j < 2; j++) |
---|
1184 | { |
---|
1185 | if (!g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_VARIANT, j))) |
---|
1186 | { |
---|
1187 | g_object_set (G_OBJECT (tag), "variant", j, NULL); |
---|
1188 | break; |
---|
1189 | } |
---|
1190 | } |
---|
1191 | } |
---|
1192 | |
---|
1193 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_WRAP_MODE))) |
---|
1194 | { |
---|
1195 | for (j = 0; j < 3; j++) |
---|
1196 | { |
---|
1197 | if (!g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_WRAP_MODE, j))) |
---|
1198 | { |
---|
1199 | g_object_set (G_OBJECT (tag), "wrap_mode", j, NULL); |
---|
1200 | break; |
---|
1201 | } |
---|
1202 | } |
---|
1203 | } |
---|
1204 | |
---|
1205 | else if (!g_strcasecmp (name, atk_text_attribute_get_name (ATK_TEXT_ATTR_STYLE))) |
---|
1206 | { |
---|
1207 | for (j = 0; j < 3; j++) |
---|
1208 | { |
---|
1209 | if (!g_strcasecmp (value, atk_text_attribute_get_value (ATK_TEXT_ATTR_STYLE, j))) |
---|
1210 | { |
---|
1211 | g_object_set (G_OBJECT (tag), "style", j, NULL); |
---|
1212 | break; |
---|
1213 | } |
---|
1214 | } |
---|
1215 | } |
---|
1216 | |
---|
1217 | else |
---|
1218 | return FALSE; |
---|
1219 | } |
---|
1220 | |
---|
1221 | gtk_text_buffer_apply_tag (buffer, tag, &start, &end); |
---|
1222 | |
---|
1223 | return TRUE; |
---|
1224 | } |
---|
1225 | |
---|
1226 | static void |
---|
1227 | gail_text_view_set_text_contents (AtkEditableText *text, |
---|
1228 | const gchar *string) |
---|
1229 | { |
---|
1230 | GtkTextView *view; |
---|
1231 | GtkWidget *widget; |
---|
1232 | GtkTextBuffer *buffer; |
---|
1233 | |
---|
1234 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
1235 | if (widget == NULL) |
---|
1236 | /* State is defunct */ |
---|
1237 | return; |
---|
1238 | |
---|
1239 | view = GTK_TEXT_VIEW (widget); |
---|
1240 | if (!gtk_text_view_get_editable (view)) |
---|
1241 | return; |
---|
1242 | buffer = view->buffer; |
---|
1243 | |
---|
1244 | /* The -1 indicates that the input string must be null-terminated */ |
---|
1245 | gtk_text_buffer_set_text (buffer, string, -1); |
---|
1246 | } |
---|
1247 | |
---|
1248 | static void |
---|
1249 | gail_text_view_insert_text (AtkEditableText *text, |
---|
1250 | const gchar *string, |
---|
1251 | gint length, |
---|
1252 | gint *position) |
---|
1253 | { |
---|
1254 | GtkTextView *view; |
---|
1255 | GtkWidget *widget; |
---|
1256 | GtkTextBuffer *buffer; |
---|
1257 | GtkTextIter pos_itr; |
---|
1258 | |
---|
1259 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
1260 | if (widget == NULL) |
---|
1261 | /* State is defunct */ |
---|
1262 | return; |
---|
1263 | |
---|
1264 | view = GTK_TEXT_VIEW (widget); |
---|
1265 | if (!gtk_text_view_get_editable (view)) |
---|
1266 | return; |
---|
1267 | buffer = view->buffer; |
---|
1268 | |
---|
1269 | gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, *position); |
---|
1270 | gtk_text_buffer_insert (buffer, &pos_itr, string, length); |
---|
1271 | } |
---|
1272 | |
---|
1273 | static void |
---|
1274 | gail_text_view_copy_text (AtkEditableText *text, |
---|
1275 | gint start_pos, |
---|
1276 | gint end_pos) |
---|
1277 | { |
---|
1278 | GtkTextView *view; |
---|
1279 | GtkWidget *widget; |
---|
1280 | GtkTextBuffer *buffer; |
---|
1281 | GtkTextIter start, end; |
---|
1282 | gchar *str; |
---|
1283 | |
---|
1284 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
1285 | if (widget == NULL) |
---|
1286 | /* State is defunct */ |
---|
1287 | return; |
---|
1288 | |
---|
1289 | view = GTK_TEXT_VIEW (widget); |
---|
1290 | buffer = view->buffer; |
---|
1291 | |
---|
1292 | gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos); |
---|
1293 | gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos); |
---|
1294 | str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); |
---|
1295 | gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), str, -1); |
---|
1296 | } |
---|
1297 | |
---|
1298 | static void |
---|
1299 | gail_text_view_cut_text (AtkEditableText *text, |
---|
1300 | gint start_pos, |
---|
1301 | gint end_pos) |
---|
1302 | { |
---|
1303 | GtkTextView *view; |
---|
1304 | GtkWidget *widget; |
---|
1305 | GtkTextBuffer *buffer; |
---|
1306 | GtkTextIter start, end; |
---|
1307 | gchar *str; |
---|
1308 | |
---|
1309 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
1310 | if (widget == NULL) |
---|
1311 | /* State is defunct */ |
---|
1312 | return; |
---|
1313 | |
---|
1314 | view = GTK_TEXT_VIEW (widget); |
---|
1315 | if (!gtk_text_view_get_editable (view)) |
---|
1316 | return; |
---|
1317 | buffer = view->buffer; |
---|
1318 | |
---|
1319 | gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos); |
---|
1320 | gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos); |
---|
1321 | str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); |
---|
1322 | gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), str, -1); |
---|
1323 | gtk_text_buffer_delete (buffer, &start, &end); |
---|
1324 | } |
---|
1325 | |
---|
1326 | static void |
---|
1327 | gail_text_view_delete_text (AtkEditableText *text, |
---|
1328 | gint start_pos, |
---|
1329 | gint end_pos) |
---|
1330 | { |
---|
1331 | GtkTextView *view; |
---|
1332 | GtkWidget *widget; |
---|
1333 | GtkTextBuffer *buffer; |
---|
1334 | GtkTextIter start_itr; |
---|
1335 | GtkTextIter end_itr; |
---|
1336 | |
---|
1337 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
1338 | if (widget == NULL) |
---|
1339 | /* State is defunct */ |
---|
1340 | return; |
---|
1341 | |
---|
1342 | view = GTK_TEXT_VIEW (widget); |
---|
1343 | if (!gtk_text_view_get_editable (view)) |
---|
1344 | return; |
---|
1345 | buffer = view->buffer; |
---|
1346 | |
---|
1347 | gtk_text_buffer_get_iter_at_offset (buffer, &start_itr, start_pos); |
---|
1348 | gtk_text_buffer_get_iter_at_offset (buffer, &end_itr, end_pos); |
---|
1349 | gtk_text_buffer_delete (buffer, &start_itr, &end_itr); |
---|
1350 | } |
---|
1351 | |
---|
1352 | static void |
---|
1353 | gail_text_view_paste_text (AtkEditableText *text, |
---|
1354 | gint position) |
---|
1355 | { |
---|
1356 | GtkTextView *view; |
---|
1357 | GtkWidget *widget; |
---|
1358 | GtkTextBuffer *buffer; |
---|
1359 | GailTextViewPaste paste_struct; |
---|
1360 | |
---|
1361 | widget = GTK_ACCESSIBLE (text)->widget; |
---|
1362 | if (widget == NULL) |
---|
1363 | /* State is defunct */ |
---|
1364 | return; |
---|
1365 | |
---|
1366 | view = GTK_TEXT_VIEW (widget); |
---|
1367 | if (!gtk_text_view_get_editable (view)) |
---|
1368 | return; |
---|
1369 | buffer = view->buffer; |
---|
1370 | |
---|
1371 | paste_struct.buffer = buffer; |
---|
1372 | paste_struct.position = position; |
---|
1373 | |
---|
1374 | g_object_ref (paste_struct.buffer); |
---|
1375 | gtk_clipboard_request_text (gtk_clipboard_get (GDK_NONE), |
---|
1376 | gail_text_view_paste_received, &paste_struct); |
---|
1377 | } |
---|
1378 | |
---|
1379 | static void |
---|
1380 | gail_text_view_paste_received (GtkClipboard *clipboard, |
---|
1381 | const gchar *text, |
---|
1382 | gpointer data) |
---|
1383 | { |
---|
1384 | GailTextViewPaste* paste_struct = (GailTextViewPaste *)data; |
---|
1385 | GtkTextIter pos_itr; |
---|
1386 | |
---|
1387 | if (text) |
---|
1388 | { |
---|
1389 | gtk_text_buffer_get_iter_at_offset (paste_struct->buffer, &pos_itr, |
---|
1390 | paste_struct->position); |
---|
1391 | gtk_text_buffer_insert (paste_struct->buffer, &pos_itr, text, -1); |
---|
1392 | } |
---|
1393 | |
---|
1394 | g_object_unref (paste_struct->buffer); |
---|
1395 | } |
---|
1396 | |
---|
1397 | /* Callbacks */ |
---|
1398 | |
---|
1399 | /* Note arg1 returns the start of the insert range, arg3 returns the |
---|
1400 | * end of the insert range if multiple characters are inserted. If one |
---|
1401 | * character is inserted they have the same value, which is the caret |
---|
1402 | * location. arg2 returns the begin location of the insert. |
---|
1403 | */ |
---|
1404 | static void |
---|
1405 | _gail_text_view_insert_text_cb (GtkTextBuffer *buffer, |
---|
1406 | GtkTextIter *arg1, |
---|
1407 | gchar *arg2, |
---|
1408 | gint arg3, |
---|
1409 | gpointer user_data) |
---|
1410 | { |
---|
1411 | GtkTextView *text = (GtkTextView *) user_data; |
---|
1412 | AtkObject *accessible; |
---|
1413 | GailTextView *gail_text_view; |
---|
1414 | gint position; |
---|
1415 | gint length; |
---|
1416 | |
---|
1417 | g_return_if_fail (arg3 > 0); |
---|
1418 | |
---|
1419 | accessible = gtk_widget_get_accessible(GTK_WIDGET(text)); |
---|
1420 | gail_text_view = GAIL_TEXT_VIEW (accessible); |
---|
1421 | |
---|
1422 | gail_text_view->signal_name = "text_changed::insert"; |
---|
1423 | position = gtk_text_iter_get_offset (arg1); |
---|
1424 | length = arg3; |
---|
1425 | |
---|
1426 | if (gail_text_view->length == 0) |
---|
1427 | { |
---|
1428 | gail_text_view->position = position; |
---|
1429 | gail_text_view->length = length; |
---|
1430 | } |
---|
1431 | else if (gail_text_view->position + gail_text_view->length == position) |
---|
1432 | { |
---|
1433 | gail_text_view->length += length; |
---|
1434 | } |
---|
1435 | else |
---|
1436 | { |
---|
1437 | /* |
---|
1438 | * We have a non-contiguous insert so report what we have |
---|
1439 | */ |
---|
1440 | if (gail_text_view->insert_notify_handler) |
---|
1441 | { |
---|
1442 | g_source_remove (gail_text_view->insert_notify_handler); |
---|
1443 | } |
---|
1444 | gail_text_view->insert_notify_handler = 0; |
---|
1445 | insert_idle_handler (gail_text_view); |
---|
1446 | gail_text_view->position = position; |
---|
1447 | gail_text_view->length = length; |
---|
1448 | } |
---|
1449 | |
---|
1450 | /* |
---|
1451 | * The signal will be emitted when the changed signal is received |
---|
1452 | */ |
---|
1453 | } |
---|
1454 | |
---|
1455 | /* Note arg1 returns the start of the delete range, arg2 returns the |
---|
1456 | * end of the delete range if multiple characters are deleted. If one |
---|
1457 | * character is deleted they have the same value, which is the caret |
---|
1458 | * location. |
---|
1459 | */ |
---|
1460 | static void |
---|
1461 | _gail_text_view_delete_range_cb (GtkTextBuffer *buffer, |
---|
1462 | GtkTextIter *arg1, |
---|
1463 | GtkTextIter *arg2, |
---|
1464 | gpointer user_data) |
---|
1465 | { |
---|
1466 | GtkTextView *text = (GtkTextView *) user_data; |
---|
1467 | AtkObject *accessible; |
---|
1468 | GailTextView *gail_text_view; |
---|
1469 | gint offset = gtk_text_iter_get_offset (arg1); |
---|
1470 | gint length = gtk_text_iter_get_offset (arg2) - offset; |
---|
1471 | |
---|
1472 | accessible = gtk_widget_get_accessible(GTK_WIDGET(text)); |
---|
1473 | gail_text_view = GAIL_TEXT_VIEW (accessible); |
---|
1474 | if (gail_text_view->insert_notify_handler) |
---|
1475 | { |
---|
1476 | g_source_remove (gail_text_view->insert_notify_handler); |
---|
1477 | gail_text_view->insert_notify_handler = 0; |
---|
1478 | if (gail_text_view->position == offset && |
---|
1479 | gail_text_view->length == length) |
---|
1480 | { |
---|
1481 | /* |
---|
1482 | * Do not bother with insert and delete notifications |
---|
1483 | */ |
---|
1484 | gail_text_view->signal_name = NULL; |
---|
1485 | gail_text_view->position = 0; |
---|
1486 | gail_text_view->length = 0; |
---|
1487 | return; |
---|
1488 | } |
---|
1489 | |
---|
1490 | insert_idle_handler (gail_text_view); |
---|
1491 | } |
---|
1492 | g_signal_emit_by_name (accessible, "text_changed::delete", |
---|
1493 | offset, length); |
---|
1494 | } |
---|
1495 | |
---|
1496 | /* Note arg1 and arg2 point to the same offset, which is the caret |
---|
1497 | * position after the move |
---|
1498 | */ |
---|
1499 | static void |
---|
1500 | _gail_text_view_mark_set_cb (GtkTextBuffer *buffer, |
---|
1501 | GtkTextIter *arg1, |
---|
1502 | GtkTextMark *arg2, |
---|
1503 | gpointer user_data) |
---|
1504 | { |
---|
1505 | GtkTextView *text = (GtkTextView *) user_data; |
---|
1506 | AtkObject *accessible; |
---|
1507 | GailTextView *gail_text_view; |
---|
1508 | const char *mark_name = gtk_text_mark_get_name(arg2); |
---|
1509 | |
---|
1510 | accessible = gtk_widget_get_accessible(GTK_WIDGET(text)); |
---|
1511 | gail_text_view = GAIL_TEXT_VIEW (accessible); |
---|
1512 | |
---|
1513 | /* |
---|
1514 | * Only generate the signal for the "insert" mark, which |
---|
1515 | * represents the cursor. |
---|
1516 | */ |
---|
1517 | if (mark_name && !strcmp(mark_name, "insert")) |
---|
1518 | { |
---|
1519 | int insert_offset, selection_bound; |
---|
1520 | gboolean selection_changed; |
---|
1521 | |
---|
1522 | insert_offset = gtk_text_iter_get_offset (arg1); |
---|
1523 | |
---|
1524 | selection_bound = get_selection_bound (buffer); |
---|
1525 | if (selection_bound != insert_offset) |
---|
1526 | { |
---|
1527 | if (selection_bound != gail_text_view->previous_selection_bound || |
---|
1528 | insert_offset != gail_text_view->previous_insert_offset) |
---|
1529 | { |
---|
1530 | selection_changed = TRUE; |
---|
1531 | } |
---|
1532 | else |
---|
1533 | { |
---|
1534 | selection_changed = FALSE; |
---|
1535 | } |
---|
1536 | } |
---|
1537 | else if (gail_text_view->previous_selection_bound != gail_text_view->previous_insert_offset) |
---|
1538 | { |
---|
1539 | selection_changed = TRUE; |
---|
1540 | } |
---|
1541 | else |
---|
1542 | { |
---|
1543 | selection_changed = FALSE; |
---|
1544 | } |
---|
1545 | |
---|
1546 | emit_text_caret_moved (gail_text_view, insert_offset); |
---|
1547 | /* |
---|
1548 | * insert and selection_bound marks are different to a selection |
---|
1549 | * has changed |
---|
1550 | */ |
---|
1551 | if (selection_changed) |
---|
1552 | g_signal_emit_by_name (accessible, "text_selection_changed"); |
---|
1553 | gail_text_view->previous_selection_bound = selection_bound; |
---|
1554 | } |
---|
1555 | } |
---|
1556 | |
---|
1557 | static void |
---|
1558 | _gail_text_view_changed_cb (GtkTextBuffer *buffer, |
---|
1559 | gpointer user_data) |
---|
1560 | { |
---|
1561 | GtkTextView *text = (GtkTextView *) user_data; |
---|
1562 | AtkObject *accessible; |
---|
1563 | GailTextView *gail_text_view; |
---|
1564 | |
---|
1565 | accessible = gtk_widget_get_accessible (GTK_WIDGET (text)); |
---|
1566 | gail_text_view = GAIL_TEXT_VIEW (accessible); |
---|
1567 | if (gail_text_view->signal_name) |
---|
1568 | { |
---|
1569 | if (!gail_text_view->insert_notify_handler) |
---|
1570 | { |
---|
1571 | gail_text_view->insert_notify_handler = g_idle_add (insert_idle_handler, accessible); |
---|
1572 | } |
---|
1573 | return; |
---|
1574 | } |
---|
1575 | emit_text_caret_moved (gail_text_view, get_insert_offset (buffer)); |
---|
1576 | gail_text_view->previous_selection_bound = get_selection_bound (buffer); |
---|
1577 | } |
---|
1578 | |
---|
1579 | static gchar* |
---|
1580 | get_text_near_offset (AtkText *text, |
---|
1581 | GailOffsetType function, |
---|
1582 | AtkTextBoundary boundary_type, |
---|
1583 | gint offset, |
---|
1584 | gint *start_offset, |
---|
1585 | gint *end_offset) |
---|
1586 | { |
---|
1587 | GtkTextView *view; |
---|
1588 | gpointer layout = NULL; |
---|
1589 | |
---|
1590 | view = GTK_TEXT_VIEW (GTK_ACCESSIBLE (text)->widget); |
---|
1591 | |
---|
1592 | /* |
---|
1593 | * Pass the GtkTextView to the function gail_text_util_get_text() |
---|
1594 | * so it can find the start and end of the current line on the display. |
---|
1595 | */ |
---|
1596 | if (boundary_type == ATK_TEXT_BOUNDARY_LINE_START || |
---|
1597 | boundary_type == ATK_TEXT_BOUNDARY_LINE_END) |
---|
1598 | layout = view; |
---|
1599 | |
---|
1600 | return gail_text_util_get_text (GAIL_TEXT_VIEW (text)->textutil, layout, |
---|
1601 | function, boundary_type, offset, |
---|
1602 | start_offset, end_offset); |
---|
1603 | } |
---|
1604 | |
---|
1605 | static gint |
---|
1606 | get_insert_offset (GtkTextBuffer *buffer) |
---|
1607 | { |
---|
1608 | GtkTextMark *cursor_mark; |
---|
1609 | GtkTextIter cursor_itr; |
---|
1610 | |
---|
1611 | cursor_mark = gtk_text_buffer_get_insert (buffer); |
---|
1612 | gtk_text_buffer_get_iter_at_mark (buffer, &cursor_itr, cursor_mark); |
---|
1613 | return gtk_text_iter_get_offset (&cursor_itr); |
---|
1614 | } |
---|
1615 | |
---|
1616 | static gint |
---|
1617 | get_selection_bound (GtkTextBuffer *buffer) |
---|
1618 | { |
---|
1619 | GtkTextMark *selection_mark; |
---|
1620 | GtkTextIter selection_itr; |
---|
1621 | |
---|
1622 | selection_mark = gtk_text_buffer_get_selection_bound (buffer); |
---|
1623 | gtk_text_buffer_get_iter_at_mark (buffer, &selection_itr, selection_mark); |
---|
1624 | return gtk_text_iter_get_offset (&selection_itr); |
---|
1625 | } |
---|
1626 | |
---|
1627 | static void |
---|
1628 | emit_text_caret_moved (GailTextView *gail_text_view, |
---|
1629 | gint insert_offset) |
---|
1630 | { |
---|
1631 | /* |
---|
1632 | * If we have text which has been inserted notify the user |
---|
1633 | */ |
---|
1634 | if (gail_text_view->insert_notify_handler) |
---|
1635 | { |
---|
1636 | g_source_remove (gail_text_view->insert_notify_handler); |
---|
1637 | gail_text_view->insert_notify_handler = 0; |
---|
1638 | insert_idle_handler (gail_text_view); |
---|
1639 | } |
---|
1640 | |
---|
1641 | if (insert_offset != gail_text_view->previous_insert_offset) |
---|
1642 | { |
---|
1643 | /* |
---|
1644 | * If the caret position has not changed then don't bother notifying |
---|
1645 | * |
---|
1646 | * When mouse click is used to change caret position, notification |
---|
1647 | * is received on button down and button up. |
---|
1648 | */ |
---|
1649 | g_signal_emit_by_name (gail_text_view, "text_caret_moved", insert_offset); |
---|
1650 | gail_text_view->previous_insert_offset = insert_offset; |
---|
1651 | } |
---|
1652 | } |
---|
1653 | |
---|
1654 | static gint |
---|
1655 | insert_idle_handler (gpointer data) |
---|
1656 | { |
---|
1657 | GailTextView *gail_text_view; |
---|
1658 | GtkTextBuffer *buffer; |
---|
1659 | |
---|
1660 | gail_text_view = GAIL_TEXT_VIEW (data); |
---|
1661 | |
---|
1662 | g_signal_emit_by_name (data, |
---|
1663 | gail_text_view->signal_name, |
---|
1664 | gail_text_view->position, |
---|
1665 | gail_text_view->length); |
---|
1666 | gail_text_view->signal_name = NULL; |
---|
1667 | gail_text_view->position = 0; |
---|
1668 | gail_text_view->length = 0; |
---|
1669 | |
---|
1670 | buffer = gail_text_view->textutil->buffer; |
---|
1671 | if (gail_text_view->insert_notify_handler) |
---|
1672 | { |
---|
1673 | /* |
---|
1674 | * If called from idle handler notify caret moved |
---|
1675 | */ |
---|
1676 | gail_text_view->insert_notify_handler = 0; |
---|
1677 | emit_text_caret_moved (gail_text_view, get_insert_offset (buffer)); |
---|
1678 | gail_text_view->previous_selection_bound = get_selection_bound (buffer); |
---|
1679 | } |
---|
1680 | return FALSE; |
---|
1681 | } |
---|