aboutsummaryrefslogtreecommitdiffstats
path: root/libgnomecanvas/gailcanvasitem.c
diff options
context:
space:
mode:
Diffstat (limited to 'libgnomecanvas/gailcanvasitem.c')
-rw-r--r--libgnomecanvas/gailcanvasitem.c514
1 files changed, 514 insertions, 0 deletions
diff --git a/libgnomecanvas/gailcanvasitem.c b/libgnomecanvas/gailcanvasitem.c
new file mode 100644
index 0000000000..f059e1909c
--- /dev/null
+++ b/libgnomecanvas/gailcanvasitem.c
@@ -0,0 +1,514 @@
+/* GAIL - The GNOME Accessibility Implementation Library
+ * Copyright 2001 Sun Microsystems Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <math.h>
+#include <gtk/gtk.h>
+#include <libgnomecanvas/gnome-canvas.h>
+#include <libgnomecanvas/gnome-canvas-util.h>
+#include "gailcanvasitem.h"
+#include <libgail-util/gailmisc.h>
+
+static void gail_canvas_item_initialize (AtkObject *obj,
+ gpointer data);
+static AtkObject* gail_canvas_item_get_parent (AtkObject *obj);
+static gint gail_canvas_item_get_index_in_parent (AtkObject *obj);
+static AtkStateSet* gail_canvas_item_ref_state_set (AtkObject *obj);
+
+static void gail_canvas_item_component_interface_init (AtkComponentIface *iface);
+static guint gail_canvas_item_add_focus_handler (AtkComponent *component,
+ AtkFocusHandler handler);
+static void gail_canvas_item_get_extents (AtkComponent *component,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height,
+ AtkCoordType coord_type);
+static gint gail_canvas_item_get_mdi_zorder (AtkComponent *component);
+static gboolean gail_canvas_item_grab_focus (AtkComponent *component);
+static void gail_canvas_item_remove_focus_handler (AtkComponent *component,
+ guint handler_id);
+static gboolean is_item_on_screen (GnomeCanvasItem *item);
+static void get_item_extents (GnomeCanvasItem *item,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height);
+static gboolean is_item_in_window (GnomeCanvasItem *item,
+ gint x,
+ gint y,
+ gint width,
+ gint height);
+
+static AtkGObjectAccessibleClass *parent_class = NULL;
+
+G_DEFINE_TYPE_WITH_CODE (GailCanvasItem,
+ gail_canvas_item,
+ ATK_TYPE_GOBJECT_ACCESSIBLE,
+ G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT,
+ gail_canvas_item_component_interface_init));
+
+static void
+gail_canvas_item_init (GailCanvasItem *foo)
+{
+ ;
+}
+
+AtkObject*
+gail_canvas_item_new (GObject *obj)
+{
+ gpointer object;
+ AtkObject *atk_object;
+
+ g_return_val_if_fail (GNOME_IS_CANVAS_ITEM (obj), NULL);
+ object = g_object_new (GAIL_TYPE_CANVAS_ITEM, NULL);
+ atk_object = ATK_OBJECT (object);
+ atk_object_initialize (atk_object, obj);
+ atk_object->role = ATK_ROLE_UNKNOWN;
+ return atk_object;
+}
+
+static void
+gail_canvas_item_initialize (AtkObject *obj,
+ gpointer data)
+{
+ ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
+
+ g_object_set_data (G_OBJECT (obj), "atk-component-layer",
+ GINT_TO_POINTER (ATK_LAYER_MDI));
+}
+
+static void
+gail_canvas_item_class_init (GailCanvasItemClass *klass)
+{
+ AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ class->get_parent = gail_canvas_item_get_parent;
+ class->get_index_in_parent = gail_canvas_item_get_index_in_parent;
+ class->ref_state_set = gail_canvas_item_ref_state_set;
+ class->initialize = gail_canvas_item_initialize;
+}
+
+static AtkObject *
+gail_canvas_item_get_parent (AtkObject *obj)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ GnomeCanvasItem *item;
+
+ g_return_val_if_fail (GAIL_IS_CANVAS_ITEM (obj), NULL);
+ if (obj->accessible_parent)
+ return obj->accessible_parent;
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (obj);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (g_obj == NULL)
+ /* Object is defunct */
+ return NULL;
+
+ item = GNOME_CANVAS_ITEM (g_obj);
+ if (item->parent)
+ return atk_gobject_accessible_for_object (G_OBJECT (item->parent));
+ else
+ return gtk_widget_get_accessible (GTK_WIDGET (item->canvas));
+}
+
+static gint
+gail_canvas_item_get_index_in_parent (AtkObject *obj)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ GnomeCanvasItem *item;
+
+ g_return_val_if_fail (GAIL_IS_CANVAS_ITEM (obj), -1);
+ if (obj->accessible_parent)
+ {
+ gint n_children, i;
+ gboolean found = FALSE;
+
+ n_children = atk_object_get_n_accessible_children (obj->accessible_parent);
+ for (i = 0; i < n_children; i++)
+ {
+ AtkObject *child;
+
+ child = atk_object_ref_accessible_child (obj->accessible_parent, i);
+ if (child == obj)
+ found = TRUE;
+
+ g_object_unref (child);
+ if (found)
+ return i;
+ }
+ return -1;
+ }
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (obj);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (g_obj == NULL)
+ /* Object is defunct */
+ return -1;
+
+ item = GNOME_CANVAS_ITEM (g_obj);
+ if (item->parent)
+ {
+ return g_list_index (GNOME_CANVAS_GROUP (item->parent)->item_list, item);
+ }
+ else
+ {
+ g_return_val_if_fail (item->canvas->root == item, -1);
+ return 0;
+ }
+}
+
+static AtkStateSet*
+gail_canvas_item_ref_state_set (AtkObject *obj)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ GnomeCanvasItem *item;
+ AtkStateSet *state_set;
+
+ g_return_val_if_fail (GAIL_IS_CANVAS_ITEM (obj), NULL);
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (obj);
+
+ state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (obj);
+
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (g_obj == NULL)
+ {
+ /* Object is defunct */
+ atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT);
+ }
+ else
+ {
+ item = GNOME_CANVAS_ITEM (g_obj);
+
+ if (item->object.flags & GNOME_CANVAS_ITEM_VISIBLE)
+ {
+ atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
+ if (is_item_on_screen (item))
+ {
+ atk_state_set_add_state (state_set, ATK_STATE_SHOWING);
+ }
+ }
+ if (gtk_widget_get_can_focus (GTK_WIDGET (item->canvas)))
+ {
+ atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE);
+
+ if (item->canvas->focused_item == item)
+ {
+ atk_state_set_add_state (state_set, ATK_STATE_FOCUSED);
+ }
+ }
+ }
+
+ return state_set;
+}
+
+static void
+gail_canvas_item_component_interface_init (AtkComponentIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->add_focus_handler = gail_canvas_item_add_focus_handler;
+ iface->get_extents = gail_canvas_item_get_extents;
+ iface->get_mdi_zorder = gail_canvas_item_get_mdi_zorder;
+ iface->grab_focus = gail_canvas_item_grab_focus;
+ iface->remove_focus_handler = gail_canvas_item_remove_focus_handler;
+}
+
+static guint
+gail_canvas_item_add_focus_handler (AtkComponent *component,
+ AtkFocusHandler handler)
+{
+ GSignalMatchType match_type;
+ gulong ret;
+ guint signal_id;
+
+ match_type = G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC;
+ signal_id = g_signal_lookup ("focus-event", ATK_TYPE_OBJECT);
+
+ ret = g_signal_handler_find (component, match_type, signal_id, 0, NULL,
+ (gpointer) handler, NULL);
+ if (!ret)
+ {
+ return g_signal_connect_closure_by_id (component,
+ signal_id, 0,
+ g_cclosure_new (
+ G_CALLBACK (handler), NULL,
+ (GClosureNotify) NULL),
+ FALSE);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+static void
+gail_canvas_item_get_extents (AtkComponent *component,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height,
+ AtkCoordType coord_type)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *obj;
+ GnomeCanvasItem *item;
+ gint window_x, window_y;
+ gint toplevel_x, toplevel_y;
+ gint local_x, local_y;
+
+ g_return_if_fail (GAIL_IS_CANVAS_ITEM (component));
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (component);
+ obj = atk_gobject_accessible_get_object (atk_gobj);
+
+ if (obj == NULL)
+ /* item is defunct */
+ return;
+
+ /* Get the GnomeCanvasItem */
+ item = GNOME_CANVAS_ITEM (obj);
+
+ /* If this item has no parent canvas, something's broken */
+ g_return_if_fail (GTK_IS_WIDGET (item->canvas));
+
+ get_item_extents (item, &local_x, &local_y, width, height);
+ if (!is_item_in_window (item, local_x, local_y, *width, *height))
+ {
+ *x = G_MININT;
+ *y = G_MININT;
+ return;
+ }
+
+ gail_misc_get_origins (GTK_WIDGET (item->canvas), &window_x, &window_y,
+ &toplevel_x, &toplevel_y);
+ *x = local_x + window_x - toplevel_x;
+ *y = local_y + window_y - toplevel_y;
+
+ /* If screen coordinates are requested, modify x and y appropriately */
+ if (coord_type == ATK_XY_SCREEN)
+ {
+ *x += toplevel_x;
+ *y += toplevel_y;
+ }
+ return;
+}
+
+static gint
+gail_canvas_item_get_mdi_zorder (AtkComponent *component)
+{
+ g_return_val_if_fail (ATK_OBJECT (component), -1);
+
+ return gail_canvas_item_get_index_in_parent (ATK_OBJECT (component));
+}
+
+static gboolean
+gail_canvas_item_grab_focus (AtkComponent *component)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *obj;
+ GnomeCanvasItem *item;
+ GtkWidget *toplevel;
+
+ g_return_val_if_fail (GAIL_IS_CANVAS_ITEM (component), FALSE);
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (component);
+ obj = atk_gobject_accessible_get_object (atk_gobj);
+
+ /* Get the GnomeCanvasItem */
+ item = GNOME_CANVAS_ITEM (obj);
+ if (item == NULL)
+ /* item is defunct */
+ return FALSE;
+
+ gnome_canvas_item_grab_focus (item);
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item->canvas));
+ if (gtk_widget_is_toplevel (toplevel))
+ gtk_window_present (GTK_WINDOW (toplevel));
+
+ return TRUE;
+}
+
+static void
+gail_canvas_item_remove_focus_handler (AtkComponent *component,
+ guint handler_id)
+{
+ g_signal_handler_disconnect (ATK_OBJECT (component), handler_id);
+}
+
+static gboolean
+is_item_on_screen (GnomeCanvasItem *item)
+{
+ gint x, y, width, height;
+
+ get_item_extents (item, &x, &y, &width, &height);
+ return is_item_in_window (item, x, y, width, height);
+}
+
+static void
+get_item_extents (GnomeCanvasItem *item,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height)
+{
+ double bx1, by1, bx2, by2;
+ double i2c[6];
+ ArtPoint p1, p2, p3, p4;
+ ArtPoint q1, q2, q3, q4;
+ double min_x1, min_y1, min_x2, min_y2;
+ double max_x1, max_y1, max_x2, max_y2;
+ int x1, y1, x2, y2;
+ int scroll_x, scroll_y;
+
+ /* Get the bounding box in item-relative coordinates */
+
+ bx1 = by1 = bx2 = by2 = 0.0;
+
+ if (GNOME_CANVAS_ITEM_CLASS (G_OBJECT_GET_CLASS (item))->bounds)
+ (* GNOME_CANVAS_ITEM_CLASS (G_OBJECT_GET_CLASS (item))->bounds) (item, &bx1, &by1, &bx2, &by2);
+
+ /* Get the item coordinates -> canvas pixel coordinates affine */
+
+ gnome_canvas_item_i2c_affine (item, i2c);
+
+ /* Convert the bounding box to canvas pixel coordinates and find its minimum
+ * surrounding rectangle.
+ */
+
+ p1.x = p2.x = bx1;
+ p1.y = p4.y = by1;
+ p3.x = p4.x = bx2;
+ p2.y = p3.y = by2;
+
+ art_affine_point (&q1, &p1, i2c);
+ art_affine_point (&q2, &p2, i2c);
+ art_affine_point (&q3, &p3, i2c);
+ art_affine_point (&q4, &p4, i2c);
+
+ if (q1.x < q2.x)
+ {
+ min_x1 = q1.x;
+ max_x1 = q2.x;
+ }
+ else
+ {
+ min_x1 = q2.x;
+ max_x1 = q1.x;
+ }
+
+ if (q1.y < q2.y)
+ {
+ min_y1 = q1.y;
+ max_y1 = q2.y;
+ }
+ else
+ {
+ min_y1 = q2.y;
+ max_y1 = q1.y;
+ }
+
+ if (q3.x < q4.x)
+ {
+ min_x2 = q3.x;
+ max_x2 = q4.x;
+ }
+ else
+ {
+ min_x2 = q4.x;
+ max_x2 = q3.x;
+ }
+
+ if (q3.y < q4.y)
+ {
+ min_y2 = q3.y;
+ max_y2 = q4.y;
+ }
+ else
+ {
+ min_y2 = q4.y;
+ max_y2 = q3.y;
+ }
+
+ bx1 = MIN (min_x1, min_x2);
+ by1 = MIN (min_y1, min_y2);
+ bx2 = MAX (max_x1, max_x2);
+ by2 = MAX (max_y1, max_y2);
+
+ /* Convert to integer coordinates */
+
+ x1 = floor (bx1);
+ y1 = floor (by1);
+ x2 = ceil (bx2);
+ y2 = ceil (by2);
+
+ gnome_canvas_get_scroll_offsets (item->canvas, &scroll_x, &scroll_y);
+
+ if (x)
+ *x = x1 - scroll_x;
+
+ if (y)
+ *y = y1 - scroll_y;
+
+ if (width)
+ *width = x2 - x1;
+
+ if (height)
+ *height = y2 - y1;
+}
+
+static gboolean
+is_item_in_window (GnomeCanvasItem *item,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ GtkWidget *widget;
+ gboolean retval;
+
+ widget = GTK_WIDGET (item->canvas);
+ if (widget->window)
+ {
+ int window_width, window_height;
+
+ gdk_window_get_geometry (widget->window, NULL, NULL,
+ &window_width, &window_height, NULL);
+ /*
+ * Check whether rectangles intersect
+ */
+ if (x + width <= 0 ||
+ y + height <= 0 ||
+ x > window_width ||
+ y > window_height)
+ {
+ retval = FALSE;
+ }
+ else
+ {
+ retval = TRUE;
+ }
+ }
+ else
+ {
+ retval = FALSE;
+ }
+ return retval;
+}