[evince] [libview] Implement AtkText interface in EvView



commit 9fbd530885b4836b86dc7c409d6a7e72b09e3f92
Author: Daniel Garcia <danigm yaco es>
Date:   Sat Jun 26 18:38:02 2010 +0200

    [libview] Implement AtkText interface in EvView

 libview/Makefile.am          |    2 +
 libview/ev-view-accessible.c |  433 ++++++++++++++++++++++++++++++++++++++----
 2 files changed, 397 insertions(+), 38 deletions(-)
---
diff --git a/libview/Makefile.am b/libview/Makefile.am
index 23210fa..226a653 100644
--- a/libview/Makefile.am
+++ b/libview/Makefile.am
@@ -57,6 +57,7 @@ libevview_la_CPPFLAGS = \
 	-I$(top_srcdir)				\
 	-I$(top_srcdir)/libdocument		\
 	-I$(top_builddir)			\
+	-I$(top_srcdir)/cut-n-paste/gail-util/	\
 	$(AM_CPPFLAGS)
 
 libevview_la_CFLAGS = \
@@ -73,6 +74,7 @@ libevview_la_LDFLAGS = \
 
 libevview_la_LIBADD = \
 	$(top_builddir)/libdocument/libevdocument.la \
+	$(top_builddir)/cut-n-paste/gail-util/libgail.la \
 	$(LIBVIEW_LIBS)
 
 BUILT_SOURCES = 			\
diff --git a/libview/ev-view-accessible.c b/libview/ev-view-accessible.c
index ab023a9..afd4771 100644
--- a/libview/ev-view-accessible.c
+++ b/libview/ev-view-accessible.c
@@ -18,11 +18,18 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+#include <math.h>
 #include <config.h>
 #include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+#include "gailmisc.h"
+#include "gailtextutil.h"
 
+#include "ev-selection.h"
+#include "ev-page-cache.h"
 #include "ev-view-accessible.h"
 #include "ev-view-private.h"
+#include "ev-mapping.h"
 
 #define EV_TYPE_VIEW_ACCESSIBLE      (ev_view_accessible_get_type ())
 #define EV_VIEW_ACCESSIBLE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_VIEW_ACCESSIBLE, EvViewAccessible))
@@ -36,6 +43,24 @@ enum {
 	LAST_ACTION
 };
 
