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