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