2 * AT-SPI - Assistive Technology Service Provider Interface
3 * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
5 * Copyright 2008 Novell, Inc.
6 * Copyright 2008, 2009, 2010 Codethink Ltd.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
29 #include "accessible-register.h"
32 * This module is responsible for keeping track of all the AtkObjects in
33 * the application, so that they can be accessed remotely and placed in
34 * a client side cache.
36 * To access an AtkObject remotely we need to provide a D-Bus object
37 * path for it. The D-Bus object paths used have a standard prefix
38 * (SPI_ATK_OBJECT_PATH_PREFIX). Appended to this prefix is a string
39 * representation of an integer reference. So to access an AtkObject
40 * remotely we keep a Hashtable that maps the given reference to
41 * the AtkObject pointer. An object in this hash table is said to be 'registered'.
43 * The architecture of AT-SPI dbus is such that AtkObjects are not
44 * remotely reference counted. This means that we need to keep track of
45 * object destruction. When an object is destroyed it must be 'deregistered'
46 * To do this lookup we keep a dbus-id attribute on each AtkObject.
50 #define SPI_ATK_PATH_PREFIX_LENGTH 27
51 #define SPI_ATK_OBJECT_PATH_PREFIX "/org/a11y/atspi/accessible/"
52 #define SPI_ATK_OBJECT_PATH_ROOT "root"
54 #define SPI_ATK_OBJECT_REFERENCE_TEMPLATE SPI_ATK_OBJECT_PATH_PREFIX "%d"
56 #define SPI_DBUS_ID "spi-dbus-id"
58 SpiRegister *spi_global_register = NULL;
60 static const gchar * spi_register_root_path = SPI_ATK_OBJECT_PATH_PREFIX SPI_ATK_OBJECT_PATH_ROOT;
68 static guint register_signals[LAST_SIGNAL] = { 0 };
70 /*---------------------------------------------------------------------------*/
73 spi_register_finalize (GObject * object);
76 spi_register_dispose (GObject * object);
78 /*---------------------------------------------------------------------------*/
80 G_DEFINE_TYPE (SpiRegister, spi_register, G_TYPE_OBJECT)
82 static void spi_register_class_init (SpiRegisterClass * klass)
84 GObjectClass *object_class = (GObjectClass *) klass;
86 spi_register_parent_class = g_type_class_ref (G_TYPE_OBJECT);
88 object_class->finalize = spi_register_finalize;
89 object_class->dispose = spi_register_dispose;
91 register_signals [OBJECT_REGISTERED] =
92 g_signal_new ("object-registered",
98 g_cclosure_marshal_VOID__OBJECT,
103 register_signals [OBJECT_DEREGISTERED] =
104 g_signal_new ("object-deregistered",
110 g_cclosure_marshal_VOID__OBJECT,
117 spi_register_init (SpiRegister * reg)
119 reg->ref2ptr = g_hash_table_new (g_direct_hash, g_direct_equal);
120 reg->reference_counter = 0;
124 deregister_object (gpointer data, GObject * gobj)
126 SpiRegister *reg = SPI_REGISTER (data);
128 spi_register_deregister_object (reg, gobj, FALSE);
132 spi_register_remove_weak_ref (gpointer key, gpointer val, gpointer reg)
134 g_object_weak_unref (val, deregister_object, reg);
138 spi_register_finalize (GObject * object)
140 SpiRegister *reg = SPI_REGISTER (object);
142 g_hash_table_foreach (reg->ref2ptr, spi_register_remove_weak_ref, reg);
143 g_hash_table_unref (reg->ref2ptr);
145 G_OBJECT_CLASS (spi_register_parent_class)->finalize (object);
149 spi_register_dispose (GObject * object)
151 SpiRegister *reg = SPI_REGISTER (object);
153 G_OBJECT_CLASS (spi_register_parent_class)->dispose (object);
156 /*---------------------------------------------------------------------------*/
159 * Each AtkObject must be asssigned a D-Bus path (Reference)
161 * This function provides an integer reference for a new
164 * TODO: Make this reference a little more unique, this is shoddy.
167 assign_reference (SpiRegister * reg)
169 reg->reference_counter++;
170 /* Reference of 0 not allowed as used as direct key in hash table */
171 if (reg->reference_counter == 0)
172 reg->reference_counter++;
173 return reg->reference_counter;
176 /*---------------------------------------------------------------------------*/
179 * Returns the reference of the object, or 0 if it is not registered.
182 object_to_ref (GObject * gobj)
184 return GPOINTER_TO_INT (g_object_get_data (gobj, SPI_DBUS_ID));
188 * Converts the Accessible object reference to its D-Bus object path
191 ref_to_path (guint ref)
193 return g_strdup_printf (SPI_ATK_OBJECT_REFERENCE_TEMPLATE, ref);
196 /*---------------------------------------------------------------------------*/
199 * Callback for when a registered AtkObject is destroyed.
201 * Removes the AtkObject from the reference lookup tables, meaning
202 * it is no longer exposed over D-Bus.
205 spi_register_deregister_object (SpiRegister *reg, GObject *gobj, gboolean unref)
209 ref = object_to_ref (gobj);
213 register_signals [OBJECT_DEREGISTERED],
217 g_object_weak_unref (gobj, deregister_object, reg);
218 g_hash_table_remove (reg->ref2ptr, GINT_TO_POINTER (ref));
221 g_debug ("DEREG - %d", ref);
227 register_object (SpiRegister * reg, GObject * gobj)
230 g_return_if_fail (G_IS_OBJECT (gobj));
232 ref = assign_reference (reg);
234 g_hash_table_insert (reg->ref2ptr, GINT_TO_POINTER (ref), gobj);
235 g_object_set_data (G_OBJECT (gobj), SPI_DBUS_ID, GINT_TO_POINTER (ref));
236 g_object_weak_ref (G_OBJECT (gobj), deregister_object, reg);
239 g_debug ("REG - %d", ref);
242 g_signal_emit (reg, register_signals [OBJECT_REGISTERED], 0, gobj);
245 /*---------------------------------------------------------------------------*/
248 * Used to lookup an GObject from its D-Bus path.
250 * If the D-Bus path is not found this function returns NULL.
253 spi_register_path_to_object (SpiRegister * reg, const char *path)
258 g_return_val_if_fail (path, NULL);
260 if (strncmp (path, SPI_ATK_OBJECT_PATH_PREFIX, SPI_ATK_PATH_PREFIX_LENGTH)
264 path += SPI_ATK_PATH_PREFIX_LENGTH; /* Skip over the prefix */
266 /* Map the root path to the root object. */
267 if (!g_strcmp0 (SPI_ATK_OBJECT_PATH_ROOT, path))
268 return G_OBJECT (spi_global_app_data->root);
271 data = g_hash_table_lookup (reg->ref2ptr, GINT_TO_POINTER (index));
273 return G_OBJECT(data);
279 spi_global_register_path_to_object (const char * path)
281 return spi_register_path_to_object (spi_global_register, path);
285 * Used to lookup a D-Bus path from the GObject.
287 * If the objects is not already registered,
288 * this function will register it.
291 spi_register_object_to_path (SpiRegister * reg, GObject * gobj)
298 /* Map the root object to the root path. */
299 if ((void *)gobj == (void *)spi_global_app_data->root)
300 return g_strdup (spi_register_root_path);
302 ref = object_to_ref (gobj);
305 register_object (reg, gobj);
306 ref = object_to_ref (gobj);
312 return ref_to_path (ref);
316 spi_register_object_to_ref (GObject * gobj)
318 return object_to_ref (gobj);
322 * Gets the path that indicates the accessible desktop object.
323 * This object is logically located on the registry daemon and not
324 * within any particular application.
327 spi_register_root_object_path ()
329 return g_strdup (SPI_ATK_OBJECT_PATH_PREFIX SPI_ATK_OBJECT_PATH_ROOT);
332 /*END------------------------------------------------------------------------*/