+static GtkTextBuffer *
+ev_view_accessible_get_text_buffer (EvView *view)
+{
+  EvPageCache *page_cache;
+  GtkTextBuffer *buffer;
+  const gchar *retval = NULL;
+
+  page_cache = view->page_cache;
+  if (!page_cache) {
+    return NULL;
+  }
+  retval = ev_page_cache_get_text (page_cache, view->current_page);
+  buffer = gtk_text_buffer_new (NULL);
+  gtk_text_buffer_set_text (buffer, retval, -1);
+
+  return buffer;
+}
+
 static const gchar *const ev_view_accessible_action_names[] = 
 {
 	N_("Scroll Up"),
@@ -88,13 +113,25 @@ ev_view_accessible_get_text (AtkText *text,
                      gint    end_pos)
 {
   GtkWidget *widget;
+  GtkTextIter start, end;
+  GtkTextBuffer *buffer;
+  gchar *retval;
 
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
     /* State is defunct */
     return NULL;
 
-  return NULL;
+  buffer = ev_view_accessible_get_text_buffer (EV_VIEW (widget));
+  if (!buffer)
+    return NULL;
+
+  gtk_text_buffer_get_iter_at_offset (buffer, &start, start_pos);
+  gtk_text_buffer_get_iter_at_offset (buffer, &end, end_pos);
+  retval = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+  g_object_unref (buffer);
+
+  return retval;
 }
 
 static gunichar 
@@ -102,13 +139,32 @@ ev_view_accessible_get_character_at_offset (AtkText *text,
                                     gint     offset)
 {
   GtkWidget *widget;
+  GtkTextIter start, end;
+  GtkTextBuffer *buffer;
+  gchar *string;
+  gunichar unichar;
 
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
     /* State is defunct */
     return '\0';
 
-  return '\0';
+  buffer = ev_view_accessible_get_text_buffer (EV_VIEW (widget));
+  if (!buffer)
+    return '\0';
+
+  if (offset >= gtk_text_buffer_get_char_count (buffer))
+    return '\0';
+
+  gtk_text_buffer_get_iter_at_offset (buffer, &start, offset);
+  end = start;
+  gtk_text_iter_forward_char (&end);
+  string = gtk_text_buffer_get_slice (buffer, &start, &end, FALSE);
+  unichar = g_utf8_get_char (string);
+  g_free(string);
+  g_object_unref (buffer);
+
+  return unichar;
 }
 
 static gchar*
@@ -119,13 +175,29 @@ ev_view_accessible_get_text_before_offset (AtkText	    *text,
 				   gint		    *end_offset)
 {
   GtkWidget *widget;
+  gpointer layout = NULL;
+  GailTextUtil *gail_text = NULL;
+  gchar *retval = NULL;
+  GtkTextBuffer *buffer;
 
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
     /* State is defunct */
     return NULL;
 
-  return NULL;
+  buffer = ev_view_accessible_get_text_buffer (EV_VIEW (widget));
+  if (!buffer)
+    return NULL;
+
+  gail_text = gail_text_util_new ();
+  gail_text_util_buffer_setup (gail_text, buffer);
+  retval = gail_text_util_get_text (gail_text, layout,
+                                  GAIL_BEFORE_OFFSET, boundary_type,
+                                  offset, start_offset, end_offset);
+  g_object_unref (gail_text);
+  g_object_unref (buffer);
+
+  return retval;
 }
 
 static gchar*
@@ -136,13 +208,29 @@ ev_view_accessible_get_text_at_offset (AtkText          *text,
                                gint             *end_offset)
 {
   GtkWidget *widget;
+  gpointer layout = NULL;
+  GailTextUtil *gail_text = NULL;
+  gchar *retval = NULL;
+  GtkTextBuffer *buffer;
 
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
     /* State is defunct */
     return NULL;
 
-  return NULL;
+  buffer = ev_view_accessible_get_text_buffer (EV_VIEW (widget));
+  if (!buffer)
+    return NULL;
+
+  gail_text = gail_text_util_new ();
+  gail_text_util_buffer_setup (gail_text, buffer);
+  retval = gail_text_util_get_text (gail_text, layout,
+                                  GAIL_AT_OFFSET, boundary_type,
+                                  offset, start_offset, end_offset);
+  g_object_unref (gail_text);
+  g_object_unref (buffer);
+
+  return retval;
 }
 
 static gchar*
@@ -153,52 +241,100 @@ ev_view_accessible_get_text_after_offset  (AtkText	    *text,
 				   gint		    *end_offset)
 {
   GtkWidget *widget;
+  gpointer layout = NULL;
+  GailTextUtil *gail_text = NULL;
+  gchar *retval = NULL;
+  GtkTextBuffer *buffer;
 
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
     /* State is defunct */
     return NULL;
 
-  return NULL;
+  buffer = ev_view_accessible_get_text_buffer (EV_VIEW (widget));
+  if (!buffer)
+    return NULL;
+
+  gail_text = gail_text_util_new ();
+  gail_text_util_buffer_setup (gail_text, buffer);
+  retval = gail_text_util_get_text (gail_text, layout,
+                                  GAIL_AFTER_OFFSET, boundary_type,
+                                  offset, start_offset, end_offset);
+  g_object_unref (gail_text);
+  g_object_unref (buffer);
+
+  return retval;
 }
 
 static gint
 ev_view_accessible_get_character_count (AtkText *text)
 {
   GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  gint retval;
 
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
     /* State is defunct */
     return 0;
 
-  return 0;
+  buffer = ev_view_accessible_get_text_buffer (EV_VIEW (widget));
+  if (!buffer)
+    return 0;
+
+  retval = gtk_text_buffer_get_char_count (buffer);
+  g_object_unref (buffer);
+
+  return retval;
 }
 
 static gint
 ev_view_accessible_get_caret_offset (AtkText *text)
 {
   GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GtkTextMark *cursor_mark;
+  GtkTextIter cursor_itr;
+  gint retval;
 
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
     /* State is defunct */
     return 0;
- 
-  return 0;
+
+  buffer = ev_view_accessible_get_text_buffer (EV_VIEW (widget));
+  if (!buffer)
+    return 0;
+
+  cursor_mark = gtk_text_buffer_get_insert (buffer);
+  gtk_text_buffer_get_iter_at_mark (buffer, &cursor_itr, cursor_mark);
+  retval = gtk_text_iter_get_offset (&cursor_itr);
+  g_object_unref (buffer);
+
+  return retval;
 }
 
 static gboolean
 ev_view_accessible_set_caret_offset (AtkText *text, gint offset)
 {
   GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GtkTextIter pos_itr;
 
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
     /* State is defunct */
     return FALSE;
 
-  return FALSE;
+  buffer = ev_view_accessible_get_text_buffer (EV_VIEW (widget));
+  if (!buffer)
+    return FALSE;
+
+  gtk_text_buffer_get_iter_at_offset (buffer,  &pos_itr, offset);
+  gtk_text_buffer_place_cursor (buffer, &pos_itr);
+  g_object_unref (buffer);
+
+  return TRUE;
 }
 
 static AtkAttributeSet*
@@ -208,13 +344,23 @@ ev_view_accessible_get_run_attributes (AtkText *text,
                                gint    *end_offset)
 {
   GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  AtkAttributeSet *retval;
 
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
     /* State is defunct */
     return NULL;
- 
-  return NULL;
+
+  buffer = ev_view_accessible_get_text_buffer (EV_VIEW (widget));
+  if (!buffer)
+    return NULL;
+
+  retval = gail_misc_buffer_get_run_attributes (buffer, offset,
+						start_offset, end_offset);
+  g_object_unref (buffer);
+
+  return retval;
 }
 
 static AtkAttributeSet*
@@ -226,56 +372,171 @@ ev_view_accessible_get_default_attributes (AtkText *text)
   if (widget == NULL)
     /* State is defunct */
     return NULL;
-
   return NULL;
 }
