]> www.fi.muni.cz Git - evince.git/blob - libview/ev-view-accessible.c
[dualscreen] fix crash on ctrl+w and fix control window closing
[evince.git] / libview / ev-view-accessible.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /* this file is part of evince, a gnome document viewer
3  *
4  *  Copyright (C) 2004 Red Hat, Inc
5  *
6  * Evince is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Evince is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20
21 #include <math.h>
22 #include <config.h>
23 #include <glib/gi18n-lib.h>
24 #include <gtk/gtk.h>
25 #include <libgail-util/gail-util.h>
26
27 #include "ev-selection.h"
28 #include "ev-page-cache.h"
29 #include "ev-view-accessible.h"
30 #include "ev-view-private.h"
31
32 #define EV_TYPE_VIEW_ACCESSIBLE      (ev_view_accessible_get_type ())
33 #define EV_VIEW_ACCESSIBLE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_VIEW_ACCESSIBLE, EvViewAccessible))
34 #define EV_IS_VIEW_ACCESSIBLE(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_VIEW_ACCESSIBLE))
35
36 static GType ev_view_accessible_get_type (void);
37
38 enum {
39         ACTION_SCROLL_UP,
40         ACTION_SCROLL_DOWN,
41         LAST_ACTION
42 };
43
44 static const gchar *const ev_view_accessible_action_names[] =
45 {
46         N_("Scroll Up"),
47         N_("Scroll Down"),
48         NULL
49 };
50
51 static const gchar *const ev_view_accessible_action_descriptions[] =
52 {
53         N_("Scroll View Up"),
54         N_("Scroll View Down"),
55         NULL
56 };
57
58 typedef struct {
59         /* Action */
60         gchar *action_descriptions[LAST_ACTION];
61         guint action_idle_handler;
62         GtkScrollType idle_scroll;
63         GtkTextBuffer *buffer;
64         guint current_page;
65 } EvViewAccessiblePriv;
66
67 typedef GtkAccessibleClass EvViewAccessibleClass;
68 typedef GtkAccessible EvViewAccessible;
69
70 #define EV_VIEW_ACCESSIBLE_GET_PRIVATE(inst) (G_TYPE_INSTANCE_GET_PRIVATE ((inst), EV_TYPE_VIEW_ACCESSIBLE, EvViewAccessiblePriv))
71
72 static void
73 ev_view_accessible_finalize (GObject *object)
74 {
75         EvViewAccessiblePriv *priv = EV_VIEW_ACCESSIBLE_GET_PRIVATE (object);
76         int i;
77
78         if (priv->action_idle_handler)
79                 g_source_remove (priv->action_idle_handler);
80         for (i = 0; i < LAST_ACTION; i++)
81                 g_free (priv->action_descriptions [i]);
82         if (priv->buffer)
83                 g_object_unref (priv->buffer);
84
85 }
86
87 static void ev_view_accessible_class_init (EvViewAccessibleClass *klass)
88 {
89         GObjectClass *object_class = G_OBJECT_CLASS (klass);
90
91         object_class->finalize = ev_view_accessible_finalize;
92
93         g_type_class_add_private (klass, sizeof (EvViewAccessiblePriv));
94 }
95
96 static GtkTextBuffer *
97 ev_view_accessible_get_text_buffer (EvViewAccessible *accessible, EvView *view)
98 {
99         EvPageCache *page_cache;
100         const gchar *retval = NULL;
101         EvViewAccessiblePriv* priv = EV_VIEW_ACCESSIBLE_GET_PRIVATE (accessible);
102
103         page_cache = view->page_cache;
104         if (!page_cache) {
105                 return NULL;
106         }
107
108         if (view->current_page == priv->current_page && priv->buffer) {
109                 return priv->buffer;
110         }
111
112         priv->current_page = view->current_page;
113
114         if (!priv->buffer) {
115                 priv->buffer = gtk_text_buffer_new (NULL);
116         }
117
118         retval = ev_page_cache_get_text (page_cache, view->current_page);
119         if (retval)
120                 gtk_text_buffer_set_text (priv->buffer, retval, -1);
121
122         return priv->buffer;
123 }
124
125 static gchar*
126 ev_view_accessible_get_text (AtkText *text,
127                              gint    start_pos,
128                              gint    end_pos)
129 {
130         GtkWidget *widget;
131         GtkTextIter start, end;
132         GtkTextBuffer *buffer;
133         gchar *retval;
134
135         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
136         if (widget == NULL)
137                 /* State is defunct */
138                 return NULL;
139
140         buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
141         if (!buffer)
142                 return NULL;
143
144         gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
145         gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
146         retval = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
147
148         return retval;
149 }
150
151 static gunichar
152 ev_view_accessible_get_character_at_offset (AtkText *text,
153                                             gint    offset)
154 {
155         GtkWidget *widget;
156         GtkTextIter start, end;
157         GtkTextBuffer *buffer;
158         gchar *string;
159         gunichar unichar;
160
161         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
162         if (widget == NULL)
163                 /* State is defunct */
164                 return '\0';
165
166         buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
167         if (!buffer)
168                 return '\0';
169
170         if (offset >= gtk_text_buffer_get_char_count (buffer))
171                 return '\0';
172
173         gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
174         end = start;
175         gtk_text_iter_forward_char (&end);
176         string = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
177         unichar = g_utf8_get_char (string);
178         g_free(string);
179
180         return unichar;
181 }
182
183 static gchar*
184 ev_view_accessible_get_text_before_offset (AtkText          *text,
185                                            gint             offset,
186                                            AtkTextBoundary  boundary_type,
187                                            gint             *start_offset,
188                                            gint             *end_offset)
189 {
190         GtkWidget *widget;
191         gpointer layout = NULL;
192         GailTextUtil *gail_text = NULL;
193         gchar *retval = NULL;
194         GtkTextBuffer *buffer;
195
196         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
197         if (widget == NULL)
198                 /* State is defunct */
199                 return NULL;
200
201         buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
202         if (!buffer)
203                 return NULL;
204
205         gail_text = gail_text_util_new ();
206         gail_text_util_buffer_setup (gail_text, buffer);
207         retval = gail_text_util_get_text (gail_text, layout,
208                                           GAIL_BEFORE_OFFSET, boundary_type,
209                                           offset, start_offset, end_offset);
210         g_object_unref (gail_text);
211
212         return retval;
213 }
214
215 static gchar*
216 ev_view_accessible_get_text_at_offset (AtkText          *text,
217                                        gint             offset,
218                                        AtkTextBoundary  boundary_type,
219                                        gint             *start_offset,
220                                        gint             *end_offset)
221 {
222         GtkWidget *widget;
223         gpointer layout = NULL;
224         GailTextUtil *gail_text = NULL;
225         gchar *retval = NULL;
226         GtkTextBuffer *buffer;
227
228         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
229         if (widget == NULL)
230                 /* State is defunct */
231                 return NULL;
232
233         buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
234         if (!buffer)
235                 return NULL;
236
237         gail_text = gail_text_util_new ();
238         gail_text_util_buffer_setup (gail_text, buffer);
239         retval = gail_text_util_get_text (gail_text, layout,
240                                           GAIL_AT_OFFSET, boundary_type,
241                                           offset, start_offset, end_offset);
242         g_object_unref (gail_text);
243
244         return retval;
245 }
246
247 static gchar*
248 ev_view_accessible_get_text_after_offset (AtkText           *text,
249                                           gint              offset,
250                                           AtkTextBoundary   boundary_type,
251                                           gint              *start_offset,
252                                           gint              *end_offset)
253 {
254         GtkWidget *widget;
255         gpointer layout = NULL;
256         GailTextUtil *gail_text = NULL;
257         gchar *retval = NULL;
258         GtkTextBuffer *buffer;
259
260         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
261         if (widget == NULL)
262                 /* State is defunct */
263                 return NULL;
264
265         buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
266         if (!buffer)
267                 return NULL;
268
269         gail_text = gail_text_util_new ();
270         gail_text_util_buffer_setup (gail_text, buffer);
271         retval = gail_text_util_get_text (gail_text, layout,
272                                           GAIL_AFTER_OFFSET, boundary_type,
273                                           offset, start_offset, end_offset);
274         g_object_unref (gail_text);
275
276         return retval;
277 }
278
279 static gint
280 ev_view_accessible_get_character_count (AtkText *text)
281 {
282         GtkWidget *widget;
283         GtkTextBuffer *buffer;
284         gint retval;
285
286         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
287         if (widget == NULL)
288                 /* State is defunct */
289                 return 0;
290
291         buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
292         if (!buffer)
293                 return 0;
294
295         retval = gtk_text_buffer_get_char_count (buffer);
296
297         return retval;
298 }
299
300 static gint
301 ev_view_accessible_get_caret_offset (AtkText *text)
302 {
303         GtkWidget *widget;
304         GtkTextBuffer *buffer;
305         GtkTextMark *cursor_mark;
306         GtkTextIter cursor_itr;
307         gint retval;
308
309         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
310         if (widget == NULL)
311                 /* State is defunct */
312                 return 0;
313
314         buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
315         if (!buffer)
316                 return 0;
317
318         cursor_mark = gtk_text_buffer_get_insert (buffer);
319         gtk_text_buffer_get_iter_at_mark (buffer, &cursor_itr, cursor_mark);
320         retval = gtk_text_iter_get_offset (&cursor_itr);
321
322         return retval;
323 }
324
325 static gboolean
326 ev_view_accessible_set_caret_offset (AtkText *text, gint offset)
327 {
328         GtkWidget *widget;
329         GtkTextBuffer *buffer;
330         GtkTextIter pos_itr;
331
332         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
333         if (widget == NULL)
334                 /* State is defunct */
335                 return FALSE;
336
337         buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
338         if (!buffer)
339                 return FALSE;
340
341         gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, offset);
342         gtk_text_buffer_place_cursor (buffer, &pos_itr);
343
344         return TRUE;
345 }
346
347 static AtkAttributeSet*
348 ev_view_accessible_get_run_attributes (AtkText *text,
349                                        gint    offset,
350                                        gint    *start_offset,
351                                        gint    *end_offset)
352 {
353         GtkWidget *widget;
354         GtkTextBuffer *buffer;
355         AtkAttributeSet *retval;
356
357         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
358         if (widget == NULL)
359                 /* State is defunct */
360                 return NULL;
361
362         buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
363         if (!buffer)
364                 return NULL;
365
366         retval = gail_misc_buffer_get_run_attributes (buffer, offset,
367                                                       start_offset, end_offset);
368
369         return retval;
370 }
371
372 static AtkAttributeSet*
373 ev_view_accessible_get_default_attributes (AtkText *text)
374 {
375         GtkWidget *widget;
376
377         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
378         if (widget == NULL)
379                 /* State is defunct */
380                 return NULL;
381         return NULL;
382 }
383
384 static void
385 ev_view_accessible_get_character_extents (AtkText      *text,
386                                           gint         offset,
387                                           gint         *x,
388                                           gint         *y,
389                                           gint         *width,
390                                           gint         *height,
391                                           AtkCoordType coords)
392 {
393         GtkWidget *widget, *toplevel;
394         EvRectangle *areas = NULL;
395         EvRectangle *rect = NULL;
396         guint n_areas = 0;
397         EvPageCache *page_cache;
398         gint x_widget, y_widget, x_window, y_window;
399         gdouble scale;
400         GtkBorder border;
401         GdkRectangle page_area;
402
403         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
404         if (widget == NULL)
405                 /* State is defunct */
406                 return;
407
408         page_cache = EV_VIEW (widget)->page_cache;
409         if (!page_cache)
410                 return;
411
412         ev_view_get_page_extents (EV_VIEW (widget), EV_VIEW (widget)->current_page,
413                                   &page_area, &border);
414
415         scale = EV_VIEW (widget)->scale;
416         ev_page_cache_get_text_layout (page_cache, EV_VIEW (widget)->current_page, &areas, &n_areas);
417         if (!areas)
418                 return;
419
420         if (offset >= n_areas)
421                 return;
422
423         rect = areas + offset;
424         *x = (int)(rect->x1 * scale);
425         *y = (int)(rect->y1 * scale);
426
427         *width = (int)(fabs (rect->x2 - rect->x1) * scale);
428         *height = (int)(fabs (rect->y2 - rect->y1) * scale);
429
430         toplevel = gtk_widget_get_toplevel (widget);
431         gtk_widget_translate_coordinates (widget, toplevel, 0, 0, &x_widget, &y_widget);
432         *x += x_widget;
433         *y += y_widget;
434
435         if (coords == ATK_XY_SCREEN) {
436                 gdk_window_get_origin (gtk_widget_get_window (toplevel), &x_window, &y_window);
437                 *x += x_window;
438                 *y += y_window;
439         }
440
441         *x -= EV_VIEW (widget)->scroll_x;
442         *y -= EV_VIEW (widget)->scroll_y;
443
444         *x += page_area.x;
445         *y += page_area.y;
446 }
447
448 static gint
449 ev_view_accessible_get_offset_at_point (AtkText      *text,
450                                         gint         x,
451                                         gint         y,
452                                         AtkCoordType coords)
453 {
454         GtkWidget *widget, *toplevel;
455         EvRectangle *areas = NULL;
456         EvRectangle *rect = NULL;
457         guint n_areas = 0;
458         guint i = 0;
459         EvPageCache *page_cache;
460         gint x_window, y_window, x_widget, y_widget;
461         gint offset=-1, rx, ry;
462         gdouble scale;
463         GtkBorder border;
464         GdkRectangle page_area;
465
466         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
467         if (widget == NULL)
468                 /* State is defunct */
469                 return -1;
470
471         page_cache = EV_VIEW (widget)->page_cache;
472         if (!page_cache)
473                 return -1;
474
475         ev_view_get_page_extents (EV_VIEW (widget), EV_VIEW (widget)->current_page,
476                                   &page_area, &border);
477
478         scale = EV_VIEW (widget)->scale;
479         ev_page_cache_get_text_layout (page_cache, EV_VIEW (widget)->current_page, &areas, &n_areas);
480         if (!areas)
481                 return -1;
482
483         rx = x;
484         ry = y;
485
486         rx -= page_area.x;
487         ry -= page_area.y;
488
489         rx += EV_VIEW (widget)->scroll_x;
490         ry += EV_VIEW (widget)->scroll_y;
491
492         toplevel = gtk_widget_get_toplevel (widget);
493         gtk_widget_translate_coordinates (widget, toplevel, 0, 0, &x_widget, &y_widget);
494         rx -= x_widget;
495         ry -= y_widget;
496
497         if (coords == ATK_XY_SCREEN) {
498                 gdk_window_get_origin (gtk_widget_get_window (toplevel), &x_window, &y_window);
499                 rx -= x_window;
500                 ry -= y_window;
501         }
502
503         rx /= scale;
504         ry /= scale;
505
506         for (i = 0; i < n_areas; i++) {
507                 rect = areas + i;
508                 if (rx >= rect->x1 && rx <= rect->x2 &&
509                     ry >= rect->y1 && ry <= rect->y2)
510                         offset = i;
511         }
512
513         return offset;
514 }
515
516 static gint
517 ev_view_accessible_get_n_selections (AtkText *text)
518 {
519         GtkWidget *widget;
520         GtkTextBuffer *buffer;
521         GtkTextIter start, end;
522         gint select_start, select_end;
523
524         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
525         if (widget == NULL)
526                 /* State is defunct */
527                 return -1;
528
529         buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
530         if (!buffer)
531                 return -1;
532
533         gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
534         select_start = gtk_text_iter_get_offset (&start);
535         select_end = gtk_text_iter_get_offset (&end);
536
537         if (select_start != select_end)
538                 return 1;
539         else
540                 return 0;
541 }
542
543 static gchar*
544 ev_view_accessible_get_selection (AtkText *text,
545                                   gint    selection_num,
546                                   gint    *start_pos,
547                                   gint    *end_pos)
548 {
549         GtkWidget *widget;
550         GtkTextBuffer *buffer;
551         GtkTextIter start, end;
552         gchar *retval = NULL;
553
554         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
555         if (widget == NULL)
556                 /* State is defunct */
557                 return NULL;
558
559         if (selection_num != 0)
560                 return NULL;
561
562         buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
563         if (!buffer)
564                 return NULL;
565
566         gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
567         *start_pos = gtk_text_iter_get_offset (&start);
568         *end_pos = gtk_text_iter_get_offset (&end);
569
570         if (*start_pos != *end_pos)
571                 retval = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
572
573         return retval;
574 }
575
576 static gboolean
577 ev_view_accessible_add_selection (AtkText *text,
578                                   gint    start_pos,
579                                   gint    end_pos)
580 {
581         GtkWidget *widget;
582         GtkTextBuffer *buffer;
583         GtkTextIter pos_itr;
584         GtkTextIter start, end;
585         gint select_start, select_end;
586         gboolean retval = FALSE;
587
588         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
589         if (widget == NULL)
590                 /* State is defunct */
591                 return FALSE;
592
593         buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
594         if (!buffer)
595                 return FALSE;
596
597         gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
598         select_start = gtk_text_iter_get_offset (&start);
599         select_end = gtk_text_iter_get_offset (&end);
600
601         /* If there is already a selection, then don't allow
602          * another to be added
603          */
604         if (select_start == select_end) {
605                 gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, start_pos);
606                 gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &pos_itr);
607                 gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, end_pos);
608                 gtk_text_buffer_move_mark_by_name (buffer, "insert", &pos_itr);
609
610                 retval = TRUE;
611         }
612
613         return retval;
614 }
615
616 static gboolean
617 ev_view_accessible_remove_selection (AtkText *text,
618                                      gint    selection_num)
619 {
620         GtkWidget *widget;
621         GtkTextBuffer *buffer;
622         GtkTextMark *cursor_mark;
623         GtkTextIter cursor_itr;
624         GtkTextIter start, end;
625         gint select_start, select_end;
626         gboolean retval = FALSE;
627
628         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
629         if (widget == NULL)
630                 /* State is defunct */
631                 return FALSE;
632
633         buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
634         if (!buffer)
635                 return FALSE;
636
637         gtk_text_buffer_get_selection_bounds(buffer, &start, &end);
638         select_start = gtk_text_iter_get_offset(&start);
639         select_end = gtk_text_iter_get_offset(&end);
640
641         if (select_start != select_end) {
642                 /* Setting the start & end of the selected region
643                  * to the caret position turns off the selection.
644                  */
645                 cursor_mark = gtk_text_buffer_get_insert (buffer);
646                 gtk_text_buffer_get_iter_at_mark (buffer, &cursor_itr, cursor_mark);
647                 gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &cursor_itr);
648
649                 retval = TRUE;
650         }
651
652         return retval;
653 }
654
655 static gboolean
656 ev_view_accessible_set_selection (AtkText *text,
657                                   gint    selection_num,
658                                   gint    start_pos,
659                                   gint    end_pos)
660 {
661         GtkWidget *widget;
662         GtkTextBuffer *buffer;
663         GtkTextIter pos_itr;
664         GtkTextIter start, end;
665         gint select_start, select_end;
666         gboolean retval = FALSE;
667
668         widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
669         if (widget == NULL)
670                 /* State is defunct */
671                 return FALSE;
672
673         buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
674         if (!buffer)
675                 return FALSE;
676
677         gtk_text_buffer_get_selection_bounds(buffer, &start, &end);
678         select_start = gtk_text_iter_get_offset(&start);
679         select_end = gtk_text_iter_get_offset(&end);
680
681         if (select_start != select_end) {
682                 gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, start_pos);
683                 gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &pos_itr);
684                 gtk_text_buffer_get_iter_at_offset (buffer, &pos_itr, end_pos);
685                 gtk_text_buffer_move_mark_by_name (buffer, "insert", &pos_itr);
686
687                 retval = TRUE;
688         }
689
690         return retval;
691 }
692
693 static void ev_view_accessible_text_iface_init (AtkTextIface * iface)
694 {
695         g_return_if_fail (iface != NULL);
696
697         iface->get_text = ev_view_accessible_get_text;
698         iface->get_character_at_offset = ev_view_accessible_get_character_at_offset;
699         iface->get_text_before_offset = ev_view_accessible_get_text_before_offset;
700         iface->get_text_at_offset = ev_view_accessible_get_text_at_offset;
701         iface->get_text_after_offset = ev_view_accessible_get_text_after_offset;
702         iface->get_caret_offset = ev_view_accessible_get_caret_offset;
703         iface->set_caret_offset = ev_view_accessible_set_caret_offset;
704         iface->get_character_count = ev_view_accessible_get_character_count;
705         iface->get_n_selections = ev_view_accessible_get_n_selections;
706         iface->get_selection = ev_view_accessible_get_selection;
707         iface->add_selection = ev_view_accessible_add_selection;
708         iface->remove_selection = ev_view_accessible_remove_selection;
709         iface->set_selection = ev_view_accessible_set_selection;
710         iface->get_run_attributes = ev_view_accessible_get_run_attributes;
711         iface->get_default_attributes = ev_view_accessible_get_default_attributes;
712         iface->get_character_extents = ev_view_accessible_get_character_extents;
713         iface->get_offset_at_point = ev_view_accessible_get_offset_at_point;
714         return;
715 }
716
717 static gboolean
718 ev_view_accessible_idle_do_action (gpointer data)
719 {
720         EvViewAccessiblePriv* priv = EV_VIEW_ACCESSIBLE_GET_PRIVATE (data);
721
722         ev_view_scroll (EV_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (data))),
723                         priv->idle_scroll,
724                         FALSE);
725         priv->action_idle_handler = 0;
726         return FALSE;
727 }
728
729 static gboolean
730 ev_view_accessible_action_do_action (AtkAction *action,
731                                      gint      i)
732 {
733         EvViewAccessiblePriv* priv = EV_VIEW_ACCESSIBLE_GET_PRIVATE (action);
734
735         if (gtk_accessible_get_widget (GTK_ACCESSIBLE (action)) == NULL)
736                 return FALSE;
737
738         if (priv->action_idle_handler)
739                 return FALSE;
740
741         switch (i) {
742         case ACTION_SCROLL_UP:
743                 priv->idle_scroll = GTK_SCROLL_PAGE_BACKWARD;
744                 break;
745         case ACTION_SCROLL_DOWN:
746                 priv->idle_scroll = GTK_SCROLL_PAGE_FORWARD;
747                 break;
748         default:
749                 return FALSE;
750         }
751         priv->action_idle_handler = g_idle_add (ev_view_accessible_idle_do_action,
752                                                 action);
753         return TRUE;
754 }
755
756 static gint
757 ev_view_accessible_action_get_n_actions (AtkAction *action)
758 {
759         return LAST_ACTION;
760 }
761
762 static const gchar *
763 ev_view_accessible_action_get_description (AtkAction *action,
764                                            gint      i)
765 {
766         EvViewAccessiblePriv* priv = EV_VIEW_ACCESSIBLE_GET_PRIVATE (action);
767
768         if (i < 0 || i >= LAST_ACTION)
769                 return NULL;
770
771         if (priv->action_descriptions[i])
772                 return priv->action_descriptions[i];
773         else
774                 return ev_view_accessible_action_descriptions[i];
775 }
776
777 static const gchar *
778 ev_view_accessible_action_get_name (AtkAction *action,
779                                     gint      i)
780 {
781         if (i < 0 || i >= LAST_ACTION)
782                 return NULL;
783
784         return ev_view_accessible_action_names[i];
785 }
786
787 static gboolean
788 ev_view_accessible_action_set_description (AtkAction   *action,
789                                            gint        i,
790                                            const gchar *description)
791 {
792         EvViewAccessiblePriv* priv = EV_VIEW_ACCESSIBLE_GET_PRIVATE (action);
793         gchar *old_description;
794
795         if (i < 0 || i >= LAST_ACTION)
796                 return FALSE;
797
798         old_description = priv->action_descriptions[i];
799         priv->action_descriptions[i] = g_strdup (description);
800         g_free (old_description);
801
802         return TRUE;
803 }
804
805 static void ev_view_accessible_action_iface_init (AtkActionIface * iface)
806 {
807         iface->do_action = ev_view_accessible_action_do_action;
808         iface->get_n_actions = ev_view_accessible_action_get_n_actions;
809         iface->get_description = ev_view_accessible_action_get_description;
810         iface->get_name = ev_view_accessible_action_get_name;
811         iface->set_description = ev_view_accessible_action_set_description;
812 }
813
814 GType ev_view_accessible_get_type (void)
815 {
816         static GType type = 0;
817
818         if (G_UNLIKELY (type == 0)) {
819                 GTypeInfo tinfo = {
820                         0,      /* class size */
821                         (GBaseInitFunc) NULL,   /* base init */
822                         (GBaseFinalizeFunc) NULL,       /* base finalize */
823                         (GClassInitFunc) ev_view_accessible_class_init, /* class init */
824                         (GClassFinalizeFunc) NULL,      /* class finalize */
825                         NULL,   /* class data */
826                         0,      /* instance size */
827                         0,      /* nb preallocs */
828                         (GInstanceInitFunc) NULL,       /* instance init */
829                         NULL    /* value table */
830                 };
831
832                 const GInterfaceInfo atk_text_info = {
833                         (GInterfaceInitFunc)
834                         ev_view_accessible_text_iface_init,
835                         (GInterfaceFinalizeFunc) NULL,
836                         NULL
837                 };
838
839                 const GInterfaceInfo atk_action_info = {
840                         (GInterfaceInitFunc)
841                         ev_view_accessible_action_iface_init,
842                         (GInterfaceFinalizeFunc) NULL,
843                         NULL
844                 };
845                 /*
846                  * Figure out the size of the class and instance
847                  * we are deriving from
848                  */
849                 AtkObjectFactory *factory;
850                 GType derived_type;
851                 GTypeQuery query;
852                 GType derived_atk_type;
853
854                 derived_type = g_type_parent (EV_TYPE_VIEW);
855                 factory = atk_registry_get_factory (atk_get_default_registry (),
856                                                     derived_type);
857                 derived_atk_type = atk_object_factory_get_accessible_type (factory);
858
859                 g_type_query (derived_atk_type, &query);
860                 tinfo.class_size = query.class_size;
861                 tinfo.instance_size = query.instance_size;
862
863                 type = g_type_register_static (derived_atk_type, "EvViewAccessible",
864                                                &tinfo, 0);
865                 g_type_add_interface_static (type, ATK_TYPE_TEXT,
866                                              &atk_text_info);
867                 g_type_add_interface_static (type, ATK_TYPE_ACTION,
868                                              &atk_action_info);
869         }
870
871         return type;
872 }
873
874 static AtkObject *ev_view_accessible_new(GObject * obj)
875 {
876         AtkObject *accessible;
877
878         g_return_val_if_fail(EV_IS_VIEW (obj), NULL);
879
880         accessible = g_object_new (ev_view_accessible_get_type (), NULL);
881         atk_object_initialize (accessible, obj);
882
883         atk_object_set_name (ATK_OBJECT (accessible), _("Document View"));
884         atk_object_set_role (ATK_OBJECT (accessible), ATK_ROLE_DOCUMENT_FRAME);
885
886         return accessible;
887 }
888
889 typedef AtkObjectFactory      EvViewAccessibleFactory;
890 typedef AtkObjectFactoryClass EvViewAccessibleFactoryClass;
891
892 static void ev_view_accessible_factory_init (EvViewAccessibleFactory *factory)
893 {
894 }
895
896 static GType ev_view_accessible_factory_get_accessible_type(void)
897 {
898         return ev_view_accessible_get_type();
899 }
900
901 static AtkObject *ev_view_accessible_factory_create_accessible (GObject * obj)
902 {
903         return ev_view_accessible_new(obj);
904 }
905
906 static void ev_view_accessible_factory_class_init (AtkObjectFactoryClass * klass)
907 {
908         klass->create_accessible = ev_view_accessible_factory_create_accessible;
909         klass->get_accessible_type = ev_view_accessible_factory_get_accessible_type;
910 }
911
912 G_DEFINE_TYPE (EvViewAccessibleFactory, ev_view_accessible_factory, ATK_TYPE_OBJECT_FACTORY)