/* 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. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "gailcanvasitem.h" #include 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, GdkRectangle *extents); static gboolean is_item_in_window (GnomeCanvasItem *item, const GdkRectangle *extents); 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 (gail_canvas_item_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); 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 (gail_canvas_item_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->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; GdkRectangle extents; 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, &extents); *width = extents.width; *height = extents.height; if (!is_item_in_window (item, &extents)) { *x = G_MININT; *y = G_MININT; return; } gail_misc_get_origins (GTK_WIDGET (item->canvas), &window_x, &window_y, &toplevel_x, &toplevel_y); *x = extents.x + window_x - toplevel_x; *y = extents.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) { GdkRectangle extents; get_item_extents (item, &extents); return is_item_in_window (item, &extents); } static void get_item_extents (GnomeCanvasItem *item, GdkRectangle *extents) { double x1, x2, y1, y2; cairo_matrix_t i2c; x1 = y1 = x2 = y2 = 0.0; if (GNOME_CANVAS_ITEM_CLASS (G_OBJECT_GET_CLASS (item))->bounds) GNOME_CANVAS_ITEM_CLASS (G_OBJECT_GET_CLASS (item))->bounds ( item, &x1, &y1, &x2, &y2); /* Get the item coordinates -> canvas pixel coordinates affine */ gnome_canvas_item_i2c_matrix (item, &i2c); gnome_canvas_matrix_transform_rect (&i2c, &x1, &y1, &x2, &y2); extents->x = floor (x1); extents->y = floor (y1); extents->width = ceil (x2) - extents->x; extents->height = ceil (y2) - extents->y; } static gboolean is_item_in_window (GnomeCanvasItem *item, const GdkRectangle *extents) { GtkWidget *widget; GdkWindow *window; gboolean retval; widget = GTK_WIDGET (item->canvas); window = gtk_widget_get_window (widget); if (window) { GdkRectangle window_rect; window_rect.x = 0; window_rect.y = 0; window_rect.width = gdk_window_get_width (window); window_rect.height = gdk_window_get_height (window); retval = gdk_rectangle_intersect (extents, &window_rect, NULL); } else { retval = FALSE; } return retval; }