-  
+
 static void
 ev_view_accessible_get_character_extents (AtkText *text,
-				  gint    offset,
-		                  gint    *x,
-                    		  gint 	  *y,
-                                  gint 	  *width,
-                                  gint 	  *height,
-			          AtkCoordType coords)
-{
-  GtkWidget *widget;
+                                          gint    offset,
+                                          gint    *x,
+                                          gint    *y,
+                                          gint    *width,
+                                          gint    *height,
+                                          AtkCoordType coords)
+{
+  GtkWidget *widget, *toplevel;
+  EvRectangle *areas = NULL;
+  EvRectangle *rect = NULL;
+  guint n_areas = 0;
+  EvPageCache *page_cache;
+  gint x_widget, y_widget, x_window, y_window;
+  gdouble scale;
+  GtkBorder border;
+  GdkRectangle page_area;
 
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
     /* State is defunct */
     return;
 
-  return;
-} 
+  page_cache = EV_VIEW (widget)->page_cache;
+  if (!page_cache)
+    return;
+
+  ev_view_get_page_extents (EV_VIEW (widget), EV_VIEW (widget)->current_page,
+                            &page_area, &border);
+
+  scale = EV_VIEW (widget)->scale;
+  ev_page_cache_get_text_layout (page_cache, EV_VIEW (widget)->current_page, &areas, &n_areas);
+  if (!areas)
+    return;
+
+  if (offset > n_areas)
+    return;
+
+  rect = areas + offset;
+  *x = (int)(rect->x1 * scale);
+  *y = (int)(rect->y1 * scale);
+
+  *width = (int)(fabs (rect->x2 - rect->x1) * scale);
+  *height = (int)(fabs (rect->y2 - rect->y1) * scale);
+
+  toplevel = gtk_widget_get_toplevel (widget);
+  gtk_widget_translate_coordinates (widget, toplevel, 0, 0, &x_widget, &y_widget);
+  *x += x_widget;
+  *y += y_widget;
+
+  if (coords == ATK_XY_SCREEN)
+  {
+    gdk_window_get_origin (toplevel->window, &x_window, &y_window);
+    *x += x_window;
+    *y += y_window;
+  }
+
+  *x -= EV_VIEW (widget)->scroll_x;
+  *y -= EV_VIEW (widget)->scroll_y;
+
+  *x += page_area.x;
+  *y += page_area.y;
+}
 
