]> www.fi.muni.cz Git - evince.git/blob - libview/ev-view-accessible.c
[libview] Only set text and text_layout flags in page cache when a11y might be enabled
[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   {
436     gdk_window_get_origin (gtk_widget_get_window (toplevel), &x_window, &y_window);
437     *x += x_window;
438     *y += y_window;
439   }
440
441   *x -= EV_VIEW (widget)->scroll_x;
442   *y -= EV_VIEW (widget)->scroll_y;
443
444   *x += page_area.x;
445   *y += page_area.y;
446 }
447
448 static gint
449 ev_view_accessible_get_offset_at_point (AtkText *text,
450                                         gint x,
451                                         gint y,
452                                         AtkCoordType coords)
453 {
454   GtkWidget *widget, *toplevel;
455   EvRectangle *areas = NULL;
456   EvRectangle *rect = NULL;
457   guint n_areas = 0;
458   guint i = 0;
459   EvPageCache *page_cache;
460   gint x_window, y_window, x_widget, y_widget;
461   gint offset=-1, rx, ry;
462   gdouble scale;
463   GtkBorder border;
464   GdkRectangle page_area;
465
466   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
467   if (widget == NULL)
468     /* State is defunct */
469     return -1;
470
471   page_cache = EV_VIEW (widget)->page_cache;
472   if (!page_cache)
473     return -1;
474
475   ev_view_get_page_extents (EV_VIEW (widget), EV_VIEW (widget)->current_page,
476                             &page_area, &border);
477
478   scale = EV_VIEW (widget)->scale;
479   ev_page_cache_get_text_layout (page_cache, EV_VIEW (widget)->current_page, &areas, &n_areas);
480   if (!areas)
481     return -1;
482
483   rx = x;
484   ry = y;
485
486   rx -= page_area.x;
487   ry -= page_area.y;
488
489   rx += EV_VIEW (widget)->scroll_x;
490   ry += EV_VIEW (widget)->scroll_y;
491
492   toplevel = gtk_widget_get_toplevel (widget);
493   gtk_widget_translate_coordinates (widget, toplevel, 0, 0, &x_widget, &y_widget);
494   rx -= x_widget;
495   ry -= y_widget;
496
497   if (coords == ATK_XY_SCREEN)
498   {
499     gdk_window_get_origin (gtk_widget_get_window (toplevel), &x_window, &y_window);
500     rx -= x_window;
501     ry -= y_window;
502   }
503
504   rx /= scale;
505   ry /= scale;
506
507   for (i = 0; i < n_areas; i++)
508   {
509     rect = areas + i;
510     if (rx >= rect->x1 && rx <= rect->x2 &&
511         ry >= rect->y1 && ry <= rect->y2)
512         offset = i;
513   }
514
515   return offset;
516 }
517
518 static gint
519 ev_view_accessible_get_n_selections (AtkText *text)
520 {
521   GtkWidget *widget;
522   GtkTextBuffer *buffer;
523   GtkTextIter start, end;
524   gint select_start, select_end;
525
526   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
527   if (widget == NULL)
528     /* State is defunct */
529     return -1;
530
531   buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
532   if (!buffer)
533     return -1;
534
535   gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
536   select_start = gtk_text_iter_get_offset (&start);
537   select_end = gtk_text_iter_get_offset (&end);
538
539   if (select_start != select_end)
540      return 1;
541   else
542      return 0;
543 }
544
545 static gchar*
546 ev_view_accessible_get_selection (AtkText *text,
547                           gint    selection_num,
548                           gint    *start_pos,
549                           gint    *end_pos)
550 {
551   GtkWidget *widget;
552   GtkTextBuffer *buffer;
553   GtkTextIter start, end;
554   gchar *retval = NULL;
555
556   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
557   if (widget == NULL)
558     /* State is defunct */
559     return NULL;
560
561   if (selection_num != 0)
562      return NULL;
563
564   buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
565   if (!buffer)
566     return NULL;
567
568   gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
569   *start_pos = gtk_text_iter_get_offset (&start);
570   *end_pos = gtk_text_iter_get_offset (&end);
571
572   if (*start_pos != *end_pos)
573     retval = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
574
575   return retval;
576 }
577
578 static gboolean
579 ev_view_accessible_add_selection (AtkText *text,
580                           gint    start_pos,
581                           gint    end_pos)
582 {
583   GtkWidget *widget;
584   GtkTextBuffer *buffer;
585   GtkTextIter pos_itr;
586   GtkTextIter start, end;
587   gint select_start, select_end;
588   gboolean retval = FALSE;
589
590   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
591   if (widget == NULL)
592     /* State is defunct */
593     return FALSE;
594
595   buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
596   if (!buffer)
597     return FALSE;
598
599   gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
600   select_start = gtk_text_iter_get_offset (&start);
601   select_end = gtk_text_iter_get_offset (&end);
602
603  /* If there is already a selection, then don't allow
604   * another to be added
605   */
606   if (select_start == select_end) {
607     gtk_text_buffer_get_iter_at_offset (buffer,  &pos_itr, start_pos);
608     gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &pos_itr);
609     gtk_text_buffer_get_iter_at_offset (buffer,  &pos_itr, end_pos);
610     gtk_text_buffer_move_mark_by_name (buffer, "insert", &pos_itr);
611
612     retval = TRUE;
613   }
614
615   return retval;
616 }
617
618 static gboolean
619 ev_view_accessible_remove_selection (AtkText *text,
620                                      gint     selection_num)
621 {
622   GtkWidget *widget;
623   GtkTextBuffer *buffer;
624   GtkTextMark *cursor_mark;
625   GtkTextIter cursor_itr;
626   GtkTextIter start, end;
627   gint select_start, select_end;
628   gboolean retval = FALSE;
629
630   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
631   if (widget == NULL)
632     /* State is defunct */
633     return FALSE;
634
635   buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
636   if (!buffer)
637     return FALSE;
638
639   gtk_text_buffer_get_selection_bounds(buffer, &start, &end);
640   select_start = gtk_text_iter_get_offset(&start);
641   select_end = gtk_text_iter_get_offset(&end);
642
643   if (select_start != select_end) {
644    /* Setting the start & end of the selected region
645     * to the caret position turns off the selection.
646     */
647     cursor_mark = gtk_text_buffer_get_insert (buffer);
648     gtk_text_buffer_get_iter_at_mark (buffer, &cursor_itr, cursor_mark);
649     gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &cursor_itr);
650
651     retval = TRUE;
652   }
653
654   return retval;
655 }
656
657 static gboolean
658 ev_view_accessible_set_selection (AtkText *text,
659                           gint    selection_num,
660                           gint    start_pos,
661                           gint    end_pos)
662 {
663   GtkWidget *widget;
664   GtkTextBuffer *buffer;
665   GtkTextIter pos_itr;
666   GtkTextIter start, end;
667   gint select_start, select_end;
668   gboolean retval = FALSE;
669
670   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
671   if (widget == NULL)
672     /* State is defunct */
673     return FALSE;
674
675   buffer = ev_view_accessible_get_text_buffer (EV_VIEW_ACCESSIBLE (text), EV_VIEW (widget));
676   if (!buffer)
677     return FALSE;
678
679   gtk_text_buffer_get_selection_bounds(buffer, &start, &end);
680   select_start = gtk_text_iter_get_offset(&start);
681   select_end = gtk_text_iter_get_offset(&end);
682
683   if (select_start != select_end) {
684     gtk_text_buffer_get_iter_at_offset (buffer,  &pos_itr, start_pos);
685     gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &pos_itr);
686     gtk_text_buffer_get_iter_at_offset (buffer,  &pos_itr, end_pos);
687     gtk_text_buffer_move_mark_by_name (buffer, "insert", &pos_itr);
688
689     retval = TRUE;
690   }
691
692   return retval;
693 }
694
695 static void ev_view_accessible_text_iface_init (AtkTextIface * iface)
696 {
697         g_return_if_fail (iface != NULL);
698
699         iface->get_text = ev_view_accessible_get_text;
700         iface->get_character_at_offset = ev_view_accessible_get_character_at_offset;
701         iface->get_text_before_offset = ev_view_accessible_get_text_before_offset;
702         iface->get_text_at_offset = ev_view_accessible_get_text_at_offset;
703         iface->get_text_after_offset = ev_view_accessible_get_text_after_offset;
704         iface->get_caret_offset = ev_view_accessible_get_caret_offset;
705         iface->set_caret_offset = ev_view_accessible_set_caret_offset;
706         iface->get_character_count = ev_view_accessible_get_character_count;
707         iface->get_n_selections = ev_view_accessible_get_n_selections;
708         iface->get_selection = ev_view_accessible_get_selection;
709         iface->add_selection = ev_view_accessible_add_selection;
710         iface->remove_selection = ev_view_accessible_remove_selection;
711         iface->set_selection = ev_view_accessible_set_selection;
712         iface->get_run_attributes = ev_view_accessible_get_run_attributes;
713         iface->get_default_attributes = ev_view_accessible_get_default_attributes;
714         iface->get_character_extents = ev_view_accessible_get_character_extents;
715         iface->get_offset_at_point = ev_view_accessible_get_offset_at_point;
716         return;
717 }
718
719 static gboolean
720 ev_view_accessible_idle_do_action (gpointer data)
721 {
722         EvViewAccessiblePriv* priv = EV_VIEW_ACCESSIBLE_GET_PRIVATE (data);
723         
724         ev_view_scroll (EV_VIEW (gtk_accessible_get_widget (GTK_ACCESSIBLE (data))),
725                         priv->idle_scroll,
726                         FALSE);
727         priv->action_idle_handler = 0;
728         return FALSE;
729 }
730
731 static gboolean
732 ev_view_accessible_action_do_action (AtkAction *action,
733                                      gint       i)
734 {
735         EvViewAccessiblePriv* priv = EV_VIEW_ACCESSIBLE_GET_PRIVATE (action);
736         
737         if (gtk_accessible_get_widget (GTK_ACCESSIBLE (action)) == NULL)
738                 return FALSE;
739
740         if (priv->action_idle_handler)
741                 return FALSE;
742         
743         switch (i) {
744                 case ACTION_SCROLL_UP:
745                         priv->idle_scroll = GTK_SCROLL_PAGE_BACKWARD;
746                         break;
747                 case ACTION_SCROLL_DOWN:
748                         priv->idle_scroll = GTK_SCROLL_PAGE_FORWARD;
749                         break;
750                 default:
751                         return FALSE;
752         }
753         priv->action_idle_handler = g_idle_add (ev_view_accessible_idle_do_action, 
754                                                 action);
755         return TRUE;
756 }
757
758 static gint
759 ev_view_accessible_action_get_n_actions (AtkAction *action)
760 {
761         return LAST_ACTION;
762 }
763
764 static const gchar *
765 ev_view_accessible_action_get_description (AtkAction *action,
766                                            gint       i)
767 {
768   EvViewAccessiblePriv* priv = EV_VIEW_ACCESSIBLE_GET_PRIVATE (action);
769
770   if (i < 0 || i >= LAST_ACTION) 
771     return NULL;
772
773   if (priv->action_descriptions[i])
774     return priv->action_descriptions[i];
775   else
776     return ev_view_accessible_action_descriptions[i];
777 }
778
779 static const gchar *
780 ev_view_accessible_action_get_name (AtkAction *action,
781                                     gint       i)
782 {
783   if (i < 0 || i >= LAST_ACTION) 
784     return NULL;
785
786   return ev_view_accessible_action_names[i];
787 }
788
789 static gboolean
790 ev_view_accessible_action_set_description (AtkAction   *action,
791                                            gint         i,
792                                            const gchar *description)
793 {
794   EvViewAccessiblePriv* priv = EV_VIEW_ACCESSIBLE_GET_PRIVATE (action);
795   gchar *old_description;
796
797   if (i < 0 || i >= LAST_ACTION) 
798     return FALSE;
799
800   old_description = priv->action_descriptions[i];
801   priv->action_descriptions[i] = g_strdup (description);
802   g_free (old_description);
803
804   return TRUE;
805 }
806
807 static void ev_view_accessible_action_iface_init (AtkActionIface * iface)
808 {
809         iface->do_action = ev_view_accessible_action_do_action;
810         iface->get_n_actions = ev_view_accessible_action_get_n_actions;
811         iface->get_description = ev_view_accessible_action_get_description;
812         iface->get_name = ev_view_accessible_action_get_name;
813         iface->set_description = ev_view_accessible_action_set_description;
814 }
815
816 GType ev_view_accessible_get_type (void)
817 {
818         static GType type = 0;
819
820         if (G_UNLIKELY (type == 0)) {
821                 GTypeInfo tinfo = {
822                         0,      /* class size */
823                         (GBaseInitFunc) NULL,   /* base init */
824                         (GBaseFinalizeFunc) NULL,       /* base finalize */
825                         (GClassInitFunc) ev_view_accessible_class_init, /* class init */
826                         (GClassFinalizeFunc) NULL,      /* class finalize */
827                         NULL,   /* class data */
828                         0,      /* instance size */
829                         0,      /* nb preallocs */
830                         (GInstanceInitFunc) NULL,       /* instance init */
831                         NULL    /* value table */
832                 };
833
834                 const GInterfaceInfo atk_text_info = {
835                         (GInterfaceInitFunc)
836                             ev_view_accessible_text_iface_init,
837                         (GInterfaceFinalizeFunc) NULL,
838                         NULL
839                 };
840
841                 const GInterfaceInfo atk_action_info = {
842                         (GInterfaceInitFunc)
843                             ev_view_accessible_action_iface_init,
844                         (GInterfaceFinalizeFunc) NULL,
845                         NULL
846                 };
847                 /*
848                  * Figure out the size of the class and instance
849                  * we are deriving from
850                  */
851                 AtkObjectFactory *factory;
852                 GType derived_type;
853                 GTypeQuery query;
854                 GType derived_atk_type;     
855
856                 derived_type = g_type_parent (EV_TYPE_VIEW);
857                 factory = atk_registry_get_factory (atk_get_default_registry (), 
858                                                     derived_type);
859                 derived_atk_type = atk_object_factory_get_accessible_type (factory);
860
861                 g_type_query (derived_atk_type, &query);
862                 tinfo.class_size = query.class_size;
863                 tinfo.instance_size = query.instance_size;
864  
865                 type = g_type_register_static (derived_atk_type, "EvViewAccessible",
866                                                &tinfo, 0);
867                 g_type_add_interface_static (type, ATK_TYPE_TEXT,
868                                              &atk_text_info);
869                 g_type_add_interface_static (type, ATK_TYPE_ACTION,
870                                              &atk_action_info);
871         }
872
873         return type;
874 }
875
876 static AtkObject *ev_view_accessible_new(GObject * obj)
877 {
878         AtkObject *accessible;
879         
880         g_return_val_if_fail(EV_IS_VIEW (obj), NULL);
881
882         accessible = g_object_new (ev_view_accessible_get_type (), NULL);
883         atk_object_initialize (accessible, obj);
884
885         atk_object_set_name (ATK_OBJECT (accessible), _("Document View"));
886         atk_object_set_role (ATK_OBJECT (accessible), ATK_ROLE_UNKNOWN);
887
888         return accessible;
889 }
890
891 typedef AtkObjectFactory      EvViewAccessibleFactory;
892 typedef AtkObjectFactoryClass EvViewAccessibleFactoryClass;
893
894 static void ev_view_accessible_factory_init (EvViewAccessibleFactory *factory)
895 {
896 }
897
898 static GType ev_view_accessible_factory_get_accessible_type(void)
899 {
900         return ev_view_accessible_get_type();
901 }
902
903 static AtkObject *ev_view_accessible_factory_create_accessible (GObject * obj)
904 {
905         return ev_view_accessible_new(obj);
906 }
907
908 static void ev_view_accessible_factory_class_init (AtkObjectFactoryClass * klass)
909 {
910         klass->create_accessible = ev_view_accessible_factory_create_accessible;
911         klass->get_accessible_type =
912             ev_view_accessible_factory_get_accessible_type;
913 }
914
915 G_DEFINE_TYPE (EvViewAccessibleFactory, ev_view_accessible_factory, ATK_TYPE_OBJECT_FACTORY)