X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=libspi%2Ftree.c;h=92f7f89c267fce0c6da83f664790a09eab180d38;hb=8e1a831f81570671c59e043e861b4bf4d2ec9754;hp=3dc71a6e8ce547d9a8654ea75962d54a32106449;hpb=f15f618cff30025b35f893c20c72468a5fb0aaa9;p=platform%2Fcore%2Fuifw%2Fat-spi2-atk.git diff --git a/libspi/tree.c b/libspi/tree.c index 3dc71a6..92f7f89 100644 --- a/libspi/tree.c +++ b/libspi/tree.c @@ -27,13 +27,13 @@ #define get_object(message) spi_dbus_get_object(dbus_message_get_path(message)) static dbus_bool_t -spi_dbus_append_tree_helper (DBusMessageIter * iter_array, AtkObject * obj, - DRouteData * data) +append_update (DBusMessageIter * iter_array, AtkObject * obj, + dbus_bool_t include_children, DRouteData * data) { - DBusMessageIter iter_struct, iter_sub, iter_sub_array; + DBusMessageIter iter_struct, iter_sub_array; char *path = NULL; + char *path_parent; const char *name, *desc; - dbus_uint16_t updating = 1; int i; dbus_uint32_t role; @@ -42,12 +42,13 @@ spi_dbus_append_tree_helper (DBusMessageIter * iter_array, AtkObject * obj, dbus_message_iter_open_container (iter_array, DBUS_TYPE_STRUCT, NULL, &iter_struct); - dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT16, &updating); path = spi_dbus_get_path (obj); dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path); - dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_STRUCT, NULL, - &iter_sub); - dbus_message_iter_open_container (&iter_sub, DBUS_TYPE_ARRAY, "o", + path_parent = spi_dbus_get_path (atk_object_get_parent(obj)); + if (!path_parent) path_parent = g_strdup("/"); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_OBJECT_PATH, &path_parent); + g_free(path_parent); + dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "o", &iter_sub_array); childcount = atk_object_get_n_accessible_children (obj); for (i = 0; i < childcount; i++) @@ -63,14 +64,14 @@ spi_dbus_append_tree_helper (DBusMessageIter * iter_array, AtkObject * obj, if (child) g_object_unref (child); } - if (!dbus_message_iter_close_container (&iter_sub, &iter_sub_array)) + if (!dbus_message_iter_close_container (&iter_struct, &iter_sub_array)) goto oom; - dbus_message_iter_open_container (&iter_sub, DBUS_TYPE_ARRAY, "s", + dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "s", &iter_sub_array); for (l = data->interfaces; l; l = g_slist_next (l)) { DRouteInterface *iface_def = (DRouteInterface *) l->data; - void *datum; + void *datum = NULL; if (iface_def->get_datum) { datum = (*iface_def->get_datum) (path, data->user_data); @@ -82,29 +83,28 @@ spi_dbus_append_tree_helper (DBusMessageIter * iter_array, AtkObject * obj, if (iface_def->free_datum) (*iface_def->free_datum) (datum); } - if (!dbus_message_iter_close_container (&iter_sub, &iter_sub_array)) + if (!dbus_message_iter_close_container (&iter_struct, &iter_sub_array)) goto oom; name = atk_object_get_name (obj); if (!name) name = ""; - dbus_message_iter_append_basic (&iter_sub, DBUS_TYPE_STRING, &name); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &name); role = spi_accessible_role_from_atk_role (atk_object_get_role (obj)); - dbus_message_iter_append_basic (&iter_sub, DBUS_TYPE_UINT32, &role); + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_UINT32, &role); desc = atk_object_get_description (obj); if (!desc) desc = ""; - dbus_message_iter_append_basic (&iter_sub, DBUS_TYPE_STRING, &desc); - if (!dbus_message_iter_close_container (&iter_struct, &iter_sub)) - goto oom; + dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &desc); if (!dbus_message_iter_close_container (iter_array, &iter_struct)) goto oom; + if (!include_children) childcount = 0; for (i = 0; i < childcount; i++) { AtkObject *child = atk_object_ref_accessible_child (obj, i); dbus_bool_t result; if (!child) continue; - result = spi_dbus_append_tree_helper (iter_array, child, data); + result = append_update (iter_array, child, TRUE, data); g_object_unref (child); if (!result) goto oom; @@ -124,43 +124,195 @@ spi_dbus_append_tree (DBusMessage * message, AtkObject * obj, dbus_bool_t result; dbus_message_iter_init_append (message, &iter); - dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(qo(aoassus))", + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(ooaoassus)", &iter_array); - result = spi_dbus_append_tree_helper (&iter_array, obj, data); + result = append_update (&iter_array, obj, TRUE, data); if (result) result = dbus_message_iter_close_container (&iter, &iter_array); return result; } static DBusMessage * -impl_getTree (DBusConnection * bus, DBusMessage * message, void *user_data) +impl_getRoot (DBusConnection * bus, DBusMessage * message, void *user_data) { + AtkObject *root = atk_get_root(); + char *path; DBusMessage *reply; - AtkObject *root; - gchar *path; - root = atk_get_root (); - if (root) - path = spi_dbus_get_path (root); + if (root) path = spi_dbus_get_path(root); if (!root || !path) return spi_dbus_general_error (message); reply = dbus_message_new_method_return (message); dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); g_free (path); + return reply; +} + +static DBusMessage * +impl_getTree (DBusConnection * bus, DBusMessage * message, void *user_data) +{ + DBusMessage *reply; + AtkObject *root = atk_get_root(); + + if (!root) return spi_dbus_general_error(message); + reply = dbus_message_new_method_return (message); spi_dbus_append_tree (reply, root, (DRouteData *) user_data); return reply; } static DRouteMethod methods[] = { - {DROUTE_METHOD, impl_getTree, "getTree", "o,root,o:a(go(aoassus)),tree,o", - TRUE}, - {0, NULL, NULL, NULL} + {impl_getRoot, "getRoot"}, + {impl_getTree, "getTree", TRUE}, + {NULL, NULL} }; void spi_initialize_tree (DRouteData * data) { - droute_add_interface (data, "org.freedesktop.atspi.AccessibleTree", + droute_add_interface (data, "org.freedesktop.atspi.Tree", methods, NULL, NULL, NULL); }; + +static GHashTable *cache_list; + +#define UPDATE_NEW 1 +#define UPDATE_REFRESH 2 +#define UPDATE_REMOVE 3 + +static int update_pending = 0; +static gint update_pending_id; + +typedef struct +{ + DBusMessageIter iter; + DRouteData *droute; + gboolean removing; +} CacheIterData; + +static void handle_cache_item(char *path, guint action, CacheIterData *d) +{ + AtkObject *obj; + + switch (action) + { + case UPDATE_NEW: + case UPDATE_REFRESH: + default: + if (d->removing) return; + obj = spi_dbus_get_object(path); +//printf("update %s\n", path); + append_update(&d->iter, obj, FALSE, d->droute); + break; + case UPDATE_REMOVE: +//printf("remove: %s\n", path); + if (!d->removing) return; + dbus_message_iter_append_basic(&d->iter, DBUS_TYPE_OBJECT_PATH, &path); + break; + } + g_hash_table_remove(cache_list, path); + } + +gboolean spi_dbus_update_cache(DRouteData *data) +{ + DBusMessage *message; + DBusMessageIter iter; + CacheIterData d; + + if (update_pending == 0) return FALSE; +//printf("Sending cache\n"); + message = dbus_message_new_signal("/org/freedesktop/atspi/tree", "org.freedesktop.atspi.Tree", "UpdateTree"); + if (!message) goto done; + dbus_message_iter_init_append (message, &iter); + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(ooaoassus)", + &d.iter); + d.droute = data; + d.removing = FALSE; + do + { + /* This loop is needed because appending an item may cause new children + * to be registered and consequently added to the hash, so they, too, + * will need to be sent with the update */ + update_pending = 0; + g_hash_table_foreach(cache_list, (GHFunc)handle_cache_item, &d); + } while (update_pending); + dbus_message_iter_close_container(&iter, &d.iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "o", &d.iter); + d.removing = TRUE; + g_hash_table_foreach(cache_list, (GHFunc)handle_cache_item, &d); + dbus_message_iter_close_container(&iter, &d.iter); + dbus_connection_send(data->bus, message, NULL); +done: + return FALSE; +} + +void spi_dbus_notify_change(AtkObject *obj, gboolean new, DRouteData *data) +{ + guint action = (new? UPDATE_NEW: UPDATE_REFRESH); + char *path = spi_dbus_get_path(obj); + + if (!cache_list) + { + cache_list = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + if (!cache_list) + { + g_free(path); + return; + } + } + if (g_hash_table_lookup(cache_list, path)) + { + g_free(path); + return; + } +//printf("change: %s\n", path); + g_hash_table_insert(cache_list, path, (gpointer)action); + if (update_pending != 2 && data) + { + update_pending_id = g_idle_add((GSourceFunc)spi_dbus_update_cache, data); + update_pending = 2; + } + else if (!update_pending) update_pending = 1; +} + +void spi_dbus_notify_remove(AtkObject *obj, DRouteData *data) +{ + guint action = UPDATE_REMOVE; + guint cur_action; + gchar *path = spi_dbus_get_path(obj); + +//printf("notify remove: %s\n", path); + if (!cache_list) + { + g_free(path); + return; + } + cur_action = (guint)g_hash_table_lookup(cache_list, path); + if (cur_action == UPDATE_NEW) + { + /* No one knew that this object ever existed, so just remove it */ +//printf("Removing object from send queue\n"); + g_hash_table_remove(cache_list, path); + g_free(path); + } + else + { + g_hash_table_insert(cache_list, path, (gpointer)action); + if (update_pending != 2 && data) + { + update_pending_id = g_idle_add((GSourceFunc)spi_dbus_update_cache, data); + update_pending = 2; + } + else if (!update_pending) update_pending = 1; + } +} + +gboolean spi_dbus_object_is_known(AtkObject *obj) +{ + guint cur_action; + char *path = spi_dbus_get_path(obj); + if (!path) return FALSE; + cur_action = (guint)g_hash_table_lookup(cache_list, path); + g_free(path); + return (cur_action != UPDATE_NEW); +}