-static gint 
+static gint
 ev_view_accessible_get_offset_at_point (AtkText *text,
-                                gint x,
-                                gint y,
-			        AtkCoordType coords)
-{ 
-  GtkWidget *widget;
+                                        gint x,
+                                        gint y,
+                                        AtkCoordType coords)
+{
+  GtkWidget *widget, *toplevel;
+  EvRectangle *areas = NULL;
+  EvRectangle *rect = NULL;
+  guint n_areas = 0;
+  guint i = 0;
+  EvPageCache *page_cache;
+  gint x_window, y_window, x_widget, y_widget;
+  gint offset=-1, rx, ry;
+  gdouble scale;
+  GtkBorder border;
+  GdkRectangle page_area;
 
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
     /* State is defunct */
     return -1;
 
-  return -1;
+  page_cache = EV_VIEW (widget)->page_cache;
+  if (!page_cache)
+    return -1;
+
+  ev_view_get_page_extents (EV_VIEW (widget), EV_VIEW (widget)->current_page,
+			    &page_area, &border);
+
+  scale = EV_VIEW (widget)->scale;
+  ev_page_cache_get_text_layout (page_cache, EV_VIEW (widget)->current_page, &areas, &n_areas);
+  if (!areas)
+    return -1;
+
+  rx = x;
+  ry = y;
+
+  rx -= page_area.x;
+  ry -= page_area.y;
+
+  rx += EV_VIEW (widget)->scroll_x;
+  ry += EV_VIEW (widget)->scroll_y;
+
+  toplevel = gtk_widget_get_toplevel (widget);
+  gtk_widget_translate_coordinates (widget, toplevel, 0, 0, &x_widget, &y_widget);
+  rx -= x_widget;
+  ry -= y_widget;
+
+  if (coords == ATK_XY_SCREEN)
+  {
+    gdk_window_get_origin (toplevel->window, &x_window, &y_window);
+    rx -= x_window;
+    ry -= y_window;
+  }
+
+  rx /= scale;
+  ry /= scale;
+
+  for (i = 0; i < n_areas; i++)
+  {
+    rect = areas + i;
+    if (rx >= rect->x1 && rx <= rect->x2 &&
+        ry >= rect->y1 && ry <= rect->y2)
+        offset = i;
+  }
+
+  return offset;
 }
 
 static gint
-ev_view_accessible_get_n_selections (AtkText              *text)
+ev_view_accessible_get_n_selections (AtkText *text)
 {
   GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GtkTextIter start, end;
+  gint select_start, select_end;
 
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
     /* State is defunct */
     return -1;
-    
-  return -1;
+
+  buffer = ev_view_accessible_get_text_buffer (EV_VIEW (widget));
+  if (!buffer)
+    return -1;
+
+  gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+  select_start = gtk_text_iter_get_offset (&start);
+  select_end = gtk_text_iter_get_offset (&end);
+
+  g_object_unref (buffer);
+
+  if (select_start != select_end)
+     return 1;
+  else
+     return 0;
 }
 
 static gchar*
@@ -285,13 +546,32 @@ ev_view_accessible_get_selection (AtkText *text,
                           gint    *end_pos)
 {
   GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GtkTextIter start, end;
+  gchar *retval = NULL;
 
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
     /* State is defunct */
     return NULL;
 
-  return NULL;
+  if (selection_num != 0)
+     return NULL;
+
+  buffer = ev_view_accessible_get_text_buffer (EV_VIEW (widget));
+  if (!buffer)
+    return NULL;
+
+  gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+  *start_pos = gtk_text_iter_get_offset (&start);
+  *end_pos = gtk_text_iter_get_offset (&end);
+
+  if (*start_pos != *end_pos)
+    retval = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+
+  g_object_unref (buffer);
+
+  return retval;
 }
 
 static gboolean
