evolution-3.6.4/libgnomecanvas/gailcanvasitem.c

No issues found

  1 /* GAIL - The GNOME Accessibility Implementation Library
  2  * Copyright 2001 Sun Microsystems Inc.
  3  *
  4  * This library is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU Lesser General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2 of the License, or (at your option) any later version.
  8  *
  9  * This library is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12  * Lesser General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU Lesser General Public
 15  * License along with this library; if not, write to the
 16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 17  * Boston, MA 02111-1307, USA.
 18  */
 19 
 20 #ifdef HAVE_CONFIG_H
 21 #include <config.h>
 22 #endif
 23 
 24 #include <math.h>
 25 #include <gtk/gtk.h>
 26 #include <libgnomecanvas/gnome-canvas.h>
 27 #include <libgnomecanvas/gnome-canvas-util.h>
 28 #include "gailcanvasitem.h"
 29 #include <libgail-util/gailmisc.h>
 30 
 31 static void       gail_canvas_item_initialize               (AtkObject         *obj,
 32 							     gpointer          data);
 33 static AtkObject * gail_canvas_item_get_parent               (AtkObject         *obj);
 34 static gint       gail_canvas_item_get_index_in_parent      (AtkObject         *obj);
 35 static AtkStateSet * gail_canvas_item_ref_state_set          (AtkObject         *obj);
 36 
 37 static void       gail_canvas_item_component_interface_init (AtkComponentIface *iface);
 38 static guint      gail_canvas_item_add_focus_handler        (AtkComponent *component,
 39 							     AtkFocusHandler   handler);
 40 static void       gail_canvas_item_get_extents              (AtkComponent *component,
 41 							     gint              *x,
 42 							     gint              *y,
 43 							     gint              *width,
 44 							     gint              *height,
 45 							     AtkCoordType      coord_type);
 46 static gint       gail_canvas_item_get_mdi_zorder           (AtkComponent *component);
 47 static gboolean   gail_canvas_item_grab_focus               (AtkComponent *component);
 48 static void       gail_canvas_item_remove_focus_handler     (AtkComponent *component,
 49 							     guint             handler_id);
 50 static gboolean   is_item_on_screen                         (GnomeCanvasItem   *item);
 51 static void       get_item_extents                          (GnomeCanvasItem   *item,
 52 							     GdkRectangle      *extents);
 53 static gboolean   is_item_in_window                         (GnomeCanvasItem   *item,
 54 							     const GdkRectangle *extents);
 55 
 56 G_DEFINE_TYPE_WITH_CODE (GailCanvasItem,
 57 			 gail_canvas_item,
 58 			 ATK_TYPE_GOBJECT_ACCESSIBLE,
 59 			 G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT,
 60 						gail_canvas_item_component_interface_init));
 61 
 62 static void
 63 gail_canvas_item_init (GailCanvasItem *foo)
 64 {
 65   ;
 66 }
 67 
 68 AtkObject *
 69 gail_canvas_item_new (GObject *obj)
 70 {
 71   gpointer object;
 72   AtkObject *atk_object;
 73 
 74   g_return_val_if_fail (GNOME_IS_CANVAS_ITEM (obj), NULL);
 75   object = g_object_new (GAIL_TYPE_CANVAS_ITEM, NULL);
 76   atk_object = ATK_OBJECT (object);
 77   atk_object_initialize (atk_object, obj);
 78   atk_object->role = ATK_ROLE_UNKNOWN;
 79   return atk_object;
 80 }
 81 
 82 static void
 83 gail_canvas_item_initialize (AtkObject *obj,
 84                              gpointer data)
 85 {
 86   ATK_OBJECT_CLASS (gail_canvas_item_parent_class)->initialize (obj, data);
 87 
 88   g_object_set_data (G_OBJECT (obj), "atk-component-layer",
 89 		     GINT_TO_POINTER (ATK_LAYER_MDI));
 90 }
 91 
 92 static void
 93 gail_canvas_item_class_init (GailCanvasItemClass *klass)
 94 {
 95   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
 96 
 97   class->get_parent = gail_canvas_item_get_parent;
 98   class->get_index_in_parent = gail_canvas_item_get_index_in_parent;
 99   class->ref_state_set = gail_canvas_item_ref_state_set;
100   class->initialize = gail_canvas_item_initialize;
101 }
102 
103 static AtkObject *
104 gail_canvas_item_get_parent (AtkObject *obj)
105 {
106   AtkGObjectAccessible *atk_gobj;
107   GObject *g_obj;
108   GnomeCanvasItem *item;
109 
110   g_return_val_if_fail (GAIL_IS_CANVAS_ITEM (obj), NULL);
111   if (obj->accessible_parent)
112     return obj->accessible_parent;
113   atk_gobj = ATK_GOBJECT_ACCESSIBLE (obj);
114   g_obj = atk_gobject_accessible_get_object (atk_gobj);
115   if (g_obj == NULL)
116     /* Object is defunct */
117     return NULL;
118 
119   item = GNOME_CANVAS_ITEM (g_obj);
120   if (item->parent)
121     return atk_gobject_accessible_for_object (G_OBJECT (item->parent));
122   else
123     return gtk_widget_get_accessible (GTK_WIDGET (item->canvas));
124 }
125 
126 static gint
127 gail_canvas_item_get_index_in_parent (AtkObject *obj)
128 {
129   AtkGObjectAccessible *atk_gobj;
130   GObject *g_obj;
131   GnomeCanvasItem *item;
132 
133   g_return_val_if_fail (GAIL_IS_CANVAS_ITEM (obj), -1);
134   if (obj->accessible_parent)
135     {
136       gint n_children, i;
137       gboolean found = FALSE;
138 
139       n_children = atk_object_get_n_accessible_children (obj->accessible_parent);
140       for (i = 0; i < n_children; i++)
141 	{
142 	  AtkObject *child;
143 
144 	  child = atk_object_ref_accessible_child (obj->accessible_parent, i);
145 	  if (child == obj)
146 	    found = TRUE;
147 
148 	  g_object_unref (child);
149 	  if (found)
150 	    return i;
151 	}
152       return -1;
153     }
154 
155   atk_gobj = ATK_GOBJECT_ACCESSIBLE (obj);
156   g_obj = atk_gobject_accessible_get_object (atk_gobj);
157   if (g_obj == NULL)
158     /* Object is defunct */
159     return -1;
160 
161   item = GNOME_CANVAS_ITEM (g_obj);
162   if (item->parent)
163     {
164       return g_list_index (GNOME_CANVAS_GROUP (item->parent)->item_list, item);
165     }
166   else
167     {
168       g_return_val_if_fail (item->canvas->root == item, -1);
169       return 0;
170     }
171 }
172 
173 static AtkStateSet *
174 gail_canvas_item_ref_state_set (AtkObject *obj)
175 {
176   AtkGObjectAccessible *atk_gobj;
177   GObject *g_obj;
178   GnomeCanvasItem *item;
179   AtkStateSet *state_set;
180 
181   g_return_val_if_fail (GAIL_IS_CANVAS_ITEM (obj), NULL);
182   atk_gobj = ATK_GOBJECT_ACCESSIBLE (obj);
183 
184   state_set = ATK_OBJECT_CLASS (gail_canvas_item_parent_class)->ref_state_set (obj);
185 
186   g_obj = atk_gobject_accessible_get_object (atk_gobj);
187   if (g_obj == NULL)
188     {
189     /* Object is defunct */
190       atk_state_set_add_state (state_set, ATK_STATE_DEFUNCT);
191     }
192   else
193     {
194       item = GNOME_CANVAS_ITEM (g_obj);
195 
196       if (item->flags & GNOME_CANVAS_ITEM_VISIBLE)
197 	{
198 	  atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
199 	  if (is_item_on_screen (item))
200 	    {
201 	      atk_state_set_add_state (state_set, ATK_STATE_SHOWING);
202 	    }
203 	}
204       if (gtk_widget_get_can_focus (GTK_WIDGET (item->canvas)))
205 	{
206 	  atk_state_set_add_state (state_set, ATK_STATE_FOCUSABLE);
207 
208 	  if (item->canvas->focused_item == item)
209 	    {
210 	      atk_state_set_add_state (state_set, ATK_STATE_FOCUSED);
211 	    }
212 	}
213     }
214 
215   return state_set;
216 }
217 
218 static void
219 gail_canvas_item_component_interface_init (AtkComponentIface *iface)
220 {
221   g_return_if_fail (iface != NULL);
222 
223   iface->add_focus_handler = gail_canvas_item_add_focus_handler;
224   iface->get_extents = gail_canvas_item_get_extents;
225   iface->get_mdi_zorder = gail_canvas_item_get_mdi_zorder;
226   iface->grab_focus = gail_canvas_item_grab_focus;
227   iface->remove_focus_handler = gail_canvas_item_remove_focus_handler;
228 }
229 
230 static guint
231 gail_canvas_item_add_focus_handler (AtkComponent *component,
232                                     AtkFocusHandler handler)
233 {
234   GSignalMatchType match_type;
235   gulong ret;
236   guint signal_id;
237 
238   match_type = G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC;
239   signal_id = g_signal_lookup ("focus-event", ATK_TYPE_OBJECT);
240 
241   ret = g_signal_handler_find (component, match_type, signal_id, 0, NULL,
242 			       (gpointer) handler, NULL);
243   if (!ret)
244     {
245       return g_signal_connect_closure_by_id (
246 		component, signal_id, 0,
247 		g_cclosure_new (
248 			G_CALLBACK (handler), NULL,
249 			(GClosureNotify) NULL),
250 			FALSE);
251     }
252   else
253     {
254       return 0;
255     }
256 }
257 
258 static void
259 gail_canvas_item_get_extents (AtkComponent *component,
260                               gint *x,
261                               gint *y,
262                               gint *width,
263                               gint *height,
264                               AtkCoordType coord_type)
265 {
266   AtkGObjectAccessible *atk_gobj;
267   GObject *obj;
268   GnomeCanvasItem *item;
269   gint window_x, window_y;
270   gint toplevel_x, toplevel_y;
271   GdkRectangle extents;
272 
273   g_return_if_fail (GAIL_IS_CANVAS_ITEM (component));
274   atk_gobj = ATK_GOBJECT_ACCESSIBLE (component);
275   obj = atk_gobject_accessible_get_object (atk_gobj);
276 
277   if (obj == NULL)
278     /* item is defunct */
279     return;
280 
281   /* Get the GnomeCanvasItem */
282   item = GNOME_CANVAS_ITEM (obj);
283 
284   /* If this item has no parent canvas, something's broken */
285   g_return_if_fail (GTK_IS_WIDGET (item->canvas));
286 
287   get_item_extents (item, &extents);
288   *width = extents.width;
289   *height = extents.height;
290   if (!is_item_in_window (item, &extents))
291     {
292       *x = G_MININT;
293       *y = G_MININT;
294       return;
295     }
296 
297   gail_misc_get_origins (GTK_WIDGET (item->canvas), &window_x, &window_y,
298 			 &toplevel_x, &toplevel_y);
299   *x = extents.x + window_x - toplevel_x;
300   *y = extents.y + window_y - toplevel_y;
301 
302   /* If screen coordinates are requested, modify x and y appropriately */
303   if (coord_type == ATK_XY_SCREEN)
304     {
305       *x += toplevel_x;
306       *y += toplevel_y;
307     }
308   return;
309 }
310 
311 static gint
312 gail_canvas_item_get_mdi_zorder (AtkComponent *component)
313 {
314   g_return_val_if_fail (ATK_OBJECT (component), -1);
315 
316   return gail_canvas_item_get_index_in_parent (ATK_OBJECT (component));
317 }
318 
319 static gboolean
320 gail_canvas_item_grab_focus (AtkComponent *component)
321 {
322   AtkGObjectAccessible *atk_gobj;
323   GObject *obj;
324   GnomeCanvasItem *item;
325   GtkWidget *toplevel;
326 
327   g_return_val_if_fail (GAIL_IS_CANVAS_ITEM (component), FALSE);
328   atk_gobj = ATK_GOBJECT_ACCESSIBLE (component);
329   obj = atk_gobject_accessible_get_object (atk_gobj);
330 
331   /* Get the GnomeCanvasItem */
332   item = GNOME_CANVAS_ITEM (obj);
333   if (item == NULL)
334     /* item is defunct */
335     return FALSE;
336 
337   gnome_canvas_item_grab_focus (item);
338   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (item->canvas));
339   if (gtk_widget_is_toplevel (toplevel))
340     gtk_window_present (GTK_WINDOW (toplevel));
341 
342   return TRUE;
343 }
344 
345 static void
346 gail_canvas_item_remove_focus_handler (AtkComponent *component,
347                                        guint handler_id)
348 {
349   g_signal_handler_disconnect (ATK_OBJECT (component), handler_id);
350 }
351 
352 static gboolean
353 is_item_on_screen (GnomeCanvasItem *item)
354 {
355   GdkRectangle extents;
356 
357   get_item_extents (item, &extents);
358   return is_item_in_window (item, &extents);
359 }
360 
361 static void
362 get_item_extents (GnomeCanvasItem *item,
363                   GdkRectangle *extents)
364 {
365   double x1, x2, y1, y2;
366   cairo_matrix_t i2c;
367 
368   x1 = y1 = x2 = y2 = 0.0;
369 
370   if (GNOME_CANVAS_ITEM_CLASS (G_OBJECT_GET_CLASS (item))->bounds)
371     GNOME_CANVAS_ITEM_CLASS (G_OBJECT_GET_CLASS (item))->bounds (
372       item, &x1, &y1, &x2, &y2);
373 
374   /* Get the item coordinates -> canvas pixel coordinates affine */
375 
376   gnome_canvas_item_i2c_matrix (item, &i2c);
377   gnome_canvas_matrix_transform_rect (&i2c, &x1, &y1, &x2, &y2);
378 
379   extents->x = floor (x1);
380   extents->y = floor (y1);
381   extents->width = ceil (x2) - extents->x;
382   extents->height = ceil (y2) - extents->y;
383 }
384 
385 static gboolean
386 is_item_in_window (GnomeCanvasItem *item,
387                    const GdkRectangle *extents)
388 {
389   GtkWidget *widget;
390   GdkWindow *window;
391   gboolean retval;
392 
393   widget = GTK_WIDGET (item->canvas);
394   window = gtk_widget_get_window (widget);
395   if (window)
396     {
397       GdkRectangle window_rect;
398 
399       window_rect.x = 0;
400       window_rect.y = 0;
401       window_rect.width = gdk_window_get_width (window);
402       window_rect.height = gdk_window_get_height (window);
403 
404       retval = gdk_rectangle_intersect (extents, &window_rect, NULL);
405     }
406   else
407     {
408       retval = FALSE;
409     }
410   return retval;
411 }