/* * GooCanvas. Copyright (C) 2005-6 Damon Chaplin. * Copyright 2001 Sun Microsystems Inc. * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation * Released under the GNU LGPL license. See COPYING for details. * * goocanvasatk.c - the accessibility code. Most of this has been ported from * the gail/libgnomecanvas & foocanvas code. */ #include #include #include #include "goocanvas.h" /* * GooCanvasItemViewAccessible. */ typedef AtkGObjectAccessible GooCanvasItemViewAccessible; typedef AtkGObjectAccessibleClass GooCanvasItemViewAccessibleClass; #define GOO_IS_CANVAS_ITEM_VIEW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), goo_canvas_item_view_accessible_get_type ())) static void goo_canvas_item_view_accessible_component_interface_init (AtkComponentIface *iface); static gint goo_canvas_item_view_accessible_get_index_in_parent (AtkObject *accessible); G_DEFINE_TYPE_WITH_CODE (GooCanvasItemViewAccessible, goo_canvas_item_view_accessible, ATK_TYPE_GOBJECT_ACCESSIBLE, G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, goo_canvas_item_view_accessible_component_interface_init)) /* Returns the extents of the item view, in pixels relative to the main canvas window. */ static void goo_canvas_item_view_accessible_get_item_extents (GooCanvasItemView *view, GdkRectangle *rect) { GooCanvasView *canvas_view; GooCanvasBounds bounds; canvas_view = goo_canvas_item_view_get_canvas_view (view); if (!canvas_view) { rect->x = rect->y = rect->width = rect->height = 0; return; } /* Get the bounds in device units. */ goo_canvas_item_view_get_bounds (view, &bounds); /* Convert to pixels within the entire canvas. */ goo_canvas_view_convert_to_pixels (canvas_view, &bounds.x1, &bounds.y1); goo_canvas_view_convert_to_pixels (canvas_view, &bounds.x2, &bounds.y2); /* Convert to pixels within the visible window. */ bounds.x1 -= canvas_view->hadjustment->value; bounds.y1 -= canvas_view->vadjustment->value; bounds.x2 -= canvas_view->hadjustment->value; bounds.y2 -= canvas_view->vadjustment->value; /* Round up or down to integers. */ rect->x = floor (bounds.x1); rect->y = floor (bounds.y1); rect->width = ceil (bounds.x1) - rect->x; rect->height = ceil (bounds.y1) - rect->y; } /* This returns TRUE if the given rectangle intersects the canvas window. The rectangle should be in pixels relative to the main canvas window. */ static gboolean goo_canvas_item_view_accessible_is_item_in_window (GooCanvasItemView *view, GdkRectangle *rect) { GtkWidget *widget; widget = (GtkWidget*) goo_canvas_item_view_get_canvas_view (view); if (!widget) return FALSE; if (rect->x + rect->width < 0 || rect->x > widget->allocation.width || rect->y + rect->height < 0 || rect->y > widget->allocation.height) return FALSE; return TRUE; } static gboolean goo_canvas_item_view_accessible_is_item_on_screen (GooCanvasItemView *view) { GdkRectangle rect; goo_canvas_item_view_accessible_get_item_extents (view, &rect); return goo_canvas_item_view_accessible_is_item_in_window (view, &rect); } static void goo_canvas_item_view_accessible_get_extents (AtkComponent *component, gint *x, gint *y, gint *width, gint *height, AtkCoordType coord_type) { GooCanvasItemView *item_view; GooCanvasView *canvas_view; GObject *object; gint window_x, window_y; gint toplevel_x, toplevel_y; GdkRectangle rect; GdkWindow *window; g_return_if_fail (GOO_IS_CANVAS_ITEM_VIEW_ACCESSIBLE (component)); *x = *y = G_MININT; object = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (component)); if (!object) return; item_view = GOO_CANVAS_ITEM_VIEW (object); canvas_view = goo_canvas_item_view_get_canvas_view (item_view); if (!canvas_view || !GTK_WIDGET (canvas_view)->window) return; goo_canvas_item_view_accessible_get_item_extents (item_view, &rect); *width = rect.width; *height = rect.height; if (!goo_canvas_item_view_accessible_is_item_in_window (item_view, &rect)) return; gdk_window_get_origin (GTK_WIDGET (canvas_view)->window, &window_x, &window_y); *x = rect.x + window_x; *y = rect.y + window_y; if (coord_type == ATK_XY_WINDOW) { window = gdk_window_get_toplevel (GTK_WIDGET (canvas_view)->window); gdk_window_get_origin (window, &toplevel_x, &toplevel_y); *x -= toplevel_x; *y -= toplevel_y; } } static gint goo_canvas_item_view_accessible_get_mdi_zorder (AtkComponent *component) { g_return_val_if_fail (GOO_IS_CANVAS_ITEM_VIEW_ACCESSIBLE (component), -1); return goo_canvas_item_view_accessible_get_index_in_parent (ATK_OBJECT (component)); } static guint goo_canvas_item_view_accessible_add_focus_handler (AtkComponent *component, AtkFocusHandler handler) { GSignalMatchType match_type; GClosure *closure; guint signal_id; g_return_val_if_fail (GOO_IS_CANVAS_ITEM_VIEW_ACCESSIBLE (component), 0); match_type = G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC; signal_id = g_signal_lookup ("focus-event", ATK_TYPE_OBJECT); /* If the handler has already been added just return. */ if (g_signal_handler_find (component, match_type, signal_id, 0, NULL, (gpointer) handler, NULL)) return 0; closure = g_cclosure_new (G_CALLBACK (handler), NULL, (GClosureNotify) NULL); return g_signal_connect_closure_by_id (component, signal_id, 0, closure, FALSE); } static void goo_canvas_item_view_accessible_remove_focus_handler (AtkComponent *component, guint handler_id) { g_return_if_fail (GOO_IS_CANVAS_ITEM_VIEW_ACCESSIBLE (component)); g_signal_handler_disconnect (ATK_OBJECT (component), handler_id); } static gboolean goo_canvas_item_view_accessible_grab_focus (AtkComponent *component) { GooCanvasItemView *item_view; GooCanvasView *canvas_view; GtkWidget *toplevel; GObject *object; g_return_val_if_fail (GOO_IS_CANVAS_ITEM_VIEW_ACCESSIBLE (component), FALSE); object = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (component)); if (!object) return FALSE; item_view = GOO_CANVAS_ITEM_VIEW (object); canvas_view = goo_canvas_item_view_get_canvas_view (item_view); if (!canvas_view) return FALSE; goo_canvas_view_grab_focus (canvas_view, item_view); toplevel = gtk_widget_get_toplevel (GTK_WIDGET (canvas_view)); if (GTK_WIDGET_TOPLEVEL (toplevel)) gtk_window_present (GTK_WINDOW (toplevel)); return TRUE; } static void goo_canvas_item_view_accessible_component_interface_init (AtkComponentIface *iface) { iface->get_extents = goo_canvas_item_view_accessible_get_extents; iface->get_mdi_zorder = goo_canvas_item_view_accessible_get_mdi_zorder; iface->add_focus_handler = goo_canvas_item_view_accessible_add_focus_handler; iface->remove_focus_handler = goo_canvas_item_view_accessible_remove_focus_handler; iface->grab_focus = goo_canvas_item_view_accessible_grab_focus; } static void goo_canvas_item_view_accessible_initialize (AtkObject *object, gpointer data) { if (ATK_OBJECT_CLASS (goo_canvas_item_view_accessible_parent_class)->initialize) ATK_OBJECT_CLASS (goo_canvas_item_view_accessible_parent_class)->initialize (object, data); /* FIXME: Maybe this should be ATK_LAYER_CANVAS. */ g_object_set_data (G_OBJECT (object), "atk-component-layer", GINT_TO_POINTER (ATK_LAYER_MDI)); } static AtkObject* goo_canvas_item_view_accessible_get_parent (AtkObject *accessible) { GooCanvasItemView *item_view, *parent_view; GooCanvasView *canvas_view; GObject *object; g_return_val_if_fail (GOO_IS_CANVAS_ITEM_VIEW_ACCESSIBLE (accessible), NULL); if (accessible->accessible_parent) return accessible->accessible_parent; object = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)); if (object == NULL) return NULL; item_view = GOO_CANVAS_ITEM_VIEW (object); parent_view = goo_canvas_item_view_get_parent_view (item_view); if (parent_view) return atk_gobject_accessible_for_object (G_OBJECT (parent_view)); canvas_view = goo_canvas_item_view_get_canvas_view (item_view); if (canvas_view) return gtk_widget_get_accessible (GTK_WIDGET (canvas_view)); return NULL; } static gint goo_canvas_item_view_accessible_get_index_in_parent (AtkObject *accessible) { GooCanvasItemView *item_view, *parent_view; GooCanvasView *canvas_view; GObject *object; g_return_val_if_fail (GOO_IS_CANVAS_ITEM_VIEW_ACCESSIBLE (accessible), -1); if (accessible->accessible_parent) { gint n_children, i; gboolean found = FALSE; n_children = atk_object_get_n_accessible_children (accessible->accessible_parent); for (i = 0; i < n_children; i++) { AtkObject *child; child = atk_object_ref_accessible_child (accessible->accessible_parent, i); if (child == accessible) found = TRUE; g_object_unref (child); if (found) return i; } return -1; } object = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)); if (object == NULL) return -1; item_view = GOO_CANVAS_ITEM_VIEW (object); parent_view = goo_canvas_item_view_get_parent_view (item_view); if (parent_view) return goo_canvas_item_view_find_child (parent_view, item_view); canvas_view = goo_canvas_item_view_get_canvas_view (item_view); if (canvas_view) return 0; return -1; } static gint goo_canvas_item_view_accessible_get_n_children (AtkObject *accessible) { GooCanvasItemView *item_view; GObject *object; g_return_val_if_fail (GOO_IS_CANVAS_ITEM_VIEW_ACCESSIBLE (accessible), -1); object = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)); if (object == NULL) return -1; item_view = GOO_CANVAS_ITEM_VIEW (object); return goo_canvas_item_view_get_n_children (item_view); } static AtkObject* goo_canvas_item_view_accessible_ref_child (AtkObject *accessible, gint child_num) { GooCanvasItemView *item_view, *child_view; AtkObject *atk_object; GObject *object; g_return_val_if_fail (GOO_IS_CANVAS_ITEM_VIEW_ACCESSIBLE (accessible), NULL); object = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)); if (object == NULL) return NULL; item_view = GOO_CANVAS_ITEM_VIEW (object); child_view = goo_canvas_item_view_get_child (item_view, child_num); if (!child_view) return NULL; atk_object = atk_gobject_accessible_for_object (G_OBJECT (child_view)); g_object_ref (atk_object); return atk_object; } static AtkStateSet* goo_canvas_item_view_accessible_ref_state_set (AtkObject *accessible) { GooCanvasItemView *item_view; GooCanvasView *canvas_view; AtkStateSet *state_set; GObject *object; gboolean can_focus = FALSE; g_return_val_if_fail (GOO_IS_CANVAS_ITEM_VIEW_ACCESSIBLE (accessible), NULL); state_set = ATK_OBJECT_CLASS (goo_canvas_item_view_accessible_parent_class)->ref_state_set (accessible); object = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)); if (!object) { atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT); return state_set; } item_view = GOO_CANVAS_ITEM_VIEW (object); canvas_view = goo_canvas_item_view_get_canvas_view (item_view); if (!canvas_view) return state_set; if (goo_canvas_item_view_is_visible (item_view)) { atk_state_set_add_state (state_set, ATK_STATE_VISIBLE); if (goo_canvas_item_view_accessible_is_item_on_screen (item_view)) atk_state_set_add_state (state_set, ATK_STATE_SHOWING); } g_object_get (item_view, "can-focus", &can_focus, NULL); if (GTK_WIDGET_CAN_FOCUS (GTK_WIDGET (canvas_view)) && can_focus) { atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE); if (GTK_WIDGET_HAS_FOCUS (canvas_view) && canvas_view->focused_item_view == item_view) atk_state_set_add_state (state_set, ATK_STATE_FOCUSED); } return state_set; } static void goo_canvas_item_view_accessible_class_init (GooCanvasItemViewAccessibleClass *klass) { AtkObjectClass *aklass = (AtkObjectClass*) klass; aklass->initialize = goo_canvas_item_view_accessible_initialize; aklass->get_parent = goo_canvas_item_view_accessible_get_parent; aklass->get_index_in_parent = goo_canvas_item_view_accessible_get_index_in_parent; aklass->get_n_children = goo_canvas_item_view_accessible_get_n_children; aklass->ref_child = goo_canvas_item_view_accessible_ref_child; aklass->ref_state_set = goo_canvas_item_view_accessible_ref_state_set; } static void goo_canvas_item_view_accessible_init (GooCanvasItemViewAccessible *accessible) { } static AtkObject * goo_canvas_item_view_accessible_new (GObject *object) { AtkObject *accessible; g_return_val_if_fail (GOO_IS_CANVAS_ITEM_VIEW (object), NULL); accessible = g_object_new (goo_canvas_item_view_accessible_get_type (), NULL); atk_object_initialize (accessible, object); return accessible; } /* * GooCanvasItemViewAccessibleFactory. */ typedef AtkObjectFactory GooCanvasItemViewAccessibleFactory; typedef AtkObjectFactoryClass GooCanvasItemViewAccessibleFactoryClass; G_DEFINE_TYPE (GooCanvasItemViewAccessibleFactory, goo_canvas_item_view_accessible_factory, ATK_TYPE_OBJECT_FACTORY) static void goo_canvas_item_view_accessible_factory_class_init (GooCanvasItemViewAccessibleFactoryClass *klass) { klass->create_accessible = goo_canvas_item_view_accessible_new; klass->get_accessible_type = goo_canvas_item_view_accessible_get_type; } static void goo_canvas_item_view_accessible_factory_init (GooCanvasItemViewAccessibleFactory *factory) { } /* * GooCanvasViewAccessible. */ static gpointer accessible_parent_class = NULL; static void goo_canvas_view_accessible_initialize (AtkObject *object, gpointer data) { if (ATK_OBJECT_CLASS (accessible_parent_class)->initialize) ATK_OBJECT_CLASS (accessible_parent_class)->initialize (object, data); /* FIXME: Maybe this should be ATK_ROLE_CANVAS. */ object->role = ATK_ROLE_LAYERED_PANE; } static gint goo_canvas_view_accessible_get_n_children (AtkObject *object) { GtkAccessible *accessible; GtkWidget *widget; GooCanvasView *canvas_view; GooCanvasModel *model; GooCanvasItem *root; accessible = GTK_ACCESSIBLE (object); widget = accessible->widget; /* Check if widget still exists. */ if (widget == NULL) return 0; g_return_val_if_fail (GOO_IS_CANVAS_VIEW (widget), 0); canvas_view = GOO_CANVAS_VIEW (widget); model = goo_canvas_view_get_model (canvas_view); if (!model) return 0; root = goo_canvas_model_get_root_item (model); if (!root) return 0; return 1; } static AtkObject* goo_canvas_view_accessible_ref_child (AtkObject *object, gint child_num) { GtkAccessible *accessible; GtkWidget *widget; GooCanvasView *canvas_view; GooCanvasModel *model; GooCanvasItem *root; AtkObject *atk_object; /* Canvas only has one child, so return NULL if index is non zero */ if (child_num != 0) return NULL; accessible = GTK_ACCESSIBLE (object); widget = accessible->widget; /* Check if widget still exists. */ if (widget == NULL) return NULL; canvas_view = GOO_CANVAS_VIEW (widget); model = goo_canvas_view_get_model (canvas_view); if (!model) return NULL; root = goo_canvas_model_get_root_item (model); if (!root) return NULL; atk_object = atk_gobject_accessible_for_object (G_OBJECT (root)); g_object_ref (atk_object); return atk_object; } static void goo_canvas_view_accessible_class_init (AtkObjectClass *klass) { accessible_parent_class = g_type_class_peek_parent (klass); klass->initialize = goo_canvas_view_accessible_initialize; klass->get_n_children = goo_canvas_view_accessible_get_n_children; klass->ref_child = goo_canvas_view_accessible_ref_child; } static GType goo_canvas_view_accessible_get_type (void) { static GType g_define_type_id = 0; if (G_UNLIKELY (g_define_type_id == 0)) { AtkObjectFactory *factory; GType parent_atk_type; GTypeQuery query; GTypeInfo tinfo = { 0 }; /* Gail doesn't declare its classes publicly, so we have to do a query to find the size of the class and instances. */ factory = atk_registry_get_factory (atk_get_default_registry (), GTK_TYPE_WIDGET); if (!factory) return G_TYPE_INVALID; parent_atk_type = atk_object_factory_get_accessible_type (factory); if (!parent_atk_type) return G_TYPE_INVALID; g_type_query (parent_atk_type, &query); tinfo.class_init = (GClassInitFunc) goo_canvas_view_accessible_class_init; tinfo.class_size = query.class_size; tinfo.instance_size = query.instance_size; g_define_type_id = g_type_register_static (parent_atk_type, "GooCanvasViewAccessible", &tinfo, 0); } return g_define_type_id; } static AtkObject * goo_canvas_view_accessible_new (GObject *object) { AtkObject *accessible; g_return_val_if_fail (GOO_IS_CANVAS_VIEW (object), NULL); accessible = g_object_new (goo_canvas_view_accessible_get_type (), NULL); atk_object_initialize (accessible, object); return accessible; } /* * GooCanvasViewAccessibleFactory. */ typedef AtkObjectFactory GooCanvasViewAccessibleFactory; typedef AtkObjectFactoryClass GooCanvasViewAccessibleFactoryClass; G_DEFINE_TYPE (GooCanvasViewAccessibleFactory, goo_canvas_view_accessible_factory, ATK_TYPE_OBJECT_FACTORY) static void goo_canvas_view_accessible_factory_class_init (GooCanvasViewAccessibleFactoryClass *klass) { klass->create_accessible = goo_canvas_view_accessible_new; klass->get_accessible_type = goo_canvas_view_accessible_get_type; } static void goo_canvas_view_accessible_factory_init (GooCanvasViewAccessibleFactory *factory) { }