@@ -300,27 +580,81 @@ ev_view_accessible_add_selection (AtkText *text,
                           gint    end_pos)
 {
   GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GtkTextIter pos_itr;
+  GtkTextIter start, end;
+  gint select_start, select_end;
+  gboolean retval = FALSE;
 
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
     /* State is defunct */
     return FALSE;
 
-  return FALSE;
+  buffer = ev_view_accessible_get_text_buffer (EV_VIEW (widget));
+  if (!buffer)
+    return FALSE;
+
+  gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+  select_start = gtk_text_iter_get_offset (&start);
+  select_end = gtk_text_iter_get_offset (&end);
+
+ /* If there is already a selection, then don't allow
+  * another to be added
+  */
+  if (select_start == select_end) {
+    gtk_text_buffer_get_iter_at_offset (buffer,  &pos_itr, start_pos);
+    gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &pos_itr);
+    gtk_text_buffer_get_iter_at_offset (buffer,  &pos_itr, end_pos);
+    gtk_text_buffer_move_mark_by_name (buffer, "insert", &pos_itr);
+
+    retval = TRUE;
+  }
+
+  g_object_unref (buffer);
+
+  return retval;
 }
 
 static gboolean
 ev_view_accessible_remove_selection (AtkText *text,
-                             gint    selection_num)
+                                     gint     selection_num)
 {
   GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GtkTextMark *cursor_mark;
+  GtkTextIter cursor_itr;
+  GtkTextIter start, end;
+  gint select_start, select_end;
+  gboolean retval = FALSE;
 
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
     /* State is defunct */
     return FALSE;
 
-  return FALSE;
+  buffer = ev_view_accessible_get_text_buffer (EV_VIEW (widget));
+  if (!buffer)
+    return FALSE;
+
+  gtk_text_buffer_get_selection_bounds(buffer, &start, &end);
+  select_start = gtk_text_iter_get_offset(&start);
+  select_end = gtk_text_iter_get_offset(&end);
+
+  if (select_start != select_end) {
+   /* Setting the start & end of the selected region
+    * to the caret position turns off the selection.
+    */
+    cursor_mark = gtk_text_buffer_get_insert (buffer);
+    gtk_text_buffer_get_iter_at_mark (buffer, &cursor_itr, cursor_mark);
+    gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &cursor_itr);
+
+    retval = TRUE;
+  }
+
+  g_object_unref (buffer);
+
+  return retval;
 }
 
 static gboolean
@@ -330,15 +664,38 @@ ev_view_accessible_set_selection (AtkText *text,
                           gint    end_pos)
 {
   GtkWidget *widget;
+  GtkTextBuffer *buffer;
+  GtkTextIter pos_itr;
+  GtkTextIter start, end;
+  gint select_start, select_end;
+  gboolean retval = FALSE;
 
   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (text));
   if (widget == NULL)
     /* State is defunct */
     return FALSE;
 
-  return FALSE;
-}
+  buffer = ev_view_accessible_get_text_buffer (EV_VIEW (widget));
+  if (!buffer)
+    return FALSE;
+
+  gtk_text_buffer_get_selection_bounds(buffer, &start, &end);
+  select_start = gtk_text_iter_get_offset(&start);
+  select_end = gtk_text_iter_get_offset(&end);
+
+  if (select_start != select_end) {
+    gtk_text_buffer_get_iter_at_offset (buffer,  &pos_itr, start_pos);
+    gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &pos_itr);
+    gtk_text_buffer_get_iter_at_offset (buffer,  &pos_itr, end_pos);
+    gtk_text_buffer_move_mark_by_name (buffer, "insert", &pos_itr);
 
+    retval = TRUE;
+  }
+
+  g_object_unref (buffer);
+
+  return retval;
+}
 
 static void ev_view_accessible_text_iface_init (AtkTextIface * iface)
 {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]