for (i =0; i < atk_object_get_n_accessible_children (accessible); i++)
{
current = atk_object_ref_accessible_child (accessible, i);
+ if (current)
+ {
#ifdef SPI_ATK_DEBUG
- non_owned_accessible (current);
+ non_owned_accessible (current);
#endif
- if (!has_manages_descendants (current))
- {
- g_queue_push_tail (traversal, current);
- }
- else
- {
- g_object_unref (G_OBJECT (current));
+ if (!has_manages_descendants (current))
+ g_queue_push_tail (traversal, current);
+ else
+ g_object_unref (G_OBJECT (current));
}
}
}
GQueue *traversal;
GQueue *emit_update;
+ g_return_if_fail (ATK_IS_OBJECT (accessible));
+
traversal = g_queue_new ();
emit_update = g_queue_new ();
}
/*
+ * TODO WARNING HACK This function is dangerous.
+ * It should only be called before sending an event on an
+ * object that has not already been registered.
+ */
+gchar *
+atk_dbus_object_attempt_registration (AtkObject *accessible)
+{
+ guint ref;
+
+ ref = object_to_ref (accessible);
+ if (!ref)
+ {
+ /* See if the object is attached to the main tree */
+ AtkObject *current, *prev = NULL;
+ guint cref = 0;
+
+ /* This should iterate until it hits a NULL or registered parent */
+ prev = accessible;
+ current = atk_object_get_parent (accessible);
+ if (current)
+ cref = object_to_ref (current);
+ while (current && !cref)
+ {
+ prev = current;
+ current = atk_object_get_parent (current);
+ if (current)
+ cref = object_to_ref (current);
+ }
+
+ /* A registered parent, with non-registered child, has been found */
+ if (current)
+ {
+ register_subtree (prev);
+ }
+
+ /* The object SHOULD be registered now. If it isn't - I give up */
+ ref = object_to_ref (accessible);
+ if (ref)
+ {
+ return ref_to_path (ref);
+ }
+ else
+ {
+#ifdef SPI_ATK_DEBUG
+ g_debug ("AT-SPI: Could not register a non-attached accessible object");
+#endif
+ return NULL;
+ }
+ }
+ else
+ {
+ return ref_to_path (ref);
+ }
+}
+
+
+/*
* Used to lookup a D-Bus path from the AtkObject.
*/
gchar *
/*---------------------------------------------------------------------------*/
+typedef gboolean (*TreeUpdateAction) (GSignalInvocationHint *signal_hint,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer data,
+ AtkObject *accessible);
+
/*
* Events are not evaluated for non-registered accessibles.
*
* When a parent is changed the subtree is de-registered
* if the parent is not attached to the root accessible.
*/
+/* TODO Turn this function into a macro? */
static gboolean
-tree_update_listener (GSignalInvocationHint *signal_hint,
- guint n_param_values,
- const GValue *param_values,
- gpointer data)
+tree_update_wrapper (GSignalInvocationHint *signal_hint,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer data,
+ TreeUpdateAction action)
{
AtkObject *accessible;
- AtkPropertyValues *values;
- const gchar *pname = NULL;
g_static_rec_mutex_lock (®istration_mutex);
/* Ensure that only registered accessibles
* have their signals processed.
*/
- accessible = g_value_get_object (¶m_values[0]);
+ accessible = ATK_OBJECT(g_value_get_object (¶m_values[0]));
g_return_val_if_fail (ATK_IS_OBJECT (accessible), TRUE);
if (object_to_ref (accessible))
g_debug ("AT-SPI: Tree update listener");
#endif
+ action (signal_hint, n_param_values, param_values, data, accessible);
+
+ recursion_check_unset ();
+ }
+
+ g_static_rec_mutex_unlock (®istration_mutex);
+
+ return TRUE;
+}
+
+static gboolean
+tree_update_state_action (GSignalInvocationHint *signal_hint,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer data,
+ AtkObject *accessible)
+{
+ update_accessible (accessible);
+}
+
+static gboolean
+tree_update_state_listener (GSignalInvocationHint *signal_hint,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer data)
+{
+ tree_update_wrapper (signal_hint, n_param_values, param_values, data, tree_update_state_action);
+}
+static gboolean
+tree_update_property_action (GSignalInvocationHint *signal_hint,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer data,
+ AtkObject *accessible)
+{
+ AtkPropertyValues *values;
+ const gchar *pname = NULL;
values = (AtkPropertyValues*) g_value_get_pointer (¶m_values[1]);
pname = values[0].property_name;
if (strcmp (pname, "accessible-name") == 0 ||
- strcmp (pname, "accessible-description") == 0)
+ strcmp (pname, "accessible-description") == 0 ||
+ strcmp (pname, "accessible-parent") == 0)
{
update_accessible (accessible);
}
/* Parent value us updated by child-add signal of parent object */
-
- recursion_check_unset ();
- }
-
- g_static_rec_mutex_unlock (®istration_mutex);
-
- return TRUE;
}
-/*
- * Events are not evaluated for non registered accessibles.
- *
- * When the children of a registered accessible are changed
- * the subtree, rooted at the child is registered.
- */
static gboolean
-tree_update_children_listener (GSignalInvocationHint *signal_hint,
+tree_update_property_listener (GSignalInvocationHint *signal_hint,
guint n_param_values,
const GValue *param_values,
gpointer data)
{
- AtkObject *accessible;
- const gchar *detail = NULL;
- AtkObject *child;
-
- g_static_rec_mutex_lock (®istration_mutex);
-
- /* Ensure that only registered accessibles
- * have their signals processed.
- */
- accessible = g_value_get_object (¶m_values[0]);
- g_return_val_if_fail (ATK_IS_OBJECT (accessible), TRUE);
-
- if (object_to_ref (accessible))
- {
-#ifdef SPI_ATK_DEBUG
- if (recursion_check_and_set ())
- g_warning ("AT-SPI: Recursive use of registration module");
+ tree_update_wrapper (signal_hint, n_param_values, param_values, data, tree_update_property_action);
+}
- g_debug ("AT-SPI: Tree update children listener");
-#endif
+static gboolean
+tree_update_children_action (GSignalInvocationHint *signal_hint,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer data,
+ AtkObject *accessible)
+{
+ const gchar *detail = NULL;
+ AtkObject *child;
if (signal_hint->detail)
detail = g_quark_to_string (signal_hint->detail);
#endif
}
register_subtree (child);
+ update_accessible (accessible);
}
+}
+
+static gboolean
+tree_update_children_listener (GSignalInvocationHint *signal_hint,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer data)
+{
+ tree_update_wrapper (signal_hint, n_param_values, param_values, data, tree_update_children_action);
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void
+spi_atk_register_toplevel_added (AtkObject *accessible,
+ guint index,
+ AtkObject *child)
+{
+ g_static_rec_mutex_lock (®istration_mutex);
+
+ g_return_if_fail (ATK_IS_OBJECT (accessible));
+
+ if (object_to_ref (accessible))
+ {
+#ifdef SPI_ATK_DEBUG
+ if (recursion_check_and_set ())
+ g_warning ("AT-SPI: Recursive use of registration module");
+
+ g_debug ("AT-SPI: Toplevel added listener");
+#endif
+ if (!ATK_IS_OBJECT (child))
+ {
+ child = atk_object_ref_accessible_child (accessible, index);
+#ifdef SPI_ATK_DEBUG
+ non_owned_accessible (child);
+#endif
+ }
+ register_subtree (child);
+ update_accessible (accessible);
recursion_check_unset ();
}
g_static_rec_mutex_unlock (®istration_mutex);
+}
- return TRUE;
+static void
+spi_atk_register_toplevel_removed (AtkObject *accessible,
+ guint index,
+ AtkObject *child)
+{
+ g_static_rec_mutex_lock (®istration_mutex);
+
+ g_return_if_fail (ATK_IS_OBJECT (accessible));
+
+ if (object_to_ref (accessible))
+ {
+#ifdef SPI_ATK_DEBUG
+ if (recursion_check_and_set ())
+ g_warning ("AT-SPI: Recursive use of registration module");
+
+ g_debug ("AT-SPI: Toplevel removed listener");
+#endif
+ update_accessible (accessible);
+ recursion_check_unset ();
+ }
+
+ g_static_rec_mutex_unlock (®istration_mutex);
}
/*
register_subtree (root);
- atk_add_global_event_listener (tree_update_listener, "Gtk:AtkObject:property-change");
+ atk_add_global_event_listener (tree_update_property_listener, "Gtk:AtkObject:property-change");
atk_add_global_event_listener (tree_update_children_listener, "Gtk:AtkObject:children-changed");
+ atk_add_global_event_listener (tree_update_state_listener, "Gtk:AtkObject:state-change");
+
+ g_signal_connect (root,
+ "children-changed::add",
+ (GCallback) spi_atk_register_toplevel_added,
+ NULL);
+ g_signal_connect (root,
+ "children-changed::remove",
+ (GCallback) spi_atk_register_toplevel_removed,
+ NULL);
}
/*END------------------------------------------------------------------------*/
-