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 }