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