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