--- /dev/null
+[general]
+upstream_tag = AT_SPI2_CORE_2_16_0
return g_strdup (obj->name);
}
+
+/**
+ * atspi_accessible_get_unique_id:
+ * @obj: a pointer to the #AtspiAccessible object on which to operate.
+ *
+ * Gets the identificator, uniquely identifying object, or NULL if an error occured.
+ *
+ * Returns: a UTF-8 string describing the #AtspiAccessible object
+ * or NULL on exception or NULL object passed.
+ **/
+gchar *
+atspi_accessible_get_unique_id(AtspiAccessible *obj, GError **error)
+{
+ if (!obj) {
+ g_set_error(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "argument is null");
+ return NULL;
+ }
+
+ gchar *id = NULL;
+ gchar *bus_name = atspi_accessible_get_bus_name(obj, error);
+ if (bus_name && bus_name[0]) {
+ gchar *path = atspi_accessible_get_path(obj, error);
+ if (path && path[0])
+ id = g_strdup_printf("%s:%s", bus_name, path);
+ else
+ g_set_error(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "failed to get path");
+ g_free(path);
+ }
+ else
+ g_set_error(error, ATSPI_ERROR, ATSPI_ERROR_IPC, "failed to get bus name");
+ g_free(bus_name);
+ return id;
+}
+
+/**
+ * atspi_accessible_get_bus_name:
+ * @obj: a pointer to the #AtspiAccessible object on which to operate.
+ *
+ * Gets the bus name, where object belongs.
+ *
+ * Returns: a UTF-8 string describing the #AtspiAccessible object's
+ * bus name or empty string on exception or NULL object passed.
+ **/
+gchar *
+atspi_accessible_get_bus_name(AtspiAccessible *obj, GError **error)
+{
+ if (!obj || !obj->parent.app)
+ return g_strdup("");
+ return g_strdup (obj->parent.app->bus_name);
+}
+
+/**
+ * atspi_accessible_get_path:
+ * @obj: a pointer to the #AtspiAccessible object on which to operate.
+ *
+ * Gets the path, uniquely identifying object over its bus name.
+ *
+ * Returns: a UTF-8 string describing the #AtspiAccessible object
+ * or empty string on exception or NULL object passed.
+ **/
+gchar *
+atspi_accessible_get_path(AtspiAccessible *obj, GError **error)
+{
+ static const char *prefix = "/org/a11y/atspi/accessible/";
+ static int prefix_len = 27;
+
+ if (!obj)
+ return g_strdup("");
+ AtspiObject *o = ATSPI_OBJECT (obj);
+ if (!o)
+ return g_strdup("");
+ if (strncmp(o->path, prefix, prefix_len) == 0)
+ return g_strdup(o->path + prefix_len);
+ return g_strdup (o->path);
+}
+
+/**
+ * atspi_accessible_get_navigable_at_point:
+ * @root: a pointer to the #AtspiAccessible to start search from.
+ * @x: a #gint specifying the x coordinate of the point in question.
+ * @y: a #gint specifying the y coordinate of the point in question.
+ * @ctype: the coordinate system of the point (@x, @y)
+ * (e.g. ATSPI_COORD_TYPE_WINDOW, ATSPI_COORD_TYPE_SCREEN).
+ *
+ * Finds the accessible element closest to user (highest in z-order), at a given coordinate within an #AtspiAccessible.
+ * This should be the element, that should be picked, when doing mouse click or finger tap at given coordinates.
+ *
+ * Returns: (nullable) (transfer full): a pointer to an
+ * #AtspiAccessible descendant (of any depth) of the specified component which
+ * contains the point (@x, @y), or NULL if no descendant contains
+ * the point.
+ **/
+AtspiAccessible *
+atspi_accessible_get_navigable_at_point (AtspiAccessible *root,
+ gint x,
+ gint y,
+ AtspiCoordType ctype, GError **error)
+{
+ dbus_int32_t d_x = x, d_y = y;
+ dbus_uint32_t d_ctype = ctype;
+ DBusMessage *reply;
+ AtspiAccessible *return_value = NULL;
+ unsigned char recurse = 0;
+ DBusMessageIter iter;
+ AtspiAccessible *deputy = NULL;
+
+ g_return_val_if_fail (root != NULL, NULL);
+ do {
+ reply = _atspi_dbus_call_partial (root, atspi_interface_accessible, "GetNavigableAtPoint", error, "iiu", d_x, d_y, d_ctype);
+ // call failed, error is set, so we bail out
+ if (!reply) {
+ if (deputy) g_object_unref(deputy);
+ if (return_value) g_object_unref(return_value);
+ return NULL;
+ }
+ _ATSPI_DBUS_CHECK_SIG (reply, "(so)y(so)", NULL, NULL);
+
+ dbus_message_iter_init (reply, &iter);
+ AtspiAccessible *tmp = _atspi_dbus_return_accessible_from_iter (&iter);
+
+ unsigned char value = 0;
+ dbus_message_iter_get_basic (&iter, &value);
+ dbus_message_iter_next (&iter);
+ recurse = (value != 0);
+
+ /* keep deputy if tmp has deputy */
+ if (!deputy)
+ deputy = _atspi_dbus_return_accessible_from_iter (&iter);
+
+ dbus_message_unref(reply);
+
+ if (!tmp) {
+ if (deputy) {
+ /* TODO: need to check deputy works for return value */
+ if (return_value)
+ g_object_unref(return_value);
+ return deputy;
+ }
+ break;
+ }
+
+ if (return_value)
+ g_object_unref(return_value);
+ return_value = root = tmp;
+ } while(recurse);
+ return return_value;
+}
+
+/**
+ * atspi_accessible_get_reading_material:
+ * @obj: a pointer to the #AtspiAccessible object on which to operate.
+ *
+ * Gets reading material
+ *
+ * Returns: reading material to be used screen-reader side. This is not stable.
+ * You have to handle all alocated memory as below on screen-reader side.
+ *
+ * AtspiAccessibleReadingMaterial *rm
+ * g_object_unref(rm->parent);
+ * g_object_unref(rm->described_by_accessible);
+ * g_hash_table_unref(rm->attributes);
+ * free(rm->name);
+ * free(rm->labeled_by_name);
+ * free(rm->text_interface_name);
+ * free(rm->localized_role_name);
+ * free(rm->description);
+ * free(rm);
+ **/
+AtspiAccessibleReadingMaterial *
+atspi_accessible_get_reading_material (AtspiAccessible *obj, GError **error)
+{
+ AtspiAccessible *parent;
+ AtspiAccessibleReadingMaterial *reading_material = NULL;
+ const char *name;
+ double current_value;
+ gint count;
+ guint64 val;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter iter_array;
+ dbus_uint32_t role;
+ dbus_uint32_t *states;
+ dbus_int32_t index_in_parent;
+ dbus_int32_t child_count;
+ dbus_bool_t is_selected;
+
+ g_return_val_if_fail (obj != NULL, NULL);
+
+ reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetReadingMaterial", error, "");
+
+ _ATSPI_DBUS_CHECK_SIG (reply, "a{ss}sssuausiddddsibbii(so)auiui(so)", NULL, NULL);
+
+ reading_material = calloc(1, sizeof(AtspiAccessibleReadingMaterial));
+ if (!reading_material)
+ {
+ return reading_material;
+ }
+
+ dbus_message_iter_init (reply, &iter);
+
+ /* get attributes */
+ reading_material->attributes = _atspi_dbus_hash_from_iter (&iter);
+ dbus_message_iter_next (&iter);
+
+ /* get name */
+ dbus_message_iter_get_basic (&iter, &name);
+ reading_material->name = g_strdup (name);
+ dbus_message_iter_next (&iter);
+
+ /* get name of relation LABELED_BY */
+ dbus_message_iter_get_basic (&iter, &name);
+ reading_material->labeled_by_name = g_strdup (name);
+ dbus_message_iter_next (&iter);
+
+ /* get name of text interface */
+ dbus_message_iter_get_basic (&iter, &name);
+ reading_material->text_interface_name = g_strdup (name);
+ dbus_message_iter_next (&iter);
+
+ /* get role */
+ dbus_message_iter_get_basic (&iter, &role);
+ reading_material->role = role;
+ dbus_message_iter_next (&iter);
+
+ /* get state set */
+ dbus_message_iter_recurse (&iter, &iter_array);
+ dbus_message_iter_get_fixed_array (&iter_array, &states, &count);
+ val = ((guint64)states [1]) << 32;
+ val += states [0];
+ reading_material->states = val;
+ dbus_message_iter_next (&iter);
+
+ /* get localized role name */
+ dbus_message_iter_get_basic (&iter, &name);
+ reading_material->localized_role_name = g_strdup (name);
+ dbus_message_iter_next (&iter);
+
+ /* get child count */
+ dbus_message_iter_get_basic (&iter, &child_count);
+ reading_material->child_count = child_count;
+ dbus_message_iter_next (&iter);
+
+ /* get current value */
+ dbus_message_iter_get_basic (&iter, ¤t_value);
+ reading_material->value = current_value;
+ dbus_message_iter_next (&iter);
+
+ /* get minimum increment */
+ dbus_message_iter_get_basic (&iter, ¤t_value);
+ reading_material->increment = current_value;
+ dbus_message_iter_next (&iter);
+
+ /* get maximum value */
+ dbus_message_iter_get_basic (&iter, ¤t_value);
+ reading_material->upper = current_value;
+ dbus_message_iter_next (&iter);
+
+ /* get minimum value */
+ dbus_message_iter_get_basic (&iter, ¤t_value);
+ reading_material->lower = current_value;
+ dbus_message_iter_next (&iter);
+
+ /* get description */
+ dbus_message_iter_get_basic (&iter, &name);
+ reading_material->description = g_strdup (name);
+ dbus_message_iter_next (&iter);
+
+ /* get index in parent */
+ dbus_message_iter_get_basic (&iter, &index_in_parent);
+ reading_material->index_in_parent = index_in_parent;
+ dbus_message_iter_next (&iter);
+
+ /* get selected in parent */
+ dbus_message_iter_get_basic (&iter, &is_selected);
+ reading_material->is_selected_in_parent = is_selected;
+ dbus_message_iter_next (&iter);
+
+ /* get has checkbox child */
+ dbus_message_iter_get_basic (&iter, &is_selected);
+ reading_material->has_checkbox_child = is_selected;
+ dbus_message_iter_next (&iter);
+
+ /* get list children count */
+ dbus_message_iter_get_basic (&iter, &child_count);
+ reading_material->list_children_count = child_count;
+ dbus_message_iter_next (&iter);
+
+ /* get first selected child index */
+ dbus_message_iter_get_basic (&iter, &index_in_parent);
+ reading_material->first_selected_child_index = index_in_parent;
+ dbus_message_iter_next (&iter);
+
+ ////////////////
+ /* get parent */
+ parent = _atspi_dbus_return_accessible_from_iter (&iter);
+ reading_material->parent = parent;
+
+ /* parent states */
+ dbus_message_iter_recurse (&iter, &iter_array);
+ dbus_message_iter_get_fixed_array (&iter_array, &states, &count);
+ val = ((guint64)states [1]) << 32;
+ val += states [0];
+ reading_material->parent_states = val;
+ dbus_message_iter_next (&iter);
+
+ /* get parent child count */
+ dbus_message_iter_get_basic (&iter, &child_count);
+ reading_material->parent_child_count = child_count;
+ dbus_message_iter_next (&iter);
+
+ /* get parent role */
+ dbus_message_iter_get_basic (&iter, &role);
+ reading_material->parent_role = role;
+ dbus_message_iter_next (&iter);
+
+ /* get parent selected child count */
+ dbus_message_iter_get_basic (&iter, &child_count);
+ reading_material->parent_selected_child_count = child_count;
+ dbus_message_iter_next (&iter);
+
+ ////////////////////////////////////////
+ /* get relation object - DESCRIBED_BY */
+ parent = _atspi_dbus_return_accessible_from_iter (&iter);
+ reading_material->described_by_accessible = parent;
+
+ return reading_material;
+}
+
+/**
+ * atspi_accessible_get_default_label_info:
+ * @obj: a pointer to the #AtspiAccessible object would be window.
+ *
+ * Gets default label information
+ *
+ * Returns: default label information to be used screen-reader side.
+ * This is not stable. And this depends on toolkit side UI definition.
+ * The candidate of default label object could be changed by UI definition.
+ * You have to handle all alocated memory as below on screen-reader side.
+ *
+ * AtspiAccessibleDefaultLabelInfo *dli
+ * g_hash_table_unref(dli->attributes);
+
+ * g_object_unref(dli->obj);
+ * free(dli);
+ **/
+AtspiAccessibleDefaultLabelInfo *
+atspi_accessible_get_default_label_info (AtspiAccessible *obj, GError **error)
+{
+ AtspiAccessibleDefaultLabelInfo *default_label_info = NULL;
+ AtspiAccessible *default_label_object;
+ dbus_uint32_t role;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+
+ g_return_val_if_fail (obj != NULL, NULL);
+
+ reply = _atspi_dbus_call_partial (obj, atspi_interface_accessible, "GetDefaultLabelInfo", error, "");
+
+ _ATSPI_DBUS_CHECK_SIG (reply, "(so)ua{ss}", NULL, NULL);
+
+ default_label_info = calloc(1, sizeof(AtspiAccessibleDefaultLabelInfo));
+ if (!default_label_info)
+ {
+ return default_label_info;
+ }
+
+ dbus_message_iter_init (reply, &iter);
+
+ default_label_object = _atspi_dbus_return_accessible_from_iter (&iter);
+ default_label_info->obj = default_label_object;
+
+ dbus_message_iter_get_basic (&iter, &role);
+ default_label_info->role = role;
+ dbus_message_iter_next (&iter);
+
+ default_label_info->attributes = _atspi_dbus_hash_from_iter (&iter);
+ dbus_message_iter_next (&iter);
+
+ return default_label_info;
+}
+
+static unsigned char are_objects_on_the_same_bus(AtspiAccessible *obj1, AtspiAccessible *obj2)
+{
+ const char *bus_name_1 = obj1->parent.app->bus_name;
+ const char *bus_name_2 = obj2->parent.app->bus_name;
+ return strcmp(bus_name_1, bus_name_2) == 0;
+}
+
+static unsigned char object_is_valid(AtspiAccessible *obj)
+{
+ if (!obj)
+ return 0;
+ AtspiStateSet *ss = atspi_accessible_get_state_set(obj);
+ if (!ss)
+ return 0;
+ unsigned char valid = atspi_state_set_contains(ss, ATSPI_STATE_DEFUNCT) == 0;
+ g_object_unref(ss);
+ return valid;
+}
+
+typedef enum {
+ NEIGHBOR_SEARCH_MODE_NORMAL = 0,
+ NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT = 1,
+ NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING = 2,
+ NEIGHBOR_SEARCH_MODE_RECURSE_TO_OUTSIDE = 3,
+} GetNeighborSearchMode;
+/**
+ * atspi_accessible_get_neighbor:
+ * @root: a pointer to a #AtspiAccessible, which represents current root of subtree to search
+ * @start: a pointer to the #AtspiAccessible to start search from (can be null, which means start from root)
+ * @direction: direction, in which search (forward or backward)
+ *
+ * Calculates next (or previous) accessible element in logical order or null if none found.
+ *
+ * Returns: (nullable) (transfer full): a pointer to an
+ * #AtspiAccessible element, which is next (previous) in logical order or null if none found.
+ **/
+AtspiAccessible *
+atspi_accessible_get_neighbor (AtspiAccessible *root,
+ AtspiAccessible *start,
+ AtspiNeighborSearchDirection direction,
+ GError **error)
+{
+ g_return_val_if_fail (object_is_valid(root), NULL);
+ if (!object_is_valid(start))
+ start = root;
+ const char *root_path = ATSPI_OBJECT(root)->path;
+ AtspiAccessible *return_value = NULL;
+ g_object_ref(start);
+ unsigned char recurse;
+ GetNeighborSearchMode search_mode = NEIGHBOR_SEARCH_MODE_NORMAL;
+ GQueue *children_root_stack = g_queue_new();
+ DBusMessageIter iter;
+
+ while(1) {
+ const char *path = are_objects_on_the_same_bus(root, start) ? root_path : "";
+ DBusMessage *reply = _atspi_dbus_call_partial (start, atspi_interface_accessible, "GetNeighbor", error, "sii", path, (int)direction, (int)search_mode);
+ // call failed, error is set, so we bail out
+ if (!reply) break;
+
+ _ATSPI_DBUS_CHECK_SIG (reply, "(so)y", error, NULL);
+ dbus_message_iter_init (reply, &iter);
+ AtspiAccessible *ret = _atspi_dbus_return_accessible_from_iter (&iter);
+
+ unsigned char value = 0;
+ dbus_message_iter_get_basic (&iter, &value);
+ dbus_message_iter_next (&iter);
+ recurse = (value != 0);
+
+ dbus_message_unref(reply);
+
+ // got return value and request for recursive search, it means ret is on another bridge, than start
+ // thus we're recursing. should the recurse failed to find anything it will end with
+ if (ret && recurse) {
+ g_object_unref(G_OBJECT(start));
+ start = ret;
+ g_object_ref(start);
+ if (are_objects_on_the_same_bus(root, ret))
+ {
+ search_mode = NEIGHBOR_SEARCH_MODE_RECURSE_TO_OUTSIDE;
+ }
+ else
+ {
+ g_queue_push_tail(children_root_stack, ret);
+ search_mode = NEIGHBOR_SEARCH_MODE_RECURSE_FROM_ROOT;
+ }
+ continue;
+ }
+ // found the one we've been looking for
+ if (ret) {
+ g_object_unref(G_OBJECT(start));
+ return_value = ret;
+ break;
+ }
+
+ // we've stepped into different bridges previously and now we're going back to the last one
+ // and continuing search where we left
+ if (!g_queue_is_empty(children_root_stack)) {
+ g_object_unref(G_OBJECT(start));
+ start = g_queue_pop_tail(children_root_stack);
+
+ search_mode = NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING;
+ continue;
+ }
+ // there's no more bridges to check, but we might have started from one
+ // in that case there might be bridges "below" start, which we yet have to visit
+ if (!are_objects_on_the_same_bus(root, start)) {
+ unsigned char continue_loop = 1;
+ while(continue_loop) {
+ AtspiAccessible *parent = atspi_accessible_get_parent(start, NULL);
+ continue_loop = parent ? are_objects_on_the_same_bus(start, parent) : 0;
+ g_object_unref(G_OBJECT(start));
+ start = parent;
+ }
+
+ // going up thru parents put us in weird place (we didnt meet root on the way)
+ // so we bail out
+ if (!start)
+ break;
+
+ // start object now points to different bridge and must be treated as "resume after recursing"
+ search_mode = NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING;
+ continue;
+ }
+
+ // nothing found
+ g_object_unref(start);
+ break;
+ }
+ while(!g_queue_is_empty(children_root_stack))
+ g_object_unref(g_queue_pop_tail(children_root_stack));
+ g_queue_free(children_root_stack);
+
+ return return_value;
+}
+
/**
* atspi_accessible_get_description:
* @obj: a pointer to the #AtspiAccessible object on which to operate.
* atspi_accessible_get_localized_role_name:
* @obj: a pointer to the #AtspiAccessible object on which to operate.
*
- * Gets a UTF-8 string corresponding to the name of the role played by an
+ * Gets a UTF-8 string corresponding to the name of the role played by an
* object, translated to the current locale.
* This method will return useful values for roles that fall outside the
* enumeration used in atspi_accessible_getRole ().
*
- * Returns: a localized, UTF-8 string specifying the type of UI role played
+ * Returns: a localized, UTF-8 string specifying the type of UI role played
* by an #AtspiAccessible object.
*
**/
dbus_message_unref (reply);
_atspi_accessible_add_cache (obj, ATSPI_CACHE_STATES);
}
-
return g_object_ref (obj->states);
}
* atspi_accessible_get_attributes:
* @obj: The #AtspiAccessible being queried.
*
- * Gets the #AttributeSet representing any assigned
+ * Gets the #AttributeSet representing any assigned
* name-value pair attributes or annotations for this object.
* For typographic, textual, or textually-semantic attributes, see
* atspi_text_get_attributes instead.
* atspi_accessible_get_attributes_as_array:
* @obj: The #AtspiAccessible being queried.
*
- * Gets a #GArray representing any assigned
+ * Gets a #GArray representing any assigned
* name-value pair attributes or annotations for this object.
* For typographic, textual, or textually-semantic attributes, see
* atspi_text_get_attributes_as_array instead.
* Gets the application id for a #AtspiAccessible object.
* Only works on application root objects.
*
- * Returns: a positive #gint indicating the id for the #AtspiAccessible object
+ * Returns: a positive #gint indicating the id for the #AtspiAccessible object
* or -1 on exception.
**/
gint
* atspi_accessible_is_action:
* @obj: a pointer to the #AtspiAccessible instance to query.
*
- * Query whether the specified #AtspiAccessible implements the
+ * Query whether the specified #AtspiAccessible implements the
* #AtspiAction interface.
*
* Returns: #TRUE if @obj implements the #AtspiAction interface,
atspi_interface_application);
}
-/**
+/**
* atspi_accessible_is_collection:
* @obj: a pointer to the #AtspiAccessible instance to query.
*
return _atspi_accessible_is_a (obj,
atspi_interface_editable_text);
}
-
+
/**
* atspi_accessible_is_hypertext:
* @obj: a pointer to the #AtspiAccessible instance to query.
* atspi_accessible_is_hyperlink:
* @obj: a pointer to the #AtspiAccessible instance to query.
*
- * Query whether the specified #AtspiAccessible implements the
+ * Query whether the specified #AtspiAccessible implements the
* #AtspiHyperlink interface.
*
* Returns: #TRUE if @obj implements the #AtspiHypertext interface,
* atspi_accessible_is_text:
* @obj: a pointer to the #AtspiAccessible instance to query.
*
- * Query whether the specified #AtspiAccessible implements the
+ * Query whether the specified #AtspiAccessible implements the
* #AtspiText interface.
*
* Returns: #TRUE if @obj implements the #AtspiText interface,
atspi_accessible_get_action (AtspiAccessible *accessible)
{
return (_atspi_accessible_is_a (accessible, atspi_interface_action) ?
- g_object_ref (ATSPI_ACTION (accessible)) : NULL);
+ g_object_ref (ATSPI_ACTION (accessible)) : NULL);
}
/**
atspi_accessible_get_action_iface (AtspiAccessible *accessible)
{
return (_atspi_accessible_is_a (accessible, atspi_interface_action) ?
- g_object_ref (ATSPI_ACTION (accessible)) : NULL);
+ g_object_ref (ATSPI_ACTION (accessible)) : NULL);
}
/**
atspi_accessible_get_collection (AtspiAccessible *accessible)
{
return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ?
- g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);
+ g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);
}
/**
atspi_accessible_get_collection_iface (AtspiAccessible *accessible)
{
return (_atspi_accessible_is_a (accessible, atspi_interface_collection) ?
- g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);
+ g_object_ref (ATSPI_COLLECTION (accessible)) : NULL);
}
/**
atspi_accessible_get_document (AtspiAccessible *accessible)
{
return (_atspi_accessible_is_a (accessible, atspi_interface_document) ?
- g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);
+ g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);
}
/**
atspi_accessible_get_document_iface (AtspiAccessible *accessible)
{
return (_atspi_accessible_is_a (accessible, atspi_interface_document) ?
- g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);
+ g_object_ref (ATSPI_DOCUMENT (accessible)) : NULL);
}
/**
atspi_accessible_get_editable_text (AtspiAccessible *accessible)
{
return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ?
- g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);
+ g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);
}
/**
atspi_accessible_get_editable_text_iface (AtspiAccessible *accessible)
{
return (_atspi_accessible_is_a (accessible, atspi_interface_editable_text) ?
- g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);
+ g_object_ref (ATSPI_EDITABLE_TEXT (accessible)) : NULL);
}
/**
atspi_accessible_get_hypertext (AtspiAccessible *accessible)
{
return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ?
- g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);
+ g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);
}
/**
atspi_accessible_get_hypertext_iface (AtspiAccessible *accessible)
{
return (_atspi_accessible_is_a (accessible, atspi_interface_hypertext) ?
- g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);
+ g_object_ref (ATSPI_HYPERTEXT (accessible)) : NULL);
}
/**
atspi_accessible_get_image (AtspiAccessible *accessible)
{
return (_atspi_accessible_is_a (accessible, atspi_interface_image) ?
- g_object_ref (ATSPI_IMAGE (accessible)) : NULL);
+ g_object_ref (ATSPI_IMAGE (accessible)) : NULL);
}
/**
atspi_accessible_get_image_iface (AtspiAccessible *accessible)
{
return (_atspi_accessible_is_a (accessible, atspi_interface_image) ?
- g_object_ref (ATSPI_IMAGE (accessible)) : NULL);
+ g_object_ref (ATSPI_IMAGE (accessible)) : NULL);
}
/**
atspi_accessible_get_selection (AtspiAccessible *accessible)
{
return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ?
- g_object_ref (ATSPI_SELECTION (accessible)) : NULL);
+ g_object_ref (ATSPI_SELECTION (accessible)) : NULL);
}
/**
atspi_accessible_get_selection_iface (AtspiAccessible *accessible)
{
return (_atspi_accessible_is_a (accessible, atspi_interface_selection) ?
- g_object_ref (ATSPI_SELECTION (accessible)) : NULL);
+ g_object_ref (ATSPI_SELECTION (accessible)) : NULL);
}
#if 0
atspi_accessible_get_streamable_content (AtspiAccessible *accessible)
{
return (_atspi_accessible_is_a (accessible, atspi_interface_streamable_content) ?
- accessible : NULL);
+ accessible : NULL);
}
#endif
atspi_accessible_get_table (AtspiAccessible *obj)
{
return (_atspi_accessible_is_a (obj, atspi_interface_table) ?
- g_object_ref (ATSPI_TABLE (obj)) : NULL);
+ g_object_ref (ATSPI_TABLE (obj)) : NULL);
}
/**
atspi_accessible_get_table_iface (AtspiAccessible *obj)
{
return (_atspi_accessible_is_a (obj, atspi_interface_table) ?
- g_object_ref (ATSPI_TABLE (obj)) : NULL);
+ g_object_ref (ATSPI_TABLE (obj)) : NULL);
}
/**
atspi_accessible_get_table_cell (AtspiAccessible *obj)
{
return (_atspi_accessible_is_a (obj, atspi_interface_table_cell) ?
- g_object_ref (ATSPI_TABLE_CELL (obj)) : NULL);
+ g_object_ref (ATSPI_TABLE_CELL (obj)) : NULL);
}
/**
atspi_accessible_get_value (AtspiAccessible *accessible)
{
return (_atspi_accessible_is_a (accessible, atspi_interface_value) ?
- g_object_ref (ATSPI_VALUE (accessible)) : NULL);
+ g_object_ref (ATSPI_VALUE (accessible)) : NULL);
}
/**
atspi_accessible_get_value_iface (AtspiAccessible *accessible)
{
return (_atspi_accessible_is_a (accessible, atspi_interface_value) ?
- g_object_ref (ATSPI_VALUE (accessible)) : NULL);
+ g_object_ref (ATSPI_VALUE (accessible)) : NULL);
}
static void
GArray *
atspi_accessible_get_interfaces (AtspiAccessible *obj)
{
- GArray *ret = g_array_new (TRUE, TRUE, sizeof (gchar *));
+ GArray *ret;
g_return_val_if_fail (obj != NULL, NULL);
+ ret = g_array_new (TRUE, TRUE, sizeof (gchar *));
+
append_const_val (ret, "Accessible");
if (atspi_accessible_is_action (obj))
append_const_val (ret, "Action");
return ret;
}
-AtspiAccessible *
+AtspiAccessible *
_atspi_accessible_new (AtspiApplication *app, const gchar *path)
{
AtspiAccessible *accessible;
-
+
accessible = g_object_new (ATSPI_TYPE_ACCESSIBLE, NULL);
g_return_val_if_fail (accessible != NULL, NULL);
* Copyright 2002 Ximian, Inc.
* 2002 Sun Microsystems Inc.
* Copyright 2010, 2011 Novell, Inc.
- *
+ *
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
typedef struct _AtspiAccessiblePrivate AtspiAccessiblePrivate;
+struct _AtspiAccessibleDefaultLabelInfo
+{
+ AtspiAccessible *obj;
+ AtspiRole role;
+ GHashTable *attributes;
+};
+
+struct _AtspiAccessibleReadingMaterial
+{
+ AtspiAccessible *parent;
+ AtspiAccessible *described_by_accessible;
+ GHashTable *attributes;
+ AtspiRole role;
+ AtspiRole parent_role;
+ char *name;
+ char *labeled_by_name;
+ char *text_interface_name;
+ char *localized_role_name;
+ char *description;
+ gdouble value;
+ gdouble increment;
+ gdouble lower;
+ gdouble upper;
+ gint64 states;
+ gint64 parent_states;
+ gint child_count;
+ gint index_in_parent;
+ gint list_children_count;
+ gint first_selected_child_index;
+ gint parent_child_count;
+ gint parent_selected_child_count;
+ gboolean is_selected_in_parent;
+ gboolean has_checkbox_child;
+};
+
struct _AtspiAccessible
{
AtspiObject parent;
AtspiObjectClass parent_class;
};
-GType atspi_accessible_get_type (void);
+GType atspi_accessible_get_type (void);
AtspiAccessible *
_atspi_accessible_new (AtspiApplication *app, const gchar *path);
gchar * atspi_accessible_get_description (AtspiAccessible *obj, GError **error);
+gchar * atspi_accessible_get_path (AtspiAccessible *obj, GError **error);
+
+gchar * atspi_accessible_get_bus_name (AtspiAccessible *obj, GError **error);
+
+gchar * atspi_accessible_get_unique_id (AtspiAccessible *obj, GError **error);
+
+AtspiAccessible *atspi_accessible_get_navigable_at_point (AtspiAccessible *root, gint x, gint y, AtspiCoordType ctype, GError **error);
+
+AtspiAccessible *atspi_accessible_get_neighbor (AtspiAccessible *root, AtspiAccessible *start, AtspiNeighborSearchDirection direction, GError **error);
+
+AtspiAccessibleReadingMaterial *atspi_accessible_get_reading_material (AtspiAccessible *obj, GError **error);
+
+AtspiAccessibleDefaultLabelInfo *atspi_accessible_get_default_label_info (AtspiAccessible *obj, GError **error);
+
AtspiAccessible * atspi_accessible_get_parent (AtspiAccessible *obj, GError **error);
gint atspi_accessible_get_child_count (AtspiAccessible *obj, GError **error);
return retval;
}
+/**
+ * atspi_action_do_action_name:
+ * @obj: a pointer to the #AtspiAction to query.
+ * @name: a action name specifying which action to invoke.
+ *
+ * Invoke the action indicated by name.
+ *
+ * Returns: #TRUE if the action is successfully invoked, otherwise #FALSE.
+ **/
+gboolean
+atspi_action_do_action_name (AtspiAction *obj, const gchar *name, GError **error)
+{
+ const char *action_name = name;
+ dbus_bool_t retval = FALSE;
+
+ g_return_val_if_fail (obj != NULL, FALSE);
+
+ _atspi_dbus_call (obj, atspi_interface_action, "DoActionName", error, "s=>b", action_name, &retval);
+
+ return retval;
+}
+
static void
atspi_action_base_init (AtspiAction *klass)
{
gchar * atspi_action_get_localized_name (AtspiAction *obj, gint i, GError **error);
gboolean atspi_action_do_action (AtspiAction *obj, gint i, GError **error);
+gboolean atspi_action_do_action_name (AtspiAction *obj, const gchar *name, GError **error);
#ifndef ATSPI_DISABLE_DEPRECATED
gchar * atspi_action_get_description (AtspiAction *obj, gint i, GError **error);
return_accessibles (DBusMessage *message)
{
DBusMessageIter iter, iter_array;
- GArray *ret = g_array_new (TRUE, TRUE, sizeof (AtspiAccessible *));
+ GArray *ret;
_ATSPI_DBUS_CHECK_SIG (message, "a(so)", NULL, NULL);
+ ret = g_array_new (TRUE, TRUE, sizeof (AtspiAccessible *));
+
dbus_message_iter_init (message, &iter);
dbus_message_iter_recurse (&iter, &iter_array);
return _atspi_dbus_return_accessible_from_message (reply);
}
+
/**
* atspi_component_get_extents:
* @obj: a pointer to the #AtspiComponent to query.
* atspi_component_get_layer:
* @obj: a pointer to the #AtspiComponent to query.
*
- * Queries which layer the component is painted into, to help determine its
+ * Queries which layer the component is painted into, to help determine its
* visibility in terms of stacking order.
*
* Returns: the #AtspiComponentLayer into which this component is painted.
* Queries the z stacking order of a component which is in the MDI or window
* layer. (Bigger z-order numbers mean nearer the top)
*
- * Returns: a #gshort indicating the stacking order of the component
+ * Returns: a #gshort indicating the stacking order of the component
* in the MDI layer, or -1 if the component is not in the MDI layer.
**/
gshort
}
/**
+ * atspi_component_grab_highlight:
+ * @obj: a pointer to the #AtspiComponent on which to operate.
+ *
+ * Attempts to set highlight to the specified
+ * #AtspiComponent.
+ *
+ * Returns: #TRUE if successful, #FALSE otherwise.
+ *
+ **/
+gboolean
+atspi_component_grab_highlight (AtspiComponent *obj, GError **error)
+{
+ dbus_bool_t retval = FALSE;
+
+ _atspi_dbus_call (obj, atspi_interface_component, "GrabHighlight", error, "=>b", &retval);
+
+ return retval;
+}
+
+/**
+ * atspi_component_clear_highlight:
+ * @obj: a pointer to the #AtspiComponent on which to operate.
+ *
+ * Attempts to clear highlight on the specified
+ * #AtspiComponent.
+ *
+ * Returns: #TRUE if successful, #FALSE otherwise.
+ *
+ **/
+gboolean
+atspi_component_clear_highlight (AtspiComponent *obj, GError **error)
+{
+ dbus_bool_t retval = FALSE;
+
+ _atspi_dbus_call (obj, atspi_interface_component, "ClearHighlight", error, "=>b", &retval);
+
+ return retval;
+}
+
+/**
* atspi_component_get_alpha:
* @obj: The #AtspiComponent to be queried.
*
* Gets the opacity/alpha value of a component, if alpha blending is in use.
*
- * Returns: the opacity value of a component, as a #gdouble between 0.0 and 1.0.
+ * Returns: the opacity value of a component, as a #gdouble between 0.0 and 1.0.
**/
-gdouble
+gdouble
atspi_component_get_alpha (AtspiComponent *obj, GError **error)
{
double retval = 1;
return ret;
}
+/**
+ * atspi_component_get_highlight_index
+ * @obj: a pointer to the #AtspiComponent to query.
+ *
+ * Returns: highlight index of object if (>0), 0 if highlight index is not set
+ * or -1 if an error occured.
+ **/
+int
+atspi_component_get_highlight_index (AtspiComponent *obj, GError **error)
+{
+ gint ret = -1;
+ g_return_val_if_fail (obj != NULL, -1);
+ _atspi_dbus_get_property (obj, atspi_interface_component,
+ "HighlightIndex", error, "i", &ret);
+ return ret;
+}
+
static void
atspi_component_base_init (AtspiComponent *klass)
{
*
* Copyright 2002 Ximian, Inc.
* 2002 Sun Microsystems Inc.
- *
+ *
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
/**
* ATSPI_TYPE_RECT:
- *
+ *
* The #GType for a boxed type holding a #AtspiRect.
*/
#define ATSPI_TYPE_RECT (atspi_rect_get_type ())
/**
* ATSPI_TYPE_POINT:
- *
+ *
* The #GType for a boxed type holding a #AtspiPoint.
*/
#define ATSPI_TYPE_POINT (atspi_point_get_type ())
gboolean atspi_component_set_size (AtspiComponent *obj, gint width, gint height, GError **error);
+gboolean atspi_component_grab_highlight (AtspiComponent *obj, GError **error);
+
+gboolean atspi_component_clear_highlight (AtspiComponent *obj, GError **error);
+
+int atspi_component_get_highlight_index(AtspiComponent *obj, GError **error);
+
G_END_DECLS
#endif /* _ATSPI_COMPONENT_H_ */
/**
* AtspiLocaleType:
* @ATSPI_LOCALE_TYPE_MESSAGES: For localizable natural-language messages.
- * @ATSPI_LOCALE_TYPE_COLLATE: For regular expression matching and string
- * collation.
- * @ATSPI_LOCALE_TYPE_CTYPE: For regular expression matching, character
- * classification, conversion, case-sensitive comparison, and wide character
- * functions.
+ * @ATSPI_LOCALE_TYPE_COLLATE: For regular expression matching and string
+ * collation.
+ * @ATSPI_LOCALE_TYPE_CTYPE: For regular expression matching, character
+ * classification, conversion, case-sensitive comparison, and wide character
+ * functions.
* @ATSPI_LOCALE_TYPE_MONETARY: For monetary formatting.
- * @ATSPI_LOCALE_TYPE_NUMERIC: For number formatting (such as the decimal
+ * @ATSPI_LOCALE_TYPE_NUMERIC: For number formatting (such as the decimal
* point and the thousands separator).
* @ATSPI_LOCALE_TYPE_TIME: For time and date formatting.
*
/**
* AtspiCoordType:
* @ATSPI_COORD_TYPE_SCREEN: Specifies xy coordinates relative to the screen.
- * @ATSPI_COORD_TYPE_WINDOW: Specifies xy coordinates relative to the widget's
+ * @ATSPI_COORD_TYPE_WINDOW: Specifies xy coordinates relative to the widget's
* top-level window.
*
* Enumeration used by #AtspiComponent, #AtspiImage, and #AtspiText interfaces
ATSPI_COORD_TYPE_WINDOW,
} AtspiCoordType;
+typedef enum {
+ ATSPI_NEIGHBOR_SEARCH_FORWARD = 1,
+ ATSPI_NEIGHBOR_SEARCH_BACKWARD = 2,
+} AtspiNeighborSearchDirection;
+
/**
* ATSPI_COORD_TYPE_COUNT:
*
/**
* AtspiCollectionMatchType:
- * @ATSPI_Collection_MATCH_INVALID: Indicates an error condition or
+ * @ATSPI_Collection_MATCH_INVALID: Indicates an error condition or
* uninitialized value.
* @ATSPI_Collection_MATCH_ALL: #TRUE if all of the criteria are met.
* @ATSPI_Collection_MATCH_ANY: #TRUE if any of the criteria are met.
* @ATSPI_Collection_MATCH_NONE: #TRUE if none of the criteria are met.
* @ATSPI_Collection_MATCH_EMPTY: Same as @ATSPI_Collection_MATCH_ALL if
- * the criteria is non-empty; for empty criteria this rule requires returned
- * value to also have empty set.
+ * the criteria is non-empty; for empty criteria this rule requires returned
+ * value to also have empty set.
* @ATSPI_Collection_MATCH_LAST_DEFINED: Used only to determine the end of the
* enumeration.
*
* UI #AtspiComponent containers.
* @ATSPI_LAYER_WIDGET: The layer in which the majority of ordinary
* 'foreground' widgets reside.
- * @ATSPI_LAYER_MDI: A special layer between @ATSPI_LAYER_CANVAS and
- * @ATSPI_LAYER_WIDGET, in which the 'pseudo windows' (e.g. the MDI frames)
- * reside. See #atspi_component_get_mdi_z_order.
+ * @ATSPI_LAYER_MDI: A special layer between @ATSPI_LAYER_CANVAS and
+ * @ATSPI_LAYER_WIDGET, in which the 'pseudo windows' (e.g. the MDI frames)
+ * reside. See #atspi_component_get_mdi_z_order.
* @ATSPI_LAYER_POPUP: A layer for popup window content, above
* @ATSPI_LAYER_WIDGET.
* @ATSPI_LAYER_OVERLAY: The topmost layer.
* @ATSPI_LAYER_LAST_DEFINED: Used only to determine the end of the
* enumeration.
*
- * The #AtspiComponentLayer of an #AtspiComponent instance indicates its
- * relative stacking order with respect to the onscreen visual representation
- * of the UI. #AtspiComponentLayer, in combination with #AtspiComponent bounds
- * information, can be used to compute the visibility of all or part of a
- * component. This is important in programmatic determination of
- * region-of-interest for magnification, and in
+ * The #AtspiComponentLayer of an #AtspiComponent instance indicates its
+ * relative stacking order with respect to the onscreen visual representation
+ * of the UI. #AtspiComponentLayer, in combination with #AtspiComponent bounds
+ * information, can be used to compute the visibility of all or part of a
+ * component. This is important in programmatic determination of
+ * region-of-interest for magnification, and in
* flat screen review models of the screen, as well as
- * for other uses. Objects residing in two of the #AtspiComponentLayer
- * categories support further z-ordering information, with respect to their
- * peers in the same layer: namely, @ATSPI_LAYER_WINDOW and
- * @ATSPI_LAYER_MDI. Relative stacking order for other objects within the
- * same layer is not available; the recommended heuristic is
- * first child paints first. In other words, assume that the
- * first siblings in the child list are subject to being overpainted by later
+ * for other uses. Objects residing in two of the #AtspiComponentLayer
+ * categories support further z-ordering information, with respect to their
+ * peers in the same layer: namely, @ATSPI_LAYER_WINDOW and
+ * @ATSPI_LAYER_MDI. Relative stacking order for other objects within the
+ * same layer is not available; the recommended heuristic is
+ * first child paints first. In other words, assume that the
+ * first siblings in the child list are subject to being overpainted by later
* siblings if their bounds intersect. The order of layers, from bottom to top,
* is: @ATSPI_LAYER_BACKGROUND, @ATSPI_LAYER_WINDOW, @ATSPI_LAYER_MDI,
- * @ATSPI_LAYER_CANVAS, @ATSPI_LAYER_WIDGET, @ATSPI_LAYER_POPUP, and
+ * @ATSPI_LAYER_CANVAS, @ATSPI_LAYER_WIDGET, @ATSPI_LAYER_POPUP, and
* @ATSPI_LAYER_OVERLAY.
*
*/
/**
* AtspiTextBoundaryType:
- * @ATSPI_TEXT_BOUNDARY_CHAR: An #AtspiText instance is bounded by this
- * character only. Start and end offsets differ by one, by definition,
+ * @ATSPI_TEXT_BOUNDARY_CHAR: An #AtspiText instance is bounded by this
+ * character only. Start and end offsets differ by one, by definition,
* for this value.
* @ATSPI_TEXT_BOUNDARY_WORD_START: Boundary condition is start of a word; i.e.
* range is from start of one word to the start of another word.
* @ATSPI_TEXT_BOUNDARY_WORD_END: Boundary condition is the end of a word; i.e.
* range is from the end of one word to the end of another. Some locales
* may not distinguish between words and characters or glyphs. In particular,
- * those locales which use wholly or partially ideographic character sets.
+ * those locales which use wholly or partially ideographic character sets.
* In these cases, characters may be returned in lieu of multi-character
* substrings.
* @ATSPI_TEXT_BOUNDARY_SENTENCE_START: Boundary condition is start of a
* generally means that an end-of-line character will appear at the end of
* the range.
* @ATSPI_TEXT_BOUNDARY_LINE_END: Boundary condition is the end of a line; i.e.
- * range is from start of one line to the start of another. This generally
+ * range is from start of one line to the start of another. This generally
* means that an end-of-line character will be the first character of the
* range.
*
/**
* AtspiStateType:
- * @ATSPI_STATE_INVALID: Indicates an invalid state - probably an error
+ * @ATSPI_STATE_INVALID: Indicates an invalid state - probably an error
* condition.
* @ATSPI_STATE_ACTIVE: Indicates a window is currently the active window, or
* an object is the active subelement within a container or table.
* @ATSPI_STATE_ENABLED: Indicates that this object is enabled, i.e. that it
* currently reflects some application state. Objects that are "greyed out"
* may lack this state, and may lack the @ATSPI_STATE_SENSITIVE if direct
- * user interaction cannot cause them to acquire @ATSPI_STATE_ENABLED.
+ * user interaction cannot cause them to acquire @ATSPI_STATE_ENABLED.
* See @ATSPI_STATE_SENSITIVE.
* @ATSPI_STATE_EXPANDABLE: Indicates this object allows progressive
* disclosure of its children.
* children that has been selected.
* @ATSPI_STATE_SENSITIVE: Indicates this object is sensitive, e.g. to user
* interaction. @ATSPI_STATE_SENSITIVE usually accompanies.
- * @ATSPI_STATE_ENABLED for user-actionable controls, but may be found in the
- * absence of @ATSPI_STATE_ENABLED if the current visible state of the control
+ * @ATSPI_STATE_ENABLED for user-actionable controls, but may be found in the
+ * absence of @ATSPI_STATE_ENABLED if the current visible state of the control
* is "disconnected" from the application state. In such cases, direct user
- * interaction can often result in the object gaining @ATSPI_STATE_SENSITIVE,
+ * interaction can often result in the object gaining @ATSPI_STATE_SENSITIVE,
* for instance if a user makes an explicit selection using an object whose
* current state is ambiguous or undefined. See @ATSPI_STATE_ENABLED,
* @ATSPI_STATE_INDETERMINATE.
* single line of text.
* @ATSPI_STATE_STALE: Indicates that the information returned for this object
* may no longer be synchronized with the application state. This can occur
- * if the object has @ATSPI_STATE_TRANSIENT, and can also occur towards the
+ * if the object has @ATSPI_STATE_TRANSIENT, and can also occur towards the
* end of the object peer's lifecycle.
* @ATSPI_STATE_TRANSIENT: Indicates this object is transient.
* @ATSPI_STATE_VERTICAL: Indicates the orientation of this object is vertical;
* for example this state may appear on such objects as scrollbars, text
* objects (with vertical text flow), separators, etc.
* @ATSPI_STATE_VISIBLE: Indicates this object is visible, e.g. has been
- * explicitly marked for exposure to the user. @ATSPI_STATE_VISIBLE is no
- * guarantee that the object is actually unobscured on the screen, only that
- * it is 'potentially' visible, barring obstruction, being scrolled or clipped
- * out of the field of view, or having an ancestor container that has not yet
- * made visible. A widget is potentially onscreen if it has both
- * @ATSPI_STATE_VISIBLE and @ATSPI_STATE_SHOWING. The absence of
+ * explicitly marked for exposure to the user. @ATSPI_STATE_VISIBLE is no
+ * guarantee that the object is actually unobscured on the screen, only that
+ * it is 'potentially' visible, barring obstruction, being scrolled or clipped
+ * out of the field of view, or having an ancestor container that has not yet
+ * made visible. A widget is potentially onscreen if it has both
+ * @ATSPI_STATE_VISIBLE and @ATSPI_STATE_SHOWING. The absence of
* @ATSPI_STATE_VISIBLE and @ATSPI_STATE_SHOWING is
* semantically equivalent to saying that an object is 'hidden'.
* @ATSPI_STATE_MANAGES_DESCENDANTS: Indicates that "active-descendant-changed"
* in very large containers, like tables. The presence of
* @ATSPI_STATE_MANAGES_DESCENDANTS is an indication to the client that the
* children should not, and need not, be enumerated by the client.
- * Objects implementing this state are expected to provide relevant state
- * notifications to listening clients, for instance notifications of
- * visibility changes and activation of their contained child objects, without
+ * Objects implementing this state are expected to provide relevant state
+ * notifications to listening clients, for instance notifications of
+ * visibility changes and activation of their contained child objects, without
* the client having previously requested references to those children.
* @ATSPI_STATE_INDETERMINATE: Indicates that a check box or other boolean
* indicator is in a state other than checked or not checked. This
* usually means that the boolean value reflected or controlled by the
- * object does not apply consistently to the entire current context.
+ * object does not apply consistently to the entire current context.
* For example, a checkbox for the "Bold" attribute of text may have
* @ATSPI_STATE_INDETERMINATE if the currently selected text contains a mixture
* of weight attributes. In many cases interacting with a
* representation becomes static. Some applications, notably content viewers,
* may not be able to detect all kinds of animated content. Therefore the
* absence of this state should not be taken as
- * definitive evidence that the object's visual representation is
+ * definitive evidence that the object's visual representation is
* static; this state is advisory.
* @ATSPI_STATE_INVALID_ENTRY: This object has indicated an error condition
* due to failure of input validation. For instance, a form control may
* acquire this state in response to invalid or malformed user input.
* @ATSPI_STATE_SUPPORTS_AUTOCOMPLETION: This state indicates that the object
- * in question implements some form of typeahead or
+ * in question implements some form of typeahead or
* pre-selection behavior whereby entering the first character of one or more
* sub-elements causes those elements to scroll into view or become
* selected. Subsequent character input may narrow the selection further as
* question supports text selection. It should only be exposed on objects
* which implement the #AtspiText interface, in order to distinguish this state
* from @ATSPI_STATE_SELECTABLE, which infers that the object in question is a
- * selectable child of an object which implements #AtspiSelection. While
+ * selectable child of an object which implements #AtspiSelection. While
* similar, text selection and subelement selection are distinct operations.
* @ATSPI_STATE_IS_DEFAULT: This state indicates that the object in question is
* the 'default' interaction object in a dialog, i.e. the one that gets
* @ATSPI_STATE_READ_ONLY: Indicates that an object which is ENABLED and
* SENSITIVE has a value which can be read, but not modified, by the
* user. @Since: 2.16
+ * @ATSPI_STATE_HIGHLIGHTED: Indicates that an object which is HIGHLIGHTABLE
+ * has been graphically marked to assits visally impared users. Only one
+ * object per window can have ATSPI_STATE_HIGHLIGHTED state.
+ * @ATSPI_STATE_HIGHLIGHTABLE: Indicates that an object can be graphically
+ * marked to assist visially impaired users.
+ * user. @Since: 2.16
* @ATSPI_STATE_LAST_DEFINED: This value of the enumeration should not be used
* as a parameter, it indicates the number of items in the #AtspiStateType
* enumeration.
*
- *
- * Enumeration used by various interfaces indicating every possible state
+ *
+ * Enumeration used by various interfaces indicating every possible state
* an #AtspiAccesible object can assume.
*
**/
ATSPI_STATE_CHECKABLE,
ATSPI_STATE_HAS_POPUP,
ATSPI_STATE_READ_ONLY,
+ ATSPI_STATE_HIGHLIGHTED,
+ ATSPI_STATE_HIGHLIGHTABLE,
ATSPI_STATE_LAST_DEFINED,
} AtspiStateType;
/**
* AtspiEventType:
- * @ATSPI_KEY_PRESSED_EVENT: Indicates that a key on a keyboard device was
+ * @ATSPI_KEY_PRESSED_EVENT: Indicates that a key on a keyboard device was
* pressed.
- * @ATSPI_KEY_RELEASED_EVENT: Indicates that a key on a keyboard device was
+ * @ATSPI_KEY_RELEASED_EVENT: Indicates that a key on a keyboard device was
* released.
- * @ATSPI_BUTTON_PRESSED_EVENT: Indicates that a button on a non-keyboard
+ * @ATSPI_BUTTON_PRESSED_EVENT: Indicates that a button on a non-keyboard
* human interface device (HID) was pressed.
* @ATSPI_BUTTON_RELEASED_EVENT: Indicates that a button on a non-keyboard
* human interface device (HID) was released.
*
- * Enumeration used to specify the event types of interest to an
- * #AtspiEventListener, or
- * to identify the type of an event for which notification has been sent.
+ * Enumeration used to specify the event types of interest to an
+ * #AtspiEventListener, or
+ * to identify the type of an event for which notification has been sent.
*
**/
typedef enum {
* of a hardware keyboard key.
* @ATSPI_KEY_SYM: A symbolic key event is generated, without specifying a
* hardware key. Note: if the keysym is not present in the current keyboard
- * map, the #AtspiDeviceEventController instance has a limited ability to
- * generate such keysyms on-the-fly. Reliability of GenerateKeyboardEvent
- * calls using out-of-keymap keysyms will vary from system to system, and on
+ * map, the #AtspiDeviceEventController instance has a limited ability to
+ * generate such keysyms on-the-fly. Reliability of GenerateKeyboardEvent
+ * calls using out-of-keymap keysyms will vary from system to system, and on
* the number of different out-of-keymap keysyms being generated in quick
- * succession.
- * In practice this is rarely significant, since the keysyms of interest to
- * AT clients and keyboard emulators are usually part of the current keymap,
- * i.e., present on the system keyboard for the current locale (even if a
+ * succession.
+ * In practice this is rarely significant, since the keysyms of interest to
+ * AT clients and keyboard emulators are usually part of the current keymap,
+ * i.e., present on the system keyboard for the current locale (even if a
* physical hardware keyboard is not connected).
* @ATSPI_KEY_STRING: A string is converted to its equivalent keyboard events
* and emitted. If the string consists of complex characters or composed
* modifies the state, onscreen location, or other attributes of one or more
* target objects.
* @ATSPI_RELATION_CONTROLLED_BY: Object state, position, etc. is
- * modified/controlled by user interaction with one or more other objects.
+ * modified/controlled by user interaction with one or more other objects.
* For instance a viewport or scroll pane may be @ATSPI_RELATION_CONTROLLED_BY
* scrollbars.
* @ATSPI_RELATION_MEMBER_OF: Object has a grouping relationship (e.g. 'same
* object which is not the 'next sibling' in the accessibility hierarchy.
* @ATSPI_RELATION_FLOWS_FROM: Reciprocal of @ATSPI_RELATION_FLOWS_TO.
* @ATSPI_RELATION_SUBWINDOW_OF: Object is visually and semantically considered
- * a subwindow of another object, even though it is not the object's child.
+ * a subwindow of another object, even though it is not the object's child.
* Useful when dealing with embedded applications and other cases where the
* widget hierarchy does not map cleanly to the onscreen presentation.
- * @ATSPI_RELATION_EMBEDS: Similar to @ATSPI_RELATION_SUBWINDOW_OF, but
+ * @ATSPI_RELATION_EMBEDS: Similar to @ATSPI_RELATION_SUBWINDOW_OF, but
* specifically used for cross-process embedding.
* @ATSPI_RELATION_EMBEDDED_BY: Reciprocal of @ATSPI_RELATION_EMBEDS. Used to
* denote content rendered by embedded renderers that live in a separate process
* @ATSPI_RELATION_POPUP_FOR: Denotes that the object is a transient window or
* frame associated with another onscreen object. Similar to @ATSPI_TOOLTIP_FOR,
* but more general. Useful for windows which are technically toplevels
- * but which, for one or more reasons, do not explicitly cause their
+ * but which, for one or more reasons, do not explicitly cause their
* associated window to lose 'window focus'. Creation of an @ATSPI_ROLE_WINDOW
- * object with the @ATSPI_RELATION_POPUP_FOR relation usually requires
+ * object with the @ATSPI_RELATION_POPUP_FOR relation usually requires
* some presentation action on the part
* of assistive technology clients, even though the previous toplevel
* @ATSPI_ROLE_FRAME object may still be the active window.
* Indicates that this object contains an error message describing an invalid
* condition in the target object(s). @Since: 2.26.
* @ATSPI_RELATION_LAST_DEFINED: Do not use as a parameter value, used to
- * determine the size of the enumeration.
+ * determine the size of the enumeration.
*
- * #AtspiRelationType specifies a relationship between objects
+ * #AtspiRelationType specifies a relationship between objects
* (possibly one-to-many
* or many-to-one) outside of the normal parent/child hierarchical
* relationship. It allows better semantic identification of how objects
- * are associated with one another. For instance the
+ * are associated with one another. For instance the
* @ATSPI_RELATION_LABELLED_BY
* relationship may be used to identify labelling information that should
* accompany the accessible name property when presenting an object's content or
- * identity to the end user. Similarly,
+ * identity to the end user. Similarly,
* @ATSPI_RELATION_CONTROLLER_FOR can be used
* to further specify the context in which a valuator is useful, and/or the
* other UI components which are directly effected by user interactions with
* the valuator. Common examples include association of scrollbars with the
* viewport or panel which they control.
*
- *
+ *
* Enumeration used to specify
* the type of relation encapsulated in an #AtspiRelation object.
*
* etc.
* @ATSPI_ROLE_GLASS_PANE: A pane that is guaranteed to be painted on top of
* all panes beneath it.
- * @ATSPI_ROLE_HTML_CONTAINER: A document container for HTML, whose children
+ * @ATSPI_ROLE_HTML_CONTAINER: A document container for HTML, whose children
* represent the document content.
* @ATSPI_ROLE_ICON: A small fixed size picture, typically used to decorate
* components.
* @ATSPI_ROLE_SCROLL_PANE: An object that allows a user to incrementally view
* a large amount of information. @ATSPI_ROLE_SCROLL_PANE objects are usually
* accompanied by @ATSPI_ROLE_SCROLL_BAR controllers, on which the
- * @ATSPI_RELATION_CONTROLLER_FOR and @ATSPI_RELATION_CONTROLLED_BY
+ * @ATSPI_RELATION_CONTROLLER_FOR and @ATSPI_RELATION_CONTROLLED_BY
* reciprocal relations are set. See #atspi_get_relation_set.
* @ATSPI_ROLE_SEPARATOR: An object usually contained in a menu to provide a
* visible and logical separation of the contents in a menu.
* range.
* @ATSPI_ROLE_SPIN_BUTTON: An object which allows one of a set of choices to
* be selected, and which displays the current choice. Unlike
- * @ATSPI_ROLE_SCROLL_BAR, @ATSPI_ROLE_SLIDER objects need not control
+ * @ATSPI_ROLE_SCROLL_BAR, @ATSPI_ROLE_SLIDER objects need not control
* 'viewport'-like objects.
* @ATSPI_ROLE_SPLIT_PANE: A specialized panel that presents two other panels
* at the same time.
* @ATSPI_ROLE_TABLE: An object used to repesent information in terms of rows
* and columns.
* @ATSPI_ROLE_TABLE_CELL: A 'cell' or discrete child within a Table. Note:
- * Table cells need not have @ATSPI_ROLE_TABLE_CELL, other
+ * Table cells need not have @ATSPI_ROLE_TABLE_CELL, other
* #AtspiRoleType values are valid as well.
* @ATSPI_ROLE_TABLE_COLUMN_HEADER: An object which labels a particular column
* in an #AtspiTable.
* user.
* @ATSPI_ROLE_TREE_TABLE: An object that presents both tabular and
* hierarchical info to the user.
- * @ATSPI_ROLE_UNKNOWN: The object contains some #AtspiAccessible information,
+ * @ATSPI_ROLE_UNKNOWN: The object contains some #AtspiAccessible information,
* but its role is not known.
* @ATSPI_ROLE_VIEWPORT: An object usually used in a scroll pane, or to
* otherwise clip a larger object or content renderer to a specific
* @ATSPI_ROLE_FOOTER: An object that serves as a document footer.
* @ATSPI_ROLE_PARAGRAPH: An object which is contains a single paragraph of
* text content. See also @ATSPI_ROLE_TEXT.
- * @ATSPI_ROLE_RULER: An object which describes margins and tab stops, etc.
- * for text objects which it controls (should have
+ * @ATSPI_ROLE_RULER: An object which describes margins and tab stops, etc.
+ * for text objects which it controls (should have
* @ATSPI_RELATION_CONTROLLER_FOR relation to such).
* @ATSPI_ROLE_APPLICATION: An object corresponding to the toplevel accessible
- * of an application, which may contain @ATSPI_ROLE_FRAME objects or other
+ * of an application, which may contain @ATSPI_ROLE_FRAME objects or other
* accessible objects. Children of #AccessibleDesktop objects are generally
* @ATSPI_ROLE_APPLICATION objects.
* @ATSPI_ROLE_AUTOCOMPLETE: The object is a dialog or list containing items
* and for embedding of out-of-process component, "panel applets", etc.
* @ATSPI_ROLE_ENTRY: The object is a component whose textual content may be
* entered or modified by the user, provided @ATSPI_STATE_EDITABLE is present.
- * A readonly @ATSPI_ROLE_ENTRY object (i.e. where @ATSPI_STATE_EDITABLE is
- * not present) implies a read-only 'text field' in a form, as opposed to a
+ * A readonly @ATSPI_ROLE_ENTRY object (i.e. where @ATSPI_STATE_EDITABLE is
+ * not present) implies a read-only 'text field' in a form, as opposed to a
* title, label, or caption.
* @ATSPI_ROLE_CHART: The object is a graphical depiction of quantitative data.
* It may contain multiple subelements whose attributes and/or description
* may be queried to obtain both the quantitative data and information about
- * how the data is being presented. The @ATSPI_LABELLED_BY relation is
+ * how the data is being presented. The @ATSPI_LABELLED_BY relation is
* particularly important in interpreting objects of this type, as is the
* accessible description property. See @ATSPI_ROLE_CAPTION.
* @ATSPI_ROLE_CAPTION: The object contains descriptive information, usually
* contains a view of document content. #AtspiDocument frames may occur within
* another #AtspiDocument instance, in which case the second document may be
* said to be embedded in the containing instance. HTML frames are often
- * ATSPI_ROLE_DOCUMENT_FRAME: Either this object, or a singleton descendant,
+ * ATSPI_ROLE_DOCUMENT_FRAME: Either this object, or a singleton descendant,
* should implement the #AtspiDocument interface.
* @ATSPI_ROLE_HEADING: The object serves as a heading for content which
* follows it in a document. The 'heading level' of the heading, if
* this role should be ignored by clients, if they are encountered at all.
* @ATSPI_ROLE_FORM: The object is a containing instance of document content
* which has within it components with which the user can interact in order
- * to input information; i.e. the object is a container for pushbuttons,
+ * to input information; i.e. the object is a container for pushbuttons,
* comboboxes, text input fields, and other 'GUI' components. @ATSPI_ROLE_FORM
* should not, in general, be used for toplevel GUI containers or dialogs,
* but should be reserved for 'GUI' containers which occur within document
* content, for instance within Web documents, presentations, or text
- * documents. Unlike other GUI containers and dialogs which occur inside
+ * documents. Unlike other GUI containers and dialogs which occur inside
* application instances, @ATSPI_ROLE_FORM containers' components are
- * associated with the current document, rather than the current foreground
+ * associated with the current document, rather than the current foreground
* application or viewer instance.
- * @ATSPI_ROLE_LINK: The object is a hypertext anchor, i.e. a "link" in a
+ * @ATSPI_ROLE_LINK: The object is a hypertext anchor, i.e. a "link" in a
* hypertext document. Such objects are distinct from 'inline' content
* which may also use the #AtspiHypertext/#AtspiHyperlink interfacesto indicate
* the range/location within a text object where an inline or embedded object
* lies.
* @ATSPI_ROLE_INPUT_METHOD_WINDOW: The object is a window or similar viewport
- * which is used to allow composition or input of a 'complex character',
+ * which is used to allow composition or input of a 'complex character',
* in other words it is an "input method window".
* @ATSPI_ROLE_TABLE_ROW: A row in a table.
* @ATSPI_ROLE_TREE_ITEM: An object that represents an element of a tree.
* @ATSPI_ROLE_INFO_BAR: An object designed to present a message to the user
* within an existing window.
* @ATSPI_ROLE_LEVEL_BAR: A bar that serves as a level indicator to, for
- * instance, show the strength of a password or the state of a battery.
+ * instance, show the strength of a password or the state of a battery.
* Since: 2.8
*@ATSPI_ROLE_TITLE_BAR: A bar that serves as the title of a window or a
* dialog. @Since: 2.12
*/
#define ATSPI_ROLE_COUNT (125+1)
+/**
+ * AtspiMoveOutedType: The type of signal that occurs when an object outted the screen.
+ * @ATSPI_MOVE_OUTED_TOP_LEFT: Object has outted top or left of the screen.
+ * @ATSPI_MOVE_OUTED_BOTTOM_RIGHT: Object has outted bottom or right of the screen.
+ **/
+
+typedef enum {
+ ATSPI_MOVE_OUTED_NULL,
+ ATSPI_MOVE_OUTED_TOP_LEFT,
+ ATSPI_MOVE_OUTED_BOTTOM_RIGHT,
+ ATSPI_MOVE_OUTED_LAST_DEFINDED
+} AtspiMoveOutedType;
+
+/**
+ * ATSPI_MOVE_OUTED_COUNT:
+ *
+ * One higher than the highest valid value of #AtspiScreenOuttedType.
+ **/
+#define ATSPI_MOVE_OUTED_COUNT (3+1)
+
typedef enum
{
ATSPI_CACHE_NONE = 0,
GPtrArray *matchrule_array;
gint i;
GList *l;
+ gboolean result = TRUE;
if (!convert_event_type_to_dbus (event_type, &category, &name, &detail, &matchrule_array))
{
atspi_path_registry,
atspi_interface_registry,
"DeregisterEvent");
- if (!message)
- return FALSE;
+ if (!message) {
+ result = FALSE;
+ break;
+ }
dbus_message_append_args (message, DBUS_TYPE_STRING, &event_type, DBUS_TYPE_INVALID);
reply = _atspi_dbus_send_with_reply_and_block (message, error);
if (reply)
for (i = 0; i < matchrule_array->len; i++)
g_free (g_ptr_array_index (matchrule_array, i));
g_ptr_array_free (matchrule_array, TRUE);
- return TRUE;
+ return result;
}
/**
return TRUE;
if (!event_detail)
- return (listener_detail ? FALSE : TRUE);
+ return FALSE;
return !(listener_detail [strcspn (listener_detail, ":")] == '\0'
? strncmp (listener_detail, event_detail,
memset (&e, 0, sizeof (e));
- if (category)
+ if (!category)
{
- category = g_utf8_strrchr (category, -1, '.');
- if (category == NULL)
- {
- // TODO: Error
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
- category++;
+ // TODO: Error
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
+
+ category = g_utf8_strrchr (category, -1, '.');
+ if (category == NULL)
+ {
+ // TODO: Error
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ category++;
+
dbus_message_iter_get_basic (&iter, &detail);
dbus_message_iter_next (&iter);
dbus_message_iter_get_basic (&iter, &detail1);
* Copyright 2002 Ximian, Inc.
* 2002 Sun Microsystems Inc.
* Copyright 2010, 2011 Novell, Inc.
- *
+ *
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
GHashTable *
_atspi_get_live_refs (void)
{
- if (!live_refs)
+ if (!live_refs)
{
live_refs = g_hash_table_new (g_direct_hash, g_direct_equal);
}
DBusMessage *message;
const char *address;
DBusPendingCall *new_pending;
+ dbus_bool_t result;
if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
{
"/org/a11y/atspi/cache",
atspi_interface_cache, "GetItems");
- dbus_connection_send_with_reply (app->bus, message, &new_pending, 2000);
+ result = dbus_connection_send_with_reply (app->bus, message, &new_pending, 2000);
dbus_message_unref (message);
- if (!new_pending)
+ if (!result || !new_pending)
return;
dbus_pending_call_set_notify (new_pending, handle_get_items, app, NULL);
}
char *bus_name_dup;
DBusMessage *message;
DBusPendingCall *pending = NULL;
+ dbus_bool_t result;
if (!app_hash)
{
message = dbus_message_new_method_call (bus_name, atspi_path_root,
atspi_interface_application, "GetApplicationBusAddress");
- dbus_connection_send_with_reply (app->bus, message, &pending, 2000);
+ result = dbus_connection_send_with_reply (app->bus, message, &pending, 2000);
dbus_message_unref (message);
- if (!pending)
+ if (!result || !pending)
{
g_hash_table_remove (app_hash, bus_name_dup);
return NULL;
return app;
}
-static AtspiAccessible *
+AtspiAccessible *
ref_accessible (const char *app_name, const char *path)
{
AtspiApplication *app;
else if (app_hash)
{
AtspiApplication *app = g_hash_table_lookup (app_hash, old);
- if (app && !strcmp (app->bus_name, old))
+ if (app && app->bus_name && !strcmp(app->bus_name, name))
g_object_run_dispose (G_OBJECT (app));
}
return DBUS_HANDLER_RESULT_HANDLED;
DBusMessageIter iter;
AtspiHyperlink *retval = NULL;
const char *signature;
-
+
if (!message)
return NULL;
*
* Connects to the accessibility registry and initializes the SPI.
*
- * Returns: 0 on success, 1 if already initialized, or an integer error code.
+ * Returns: 0 on success, 1 if already initialized, or an integer error code.
**/
int
atspi_init (void)
bus = atspi_get_a11y_bus ();
if (!bus)
return 2;
- dbus_bus_register (bus, NULL);
+ if (!dbus_bus_register (bus, NULL))
+ return 2;
atspi_dbus_connection_setup_with_g_main(bus, g_main_context_default());
dbus_connection_add_filter (bus, atspi_dbus_filter, NULL, NULL);
match = g_strdup_printf ("type='signal',interface='%s',member='AddAccessible'", atspi_interface_cache);
/**
* atspi_exit:
*
- * Disconnects from #AtspiRegistry instances and releases
+ * Disconnects from #AtspiRegistry instances and releases
* any floating resources. Call only once at exit.
*
* Returns: 0 if there were no leaks, otherwise other integer values.
DBusMessage *message;
gchar *bus_name_dup;
DBusPendingCall *pending = NULL;
+ dbus_bool_t result;
for (l = hung_processes; l; l = l->next)
if (!strcmp (l->data, bus_name))
return;
"Ping");
if (!message)
return;
- dbus_connection_send_with_reply (bus, message, &pending, -1);
+ result = dbus_connection_send_with_reply (bus, message, &pending, -1);
dbus_message_unref (message);
- if (!pending)
+ if (!result || !pending)
return;
bus_name_dup = g_strdup (bus_name);
hung_processes = g_slist_append (hung_processes, bus_name_dup);
const char *type, ...)
{
va_list args;
-
+ DBusMessage * result;
va_start (args, type);
- return _atspi_dbus_call_partial_va (obj, interface, method, error, type, args);
+ result = _atspi_dbus_call_partial_va (obj, interface, method, error, type, args);
+ va_end (args);
+ return result;
}
{
AtspiObject *aobj = ATSPI_OBJECT (obj);
DBusError err;
- DBusMessage *msg = NULL, *reply = NULL;
- DBusMessageIter iter;
- const char *p;
+ DBusMessage *msg = NULL, *reply = NULL;
+ DBusMessageIter iter;
+ const char *p;
dbus_error_init (&err);
process_deferred_messages ();
if (dbus_error_is_set (&err))
{
- /* TODO: Set gerror */
+ g_set_error_literal(error, ATSPI_ERROR, ATSPI_ERROR_IPC, err.message);
dbus_error_free (&err);
+ if (reply)
+ dbus_message_unref(reply);
+ return NULL;
}
-
- if (reply && dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR)
+ else if (reply && dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
{
const char *err_str = NULL;
dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &err_str, DBUS_TYPE_INVALID);
dbus_message_unref (reply);
return NULL;
}
-
return reply;
}
g_warning ("Could not open X display");
return NULL;
}
-
+
AT_SPI_BUS = XInternAtom (bridge_display, "AT_SPI_BUS", False);
XGetWindowProperty (bridge_display,
XDefaultRootWindow (bridge_display),
dbus_error_free (&error);
goto out;
}
-
+
{
const char *tmp_address;
if (!dbus_message_get_args (reply,
return NULL;
}
}
-
+
/* Simulate a weak ref on the bus */
dbus_connection_set_data (a11y_bus, a11y_dbus_slot, a11y_bus, a11y_bus_free);
g_value_set_boxed (val, &extents);
}
if (val)
- g_hash_table_insert (cache, g_strdup (key), val);
+ g_hash_table_insert (cache, g_strdup (key), val);
dbus_message_iter_next (&iter_dict);
}
atspi_set_main_context (GMainContext *cnx);
gchar * atspi_role_get_name (AtspiRole role);
+
+AtspiAccessible *ref_accessible(const char *app_name, const char *path);
+
G_END_DECLS
#endif /* _ATSPI_MISC_H_ */
GError **error)
{
GArray *d_key_set;
- gchar *path = _atspi_device_listener_get_path (listener);
+ gchar *path;
gint i;
dbus_uint32_t d_modmask = modmask;
dbus_uint32_t d_event_types = event_types;
{
return FALSE;
}
+ path = _atspi_device_listener_get_path (listener);
/* copy the keyval filter values from the C api into the DBind KeySet */
if (key_set)
{
gboolean retval = FALSE;
dbus_uint32_t d_event_types = event_types;
- gchar *path = _atspi_device_listener_get_path (listener);
+ gchar *path;
DBusError d_error;
dbus_error_init (&d_error);
{
return retval;
}
+ path = _atspi_device_listener_get_path (listener);
dbind_method_call_reentrant (_atspi_bus(), atspi_bus_registry, atspi_path_dec, atspi_interface_dec, "RegisterDeviceEventListener", &d_error, "ou=>b", path, d_event_types, &retval);
if (dbus_error_is_set (&d_error))
void *filter, GError **error)
{
dbus_uint32_t event_types = 0;
- gchar *path = _atspi_device_listener_get_path (listener);
+ gchar *path;
DBusError d_error;
dbus_error_init (&d_error);
{
return FALSE;
}
+ path = _atspi_device_listener_get_path (listener);
event_types |= (1 << ATSPI_BUTTON_PRESSED_EVENT);
event_types |= (1 << ATSPI_BUTTON_RELEASED_EVENT);
if (!value)
{
g_warning ("AT-SPI: Attempt to set unknown state '%s'", name);
+ return;
}
else
if (enabled)
typedef struct _AtspiTableCell AtspiTableCell;
typedef struct _AtspiText AtspiText;
typedef struct _AtspiValue AtspiValue;
+typedef struct _AtspiAccessibleReadingMaterial AtspiAccessibleReadingMaterial;
+typedef struct _AtspiAccessibleDefaultLabelInfo AtspiAccessibleDefaultLabelInfo;
typedef guint AtspiControllerEventMask;
at_spi_bus_launcher_CPPFLAGS = -DSYSCONFDIR=\"$(sysconfdir)\" \
-DDATADIR=\"$(datadir)\" \
-DDBUS_DAEMON=\"$(DBUS_DAEMON)\"
-at_spi_bus_launcher_CFLAGS = $(GIO_CFLAGS)
-at_spi_bus_launcher_LDADD = $(GIO_LIBS) $(X11_LIBS)
+at_spi_bus_launcher_CFLAGS = $(GIO_CFLAGS) $(APPSVC_CFLAGS) $(VCONF_CFLAGS) $(AUL_CFLAGS) -fPIE
+at_spi_bus_launcher_LDADD = $(GIO_LIBS) $(X11_LIBS) $(APPSVC_LIBS) $(VCONF_LIBS) $(AUL_LIBS)
+at_spi_bus_launcher_LDFLAGS = -pie
substitutions = "s,@libexecdir[@],$(libexecdir),"
<listen>unix:tmpdir=/tmp</listen>
- <policy context="default">
- <!-- Allow root to connect -->
- <allow user="root"/>
+ <policy user="owner">
<!-- Allow everything to be sent -->
<allow send_destination="*" eavesdrop="true"/>
<!-- Allow everything to be received -->
<!-- Allow anyone to own anything -->
<allow own="*"/>
</policy>
-
+
<limit name="max_incoming_bytes">1000000000</limit>
<limit name="max_outgoing_bytes">1000000000</limit>
<limit name="max_message_size">1000000000</limit>
#include <X11/Xatom.h>
#endif
+//TODO: move to vconf/vconf-internal-setting-keys.h?
+#define VCONFKEY_SETAPPL_ACCESSIBILITY_UNIVERSAL_SWITCH "db/setting/accessibility/universal-switch"
+
+#define APP_CONTROL_OPERATION_SCREEN_READ "http://tizen.org/appcontrol/operation/read_screen"
+#define APP_CONTROL_OPERATION_UNIVERSAL_SWITCH "http://tizen.org/appcontrol/operation/universal_switch"
+#include <appsvc.h>
+#include <vconf.h>
+
+//uncomment if you want debug
+//#ifndef TIZEN_ENGINEER_MODE
+//#define TIZEN_ENGINEER_MODE
+//#endif
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "ATSPI_BUS_LAUNCHER"
+
+#include <dlog.h>
+#include <aul.h>
+
+//uncomment this if you want log suring startup
+//seems like dlog is not working at startup time
+#define ATSPI_BUS_LAUNCHER_LOG_TO_FILE
+
+#ifdef ATSPI_BUS_LAUNCHER_LOG_TO_FILE
+FILE *log_file;
+#ifdef LOGD
+#undef LOGD
+#endif
+#define LOGD(arg...) do {if (log_file) {fprintf(log_file, ##arg);fprintf(log_file, "\n"); fflush(log_file);}} while(0)
+#endif
+
+static gboolean _launch_process_repeat_until_success(gpointer user_data);
+
typedef enum {
A11Y_BUS_STATE_IDLE = 0,
A11Y_BUS_STATE_READING_ADDRESS,
} A11yBusState;
typedef struct {
+ const char * name;
+ const char * app_control_operation;
+ const char * vconf_key;
+ int launch_repeats;
+ int pid;
+} A11yBusClient;
+
+typedef struct {
GMainLoop *loop;
gboolean launch_immediately;
gboolean a11y_enabled;
gboolean screen_reader_enabled;
+ GHashTable *client_watcher_id;
GDBusConnection *session_bus;
GSettings *a11y_schema;
GSettings *interface_schema;
+ A11yBusClient screen_reader;
+ A11yBusClient universal_switch;
+
GDBusProxy *client_proxy;
A11yBusState state;
+
/* -1 == error, 0 == pending, > 0 == running */
int a11y_bus_pid;
char *a11y_bus_address;
#ifdef __linux
#include <sys/prctl.h>
prctl (PR_SET_PDEATHSIG, 15);
-#endif
+#endif
}
/**
gpointer data)
{
A11yBusLauncher *app = data;
-
+
app->a11y_bus_pid = -1;
app->state = A11Y_BUS_STATE_ERROR;
if (app->a11y_launch_error_message == NULL)
app->a11y_launch_error_message = g_strdup_printf ("Bus stopped by signal %d", WSTOPSIG (status));
}
g_main_loop_quit (app->loop);
-}
+}
static gboolean
ensure_a11y_bus (A11yBusLauncher *app)
else
config_path = "--config-file="DATADIR"/defaults/at-spi2/accessibility.conf";
- argv[1] = config_path;
+ argv[1] = (char*)config_path;
if (pipe (app->pipefd) < 0)
g_error ("Failed to create pipe: %s", strerror (errno));
-
+
if (!g_spawn_async (NULL,
argv,
NULL,
app->state = A11Y_BUS_STATE_READING_ADDRESS;
app->a11y_bus_pid = pid;
- g_debug ("Launched a11y bus, child is %ld", (long) pid);
+ LOGD("Launched a11y bus, child is %ld", (long) pid);
if (!unix_read_all_fd_to_string (app->pipefd[0], addr_buf, sizeof (addr_buf)))
{
app->a11y_launch_error_message = g_strdup_printf ("Failed to read address: %s", strerror (errno));
/* Trim the trailing newline */
app->a11y_bus_address = g_strchomp (g_strdup (addr_buf));
- g_debug ("a11y bus address: %s", app->a11y_bus_address);
+ LOGD("a11y bus address: %s", app->a11y_bus_address);
#ifdef HAVE_X11
{
#endif
return TRUE;
-
+
error:
close (app->pipefd[0]);
close (app->pipefd[1]);
if (enabled == app->screen_reader_enabled)
return;
- /* If the screen reader is being enabled, we should enable accessibility
- * if it isn't enabled already */
- if (enabled)
- handle_a11y_enabled_change (app, enabled, notify_gsettings);
-
app->screen_reader_enabled = enabled;
if (notify_gsettings && app->a11y_schema)
&builder,
&invalidated_builder),
NULL);
-
g_variant_builder_clear (&builder);
g_variant_builder_clear (&invalidated_builder);
}
static gboolean
+is_client_connected(A11yBusLauncher *app)
+{
+ guint watchers = g_hash_table_size(app->client_watcher_id);
+ LOGD("clients connected: %d", watchers);
+ return watchers > 0;
+}
+
+static void
+remove_client_watch(A11yBusLauncher *app,
+ const gchar *sender)
+{
+ LOGD("Remove client watcher for %s", sender);
+ guint watcher_id = GPOINTER_TO_UINT(g_hash_table_lookup(app->client_watcher_id, sender));
+ if (watcher_id)
+ g_bus_unwatch_name(watcher_id);
+
+ g_hash_table_remove(app->client_watcher_id, sender);
+ if (!is_client_connected(app))
+ handle_a11y_enabled_change (app, FALSE, TRUE);
+}
+
+static void
+on_client_name_vanished (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ A11yBusLauncher *app = user_data;
+ remove_client_watch(app, name);
+}
+
+static void
+add_client_watch(A11yBusLauncher *app,
+ const gchar *sender)
+{
+ LOGD("Add client watcher for %s", sender);
+
+ if (g_hash_table_contains(app->client_watcher_id, sender))
+ {
+ LOGI("Watcher for %s already registered", sender);
+ return;
+ }
+
+ guint watcher_id = g_bus_watch_name(G_BUS_TYPE_SESSION,
+ sender,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ NULL,
+ on_client_name_vanished,
+ app,
+ NULL);
+
+ g_hash_table_insert(app->client_watcher_id, g_strdup(sender), GUINT_TO_POINTER(watcher_id));
+ handle_a11y_enabled_change (app, TRUE, TRUE);
+}
+
+static gboolean
handle_set_property (GDBusConnection *connection,
const gchar *sender,
const gchar *object_path,
A11yBusLauncher *app = user_data;
const gchar *type = g_variant_get_type_string (value);
gboolean enabled;
-
+
if (g_strcmp0 (type, "b") != 0)
{
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
if (g_strcmp0 (property_name, "IsEnabled") == 0)
{
- handle_a11y_enabled_change (app, enabled, TRUE);
+ if (enabled)
+ add_client_watch(app, sender);
+ else
+ remove_client_watch(app, sender);
return TRUE;
}
else if (g_strcmp0 (property_name, "ScreenReaderEnabled") == 0)
A11yBusLauncher *app = user_data;
GError *error;
guint registration_id;
-
+
if (connection == NULL)
{
g_main_loop_quit (app->loop);
gpointer data)
{
A11yBusLauncher *app = data;
-
+
g_main_loop_quit (app->loop);
return FALSE;
bridge_display = XOpenDisplay (NULL);
if (!bridge_display)
return FALSE;
-
+
AT_SPI_BUS = XInternAtom (bridge_display, "AT_SPI_BUS", False);
XGetWindowProperty (bridge_display,
XDefaultRootWindow (bridge_display),
gsettings_key_changed (GSettings *gsettings, const gchar *key, void *user_data)
{
gboolean new_val = g_settings_get_boolean (gsettings, key);
- A11yBusLauncher *app = user_data;
if (!strcmp (key, "toolkit-accessibility"))
handle_a11y_enabled_change (_global_app, new_val, FALSE);
handle_screen_reader_enabled_change (_global_app, new_val, FALSE);
}
+static int
+_process_dead_tracker (int pid, void *data)
+{
+ A11yBusLauncher *app = data;
+
+ if (app->screen_reader.pid > 0 && pid == app->screen_reader.pid)
+ {
+ LOGE("screen reader is dead, pid: %d, restarting", pid);
+ app->screen_reader.pid = 0;
+ g_timeout_add_seconds (2, _launch_process_repeat_until_success, &app->screen_reader);
+ }
+
+ if (app->universal_switch.pid > 0 && pid == app->universal_switch.pid)
+ {
+ LOGE("universal switch is dead, pid: %d, restarting", pid);
+ app->universal_switch.pid = 0;
+ g_timeout_add_seconds (2, _launch_process_repeat_until_success, &app->universal_switch);
+ }
+ return 0;
+}
+
+static void
+_register_process_dead_tracker ()
+{
+ if(_global_app->screen_reader.pid > 0 || _global_app->universal_switch.pid > 0) {
+ LOGD("registering process dead tracker");
+ aul_listen_app_dead_signal(_process_dead_tracker, _global_app);
+ } else {
+ LOGD("unregistering process dead tracker");
+ aul_listen_app_dead_signal(NULL, NULL);
+ }
+}
+
+
+static gboolean
+_launch_client(A11yBusClient *client, gboolean by_vconf_change)
+{
+ LOGD("Launching %s", client->name);
+
+ bundle *kb = NULL;
+ gboolean ret = FALSE;
+
+ kb = bundle_create();
+
+ if (kb == NULL)
+ {
+ LOGD("Can't create bundle");
+ return FALSE;
+ }
+
+ if (by_vconf_change)
+ {
+ if (bundle_add_str(kb, "by_vconf_change", "yes") != BUNDLE_ERROR_NONE)
+ {
+ LOGD("Can't add information to bundle");
+ }
+ }
+
+ int operation_error = appsvc_set_operation(kb, client->app_control_operation);
+ LOGD("appsvc_set_operation: %i", operation_error);
+
+ client->pid = appsvc_run_service(kb, 0, NULL, NULL);
+
+ if (client->pid > 0)
+ {
+ LOGD("Process launched with pid: %i", client->pid);
+ _register_process_dead_tracker();
+ ret = TRUE;
+ }
+ else
+ {
+ LOGD("Can't start %s - error code: %i", client->name, client->pid);
+ }
+
+ bundle_free(kb);
+ return ret;
+}
+
+static gboolean
+_launch_process_repeat_until_success(gpointer user_data) {
+ A11yBusClient *client = user_data;
+
+ if (client->launch_repeats > 100 || client->pid > 0)
+ {
+ //do not try anymore
+ return FALSE;
+ }
+
+ gboolean ret = _launch_client(client, FALSE);
+
+ if (ret)
+ {
+ //we managed to
+ client->launch_repeats = 0;
+ return FALSE;
+ }
+ client->launch_repeats++;
+ //try again
+ return TRUE;
+}
+
+static gboolean
+_terminate_process(int pid)
+{
+ int ret;
+ int ret_aul;
+ if (pid <= 0)
+ return FALSE;
+
+ int status = aul_app_get_status_bypid(pid);
+
+ if (status < 0)
+ {
+ LOGD("App with pid %d already terminated", pid);
+ return TRUE;
+ }
+
+ LOGD("terminate process with pid %d", pid);
+ ret_aul = aul_terminate_pid(pid);
+ if (ret_aul >= 0)
+ {
+ LOGD("Terminating with aul_terminate_pid: return is %d", ret_aul);
+ return TRUE;
+ }
+ else
+ LOGD("aul_terminate_pid failed: return is %d", ret_aul);
+
+ LOGD("Unable to terminate process using aul api. Sending SIGTERM signal");
+ ret = kill(pid, SIGTERM);
+ if (!ret)
+ {
+ return TRUE;
+ }
+
+ LOGD("Unable to terminate process: %d with api or signal.", pid);
+ return FALSE;
+}
+
+static gboolean
+_terminate_client(A11yBusClient *client)
+{
+ LOGD("Terminating %s", client->name);
+ int pid = client->pid;
+ client->pid = 0;
+ _register_process_dead_tracker();
+ gboolean ret = _terminate_process(pid);
+ return ret;
+}
+
+void vconf_client_cb(keynode_t *node, void *user_data)
+{
+ A11yBusClient *client = user_data;
+ int client_needed = vconf_keynode_get_bool(node);
+ LOGD("vconf_keynode_get_bool(node): %i", client_needed);
+ if (client_needed < 0)
+ return;
+
+ //check if process really exists (e.g didn't crash)
+ if (client->pid > 0)
+ {
+ int err = kill(client->pid,0);
+ //process doesn't exist
+ if (err == ESRCH)
+ client->pid = 0;
+ }
+
+ LOGD("client_needed: %i, client->pid: %i", client_needed, client->pid);
+ if (!client_needed && (client->pid > 0))
+ _terminate_client(client);
+ else if (client_needed && (client->pid <= 0))
+ _launch_client(client, TRUE);
+}
+
+
+static gboolean register_executable(A11yBusClient *client)
+{
+ gboolean client_needed = FALSE;
+
+ if(!client->vconf_key) {
+ LOGE("Vconf_key missing for client: %s \n", client->vconf_key);
+ return FALSE;
+ }
+
+ int ret = vconf_get_bool(client->vconf_key, &client_needed);
+ if (ret != 0)
+ {
+ LOGD("Could not read %s key value.\n", client->vconf_key);
+ return FALSE;
+ }
+ ret = vconf_notify_key_changed(client->vconf_key, vconf_client_cb, client);
+ if(ret != 0)
+ {
+ LOGD("Could not add information level callback\n");
+ return FALSE;
+ }
+
+ if (client_needed)
+ g_timeout_add_seconds(2,_launch_process_repeat_until_success, client);
+ return TRUE;
+}
+
int
main (int argc,
char **argv)
{
- GError *error = NULL;
- GMainLoop *loop;
- GDBusConnection *session_bus;
- int name_owner_id;
+#ifdef ATSPI_BUS_LAUNCHER_LOG_TO_FILE
+ log_file = fopen("/tmp/at-spi-bus-launcher.log", "a");
+#endif
+
+ LOGD("Starting atspi bus launcher");
gboolean a11y_set = FALSE;
gboolean screen_reader_set = FALSE;
gint i;
if (already_running ())
- return 0;
+ {
+ LOGD("atspi bus launcher is already running");
+ return 0;
+ }
_global_app = g_slice_new0 (A11yBusLauncher);
_global_app->loop = g_main_loop_new (NULL, FALSE);
+ _global_app->client_watcher_id = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+
+ _global_app->screen_reader.name = "screen-reader";
+ _global_app->screen_reader.app_control_operation = APP_CONTROL_OPERATION_SCREEN_READ;
+ _global_app->screen_reader.vconf_key = VCONFKEY_SETAPPL_ACCESSIBILITY_TTS;
+
+ _global_app->universal_switch.name = "universal-switch";
+ _global_app->universal_switch.app_control_operation = APP_CONTROL_OPERATION_UNIVERSAL_SWITCH;
+ _global_app->universal_switch.vconf_key = VCONFKEY_SETAPPL_ACCESSIBILITY_UNIVERSAL_SWITCH;
for (i = 1; i < argc; i++)
{
introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
g_assert (introspection_data != NULL);
- name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+ g_bus_own_name (G_BUS_TYPE_SESSION,
"org.a11y.Bus",
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
on_bus_acquired,
_global_app,
NULL);
+ register_executable (&_global_app->screen_reader);
+ register_executable (&_global_app->universal_switch);
+
g_main_loop_run (_global_app->loop);
if (_global_app->a11y_bus_pid > 0)
kill (_global_app->a11y_bus_pid, SIGTERM);
- /* Clear the X property if our bus is gone; in the case where e.g.
+ /* Clear the X property if our bus is gone; in the case where e.g.
* GDM is launching a login on an X server it was using before,
* we don't want early login processes to pick up the stale address.
*/
AC_SUBST(GIO_LIBS)
AC_SUBST(GIO_CFLAGS)
+PKG_CHECK_MODULES(APPSVC, [appsvc])
+AC_SUBST(APPSVC_LIBS)
+AC_SUBST(APPSVC_CFLAGS)
+
+PKG_CHECK_MODULES(VCONF, [vconf])
+AC_SUBST(VCONF_LIBS)
+AC_SUBST(VCONF_CFLAGS)
+
+PKG_CHECK_MODULES(AUL, [aul])
+AC_SUBST(AUL_LIBS)
+AC_SUBST(AUL_CFLAGS)
# --------------------------------------------------------------------
# Find DL functionality
signal TextAttributesChanged {Event event;}
signal TextCaretMoved {Event event;}
signal AttributesChanged {Event event;}
+ signal MoveOuted {Event event;}
}
interface Window {
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_"/>
+ </request>
+</manifest>
--- /dev/null
+%bcond_with x
+
+Name: at-spi2-core
+Version: 2.26.1
+Release: 0
+Summary: Assistive Technology Service Provider Interface - D-Bus based implementation
+License: LGPL-2.0+
+Group: System/Libraries
+Url: http://www.gnome.org/
+Source: http://ftp.gnome.org/pub/GNOME/sources/at-spi2-core/2.26/%{name}-%{version}.tar.xz
+Source1001: %{name}.manifest
+Requires: dbus
+BuildRequires: python-devel
+BuildRequires: python-xml
+BuildRequires: intltool
+BuildRequires: dbus-devel
+BuildRequires: glib2-devel
+BuildRequires: gettext
+BuildRequires: gtk-doc
+%if %{with x}
+BuildRequires: libX11-devel
+BuildRequires: libXtst-devel
+BuildRequires: libXi-devel
+%endif
+BuildRequires: pkgconfig(vconf)
+BuildRequires: pkgconfig(appsvc)
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(aul)
+BuildRequires: gobject-introspection
+
+%description
+AT-SPI is a general interface for applications to make use of the
+accessibility toolkit. This version is based on dbus.
+
+This package contains the AT-SPI registry daemon. It provides a
+mechanism for all assistive technologies to discover and interact
+with applications running on the desktop.
+
+%package -n libatspi0
+Summary: An Accessibility ToolKit -- Library
+Group: System/Libraries
+
+%description -n libatspi0
+AT-SPI is a general interface for applications to make use of the
+accessibility toolkit. This version is based on dbus.
+
+%package -n typelib-1_0-Atspi-2_0
+Summary: An Accessibility ToolKit -- Introspection bindings
+Group: System/Libraries
+
+%description -n typelib-1_0-Atspi-2_0
+AT-SPI is a general interface for applications to make use of the
+accessibility toolkit. This version is based on dbus.
+
+This package provides the GObject Introspection bindings for the
+libatspi library.
+
+%package devel
+Summary: Include Files and Libraries mandatory for Development
+Group: Development/Libraries
+Requires: %{name} = %{version}
+Requires: libatspi0 = %{version}
+Requires: typelib-1_0-Atspi-2_0 = %{version}
+
+%description devel
+This package contains all necessary include files and libraries needed
+to develop applications that require these.
+
+%prep
+%setup -q
+cp %{SOURCE1001} .
+
+%build
+%autogen --libexecdir=%{_libexecdir}/at-spi2 \
+ --with-dbus-daemondir=%{_bindir} \
+%if !%{with x}
+ --disable-x11 \
+%endif
+ --disable-static
+%__make %{?_smp_flags}
+
+%install
+rm -rf %{buildroot}
+find %{buildroot} -name '*.la' -or -name '*.a' | xargs rm -f
+
+%make_install
+%find_lang %{name}
+
+%clean
+rm -fr %{buildroot}
+
+%post -n libatspi0 -p /sbin/ldconfig
+
+%postun -n libatspi0 -p /sbin/ldconfig
+
+%files -f %{name}.lang
+%manifest %{name}.manifest
+%defattr(-,root,root)
+%{_bindir}/at_spi2_tool
+
+%doc AUTHORS README
+%license COPYING
+%{_libexecdir}/at-spi2/at-spi-bus-launcher
+%{_libexecdir}/at-spi2/at-spi2-registryd
+%{_datadir}/defaults/at-spi2/accessibility.conf
+%{_sysconfdir}/xdg/autostart/at-spi-dbus-bus.desktop
+%{_datadir}/dbus-1/accessibility-services/org.a11y.atspi.Registry.service
+%{_datadir}/dbus-1/services/org.a11y.Bus.service
+%{_prefix}/lib/systemd/user/at-spi-dbus-bus.service
+%files -n libatspi0
+%manifest %{name}.manifest
+%defattr(-, root, root)
+%{_libdir}/libatspi.so.0*
+
+%files -n typelib-1_0-Atspi-2_0
+%manifest %{name}.manifest
+%defattr(-, root, root)
+
+%files devel
+%manifest %{name}.manifest
+%defattr(-, root, root)
+%{_includedir}/at-spi-2.0
+%{_libdir}/libatspi.so
+%{_libdir}/pkgconfig/atspi-2.pc
libexec_PROGRAMS = at-spi2-registryd
+at_spi2_registryd_LDFLAGS = -pie
at_spi2_registryd_CFLAGS = \
+ -fPIE \
$(GLIB_CFLAGS) \
$(GIO_CFLAGS) \
$(DBUS_CFLAGS) \
{
const char *dest = dbus_message_get_destination (message);
GSList *l;
+ dbus_bool_t result;
gchar *bus_name_dup;
dbus_message_ref (message);
dbus_pending_call_set_notify (pending, reset_hung_process, message,
"Ping");
if (!message)
return NULL;
- dbus_connection_send_with_reply (bus, message, &pending, -1);
+ result = dbus_connection_send_with_reply (bus, message, &pending, -1);
dbus_message_unref (message);
- if (!pending)
+ if (!result || !pending)
return NULL;
bus_name_dup = g_strdup (dest);
dbus_pending_call_set_notify (pending, reset_hung_process_from_ping,
Accessibility_KeyDefinition *kd = (Accessibility_KeyDefinition *)g_malloc(sizeof(Accessibility_KeyDefinition));
if (!spi_dbus_message_iter_get_struct(&iter_array, DBUS_TYPE_INT32, &kd->keycode, DBUS_TYPE_INT32, &kd->keysym, DBUS_TYPE_STRING, &keystring, DBUS_TYPE_INVALID))
{
+ g_free (kd);
break;
}
kd->keystring = g_strdup (keystring);
if (!spi_dbus_message_iter_get_struct(&iter_array, DBUS_TYPE_INT32, &kd->keycode, DBUS_TYPE_INT32, &kd->keysym, DBUS_TYPE_STRING, &keystring, DBUS_TYPE_INVALID))
{
+ g_free(kd);
break;
}
kd->keystring = g_strdup (keystring);
" <arg direction=\"out\" type=\"b\" />"
" </method>"
""
+" <method name=\"ClearHighlight\">"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
+" <method name=\"GrabHighlight\">"
+" <arg direction=\"out\" type=\"b\" />"
+" </method>"
+""
" <method name=\"GetAlpha\">"
" <arg direction=\"out\" type=\"d\" />"
" </method>"
[D-BUS Service]
Name=org.a11y.atspi.Registry
-Exec=@libexecdir@/at-spi2-registryd --use-gnome-session
+Exec=@libexecdir@/at-spi2-registryd
}
static DBusMessage *
+impl_ClearHighlight (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ DBusMessage *reply;
+ dbus_bool_t retval = FALSE;
+
+ reply = dbus_message_new_method_return (message);
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &retval,
+ DBUS_TYPE_INVALID);
+ return reply;
+}
+
+static DBusMessage *
+impl_GrabHighlight (DBusConnection * bus, DBusMessage * message, void *user_data)
+{
+ DBusMessage *reply;
+ dbus_bool_t retval = FALSE;
+
+ reply = dbus_message_new_method_return (message);
+ dbus_message_append_args (reply, DBUS_TYPE_BOOLEAN, &retval,
+ DBUS_TYPE_INVALID);
+ return reply;
+}
+
+static DBusMessage *
impl_GetAlpha (DBusConnection * bus, DBusMessage * message, void *user_data)
{
double rv = 1.0;
reply = impl_GetMDIZOrder (bus, message, user_data);
else if (!strcmp (member, "GrabFocus"))
reply = impl_GrabFocus (bus, message, user_data);
+ else if (!strcmp (member, "GrabHighlight"))
+ reply = impl_GrabHighlight (bus, message, user_data);
+ else if (!strcmp (member, "ClearHighlight"))
+ reply = impl_ClearHighlight (bus, message, user_data);
else if (!strcmp (member, "GetAlpha"))
reply = impl_GetAlpha (bus, message, user_data);
else
* This software is in the public domain. Share and enjoy!
*
*/
-
+#ifdef HAVE_X11
#include <X11/X.h>
+#endif
#include "deviceeventcontroller.h" /* for prototype */
struct codepair {
LDADD = $(top_builddir)/atspi/libatspi.la
+
+bin_PROGRAMS = at_spi2_tool
+at_spi2_tool_SOURCES = at_spi2_tool.c
+at_spi2_tool_CPPFLAGS = -I$(top_srcdir) -I$(top_builddir) -I$(top_builddir)/atspi
+at_spi2_tool_CFLAGS = $(GIO_CFLAGS) $(GLIB_CFLAGS) --std=c99 -Wall -fPIE $(GOBJ_LIBS) $(DBUS_CFLAGS)
+at_spi2_tool_LDFLAGS = $(GIO_LIBS) -pie
+
+
noinst_PROGRAMS = memory
memory_SOURCES = memory.c
memory_CPPFLAGS = -I$(top_srcdir) -I$(top_builddir) -I$(top_builddir)/atspi
memory_CFLAGS = $(GLIB_CFLAGS) $(GOBJ_LIBS) $(DBUS_CFLAGS)
-memory_LDFLAGS =
+memory_LDFLAGS =
+
-include $(top_srcdir)/git.mk
--- /dev/null
+#include "atspi/atspi.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <gio/gio.h>
+#include <assert.h>
+#include <stdint.h>
+
+#define ERROR_STATE -1
+#define SAFE_BUFFER_SIZE 2048
+#define CHECK_OUTPUT_WIDTH 42
+#define MINIMAL_MODULE_WIDTH 3
+#define ATTR_WIDTH 50
+#define NUMBER_WIDTH 6
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#define COLUMN_NO 3
+#define FLAG_NO 3
+#define DUMP 0
+#define CHECK 1
+#define FIRST_MATCH 2
+#define RELATION_TABLE_COLUMN_COUNT 7
+#define ATTRIBUTE_TABLE_COLUMN_COUNT 3
+#define RELATION_TABLE_COLUMN_WIDTH 20
+#define ATTRIBUTE_TABLE_BASE_COLUMN_WIDTH 20
+#define VERSION "1.1"
+
+static unsigned indent_width = 2;
+static int module_name_limit = -1;
+
+static const char* atspi_state_names[] = {
+ [ATSPI_STATE_INVALID] = "INVALID",
+ [ATSPI_STATE_ACTIVE] = "ACTIVE",
+ [ATSPI_STATE_ARMED] = "ARMED",
+ [ATSPI_STATE_BUSY] = "BUSY",
+ [ATSPI_STATE_CHECKED] = "CHECKED",
+ [ATSPI_STATE_COLLAPSED] = "COLLAPSED",
+ [ATSPI_STATE_DEFUNCT] = "DEFUNCT",
+ [ATSPI_STATE_EDITABLE] = "EDITABLE",
+ [ATSPI_STATE_ENABLED] = "ENABLED",
+ [ATSPI_STATE_EXPANDABLE] = "EXPANDABLE",
+ [ATSPI_STATE_EXPANDED] = "EXPANDED",
+ [ATSPI_STATE_FOCUSABLE] = "FOCUSABLE",
+ [ATSPI_STATE_FOCUSED] = "FOCUSED",
+ [ATSPI_STATE_HAS_TOOLTIP] = "HAS_TOOLTIP",
+ [ATSPI_STATE_HORIZONTAL] = "HORIZONTAL",
+ [ATSPI_STATE_ICONIFIED] = "ICONIFIED",
+ [ATSPI_STATE_MULTI_LINE] = "MULTI_LINE",
+ [ATSPI_STATE_MULTISELECTABLE] = "MULTISELECTABLE",
+ [ATSPI_STATE_OPAQUE] = "OPAQUE",
+ [ATSPI_STATE_PRESSED] = "PRESSED",
+ [ATSPI_STATE_RESIZABLE] = "RESIZABLE",
+ [ATSPI_STATE_SELECTABLE] = "SELECTABLE",
+ [ATSPI_STATE_SELECTED] = "SELECTED",
+ [ATSPI_STATE_SENSITIVE] = "SENSITIVE",
+ [ATSPI_STATE_SHOWING] = "SHOWING",
+ [ATSPI_STATE_SINGLE_LINE] = "SINGLE_LINE",
+ [ATSPI_STATE_STALE] = "STALE",
+ [ATSPI_STATE_TRANSIENT] = "TRANSIENT",
+ [ATSPI_STATE_VERTICAL] = "VERTICAL",
+ [ATSPI_STATE_VISIBLE] = "VISIBLE",
+ [ATSPI_STATE_MANAGES_DESCENDANTS] = "MANAGES_DESCENDANTS",
+ [ATSPI_STATE_INDETERMINATE] = "INDETERMINATE",
+ [ATSPI_STATE_REQUIRED] = "REQUIRED",
+ [ATSPI_STATE_TRUNCATED] = "TRUNCATED",
+ [ATSPI_STATE_ANIMATED] = "ANIMATED",
+ [ATSPI_STATE_INVALID_ENTRY] = "INVALID_ENTRY",
+ [ATSPI_STATE_SUPPORTS_AUTOCOMPLETION] = "SUPPORTS_AUTOCOMPLETION",
+ [ATSPI_STATE_SELECTABLE_TEXT] = "SELECTABLE_TEXT",
+ [ATSPI_STATE_IS_DEFAULT] = "IS_DEFAULT",
+ [ATSPI_STATE_VISITED] = "VISITED",
+ [ATSPI_STATE_CHECKABLE] = "CHECKABLE",
+ [ATSPI_STATE_MODAL] = "MODAL",
+ [ATSPI_STATE_HIGHLIGHTED] = "HIGHLIGHTED",
+ [ATSPI_STATE_HIGHLIGHTABLE] = "HIGHLIGHTABLE",
+ [ATSPI_STATE_HAS_POPUP] = "HAS_POPUP",
+ [ATSPI_STATE_READ_ONLY] = "READ_ONLY",
+ [ATSPI_STATE_LAST_DEFINED] = "LAST_DEFINED"
+};
+
+typedef struct _Box_Size {
+ char *x;
+ char *y;
+ char *height;
+ char *width;
+} Box_Size;
+
+static char *_multiply_string(char c, unsigned number)
+{
+ char *result = (char *)calloc(1, number + 1);
+
+ if (result == NULL)
+ return result;
+
+ memset(result, c, number);
+
+ return result;
+}
+
+static void _print_module_legend()
+{
+ printf("\n[[node],[node role name],[attributes list],[x,y,width,height],[node name],[states list][relations]\n\n");
+}
+
+static void _print_atspi_states_legend()
+{
+ _print_module_legend();
+
+ int array_len = ARRAY_SIZE(atspi_state_names);
+ int line_count = (array_len + COLUMN_NO - 1)/COLUMN_NO;
+ for (int line_idx = 0; line_idx < line_count; line_idx++) {
+ if ((line_idx < line_count - 1) || (array_len % COLUMN_NO == 0)) {
+ printf("[%d]\t%-24s[%d]\t%-24s[%d]\t%s\n",
+ line_idx * COLUMN_NO,
+ atspi_state_names[line_idx * COLUMN_NO],
+ (line_idx * COLUMN_NO) + 1,
+ atspi_state_names[(line_idx * COLUMN_NO) + 1],
+ (line_idx * COLUMN_NO) + 2,
+ atspi_state_names[(line_idx * COLUMN_NO) + 2]);
+ } else if (array_len % COLUMN_NO == 2) {
+ printf("[%d]\t%-24s[%d]\t%s\n",
+ line_idx * COLUMN_NO,
+ atspi_state_names[line_idx * COLUMN_NO],
+ (line_idx * COLUMN_NO) + 1,
+ atspi_state_names[(line_idx * COLUMN_NO) + 1]);
+ } else {
+ printf("[%d]\t%s\n", line_idx * COLUMN_NO, atspi_state_names[line_idx * COLUMN_NO]);
+ }
+ }
+}
+
+static void _set_indent(int indent_size)
+{
+ if (indent_size < 0) {
+ fprintf(stderr, "WARNING: Invalid indent size. Default value retained.\n");
+ return;
+ }
+
+ indent_width = indent_size;
+}
+
+static void _set_module_length_limit(int limit)
+{
+ if (limit < MINIMAL_MODULE_WIDTH) {
+ fprintf(stderr, "WARNING: Invalid maximum field size. Default value retained.\n");
+ return;
+ }
+
+ module_name_limit = limit;
+}
+
+static int _int_sort_function(gconstpointer a, gconstpointer b)
+{
+ int int_a = GPOINTER_TO_INT (a);
+ int int_b = GPOINTER_TO_INT (b);
+
+ return int_a - int_b;
+}
+
+static void _truncate_string(char *string, int length_limit)
+{
+ if (length_limit < MINIMAL_MODULE_WIDTH || !string)
+ return;
+
+ int len = strlen(string);
+
+ if (len > length_limit)
+ memcpy(string + length_limit - 3, "...", 4);
+}
+
+static size_t _combine_strings(char **destination, const char *source)
+{
+ if (!source || !*source || !destination)
+ return 0;
+
+ size_t old_len = *destination ? strlen(*destination) : 0;
+ size_t source_len = strlen(source);
+ size_t len = old_len + source_len;
+ char *buf = realloc(*destination, (len + 1) * sizeof(char));
+
+ if (!buf) {
+ fprintf(stderr, "_combine_strings: allocation failed");
+ return old_len;
+ }
+
+ memcpy(buf + old_len, source, source_len + 1);
+
+ *destination = buf;
+
+ return len;
+}
+
+static Box_Size *_get_box_size(AtspiAccessible *node)
+{
+ Box_Size *box_size = (Box_Size *)malloc(sizeof(Box_Size));
+ if (box_size == NULL)
+ return NULL;
+
+ char *x = NULL;
+ char *y = NULL;
+ char *width = NULL;
+ char *height = NULL;
+
+ AtspiComponent *component = atspi_accessible_get_component_iface(node);
+ AtspiRect *extent = component ? atspi_component_get_extents(component, ATSPI_COORD_TYPE_SCREEN, NULL) : NULL;
+
+ if (extent == NULL) {
+ _combine_strings(&x, "_");
+ _combine_strings(&y, "_");
+ _combine_strings(&width, "_");
+ _combine_strings(&height, "_");
+ } else {
+ char temp_buff[NUMBER_WIDTH];
+
+ snprintf(temp_buff, NUMBER_WIDTH, "%d", extent->x);
+ _combine_strings(&x, temp_buff);
+
+ snprintf(temp_buff, NUMBER_WIDTH, "%d", extent->y);
+ _combine_strings(&y, temp_buff);
+
+ snprintf(temp_buff, NUMBER_WIDTH, "%d", extent->width);
+ _combine_strings(&width, temp_buff);
+
+ snprintf(temp_buff, NUMBER_WIDTH, "%d", extent->height);
+ _combine_strings(&height, temp_buff);
+
+ g_object_unref(component);
+ g_free(extent);
+ }
+
+ box_size->x = x;
+ box_size->y = y;
+ box_size->width = width;
+ box_size->height = height;
+
+ return box_size;
+}
+
+static char *_get_states(AtspiAccessible *node, int length_limit)
+{
+ AtspiStateSet *node_state_set = atspi_accessible_get_state_set(node);
+ GArray *states = atspi_state_set_get_states(node_state_set);
+ if (!states) {
+ g_clear_object(&node_state_set);
+ return NULL;
+ }
+ g_array_sort(states, _int_sort_function);
+
+ AtspiStateType state_type;
+ char *state_string = NULL;
+
+ for (int i = 0; i < states->len; i++) {
+ state_type = g_array_index(states, AtspiStateType, i);
+
+ char node_state_str[27] = "";
+ strncat(node_state_str, "(", sizeof(node_state_str) - strlen(node_state_str) - 1);
+ strncat(node_state_str, atspi_state_names[state_type], sizeof(node_state_str) - strlen(node_state_str) - 1);
+ strncat(node_state_str, ")", sizeof(node_state_str) - strlen(node_state_str) - 1);
+
+ _combine_strings(&state_string, node_state_str);
+ }
+
+ g_array_free(states, 0);
+ g_clear_object(&node_state_set);
+
+ _truncate_string(state_string, length_limit);
+
+ return state_string;
+}
+
+static char *_get_attributes(AtspiAccessible *node, int length_limit, bool *attributes_are_too_long)
+{
+ GHashTable *attributes = atspi_accessible_get_attributes(node, NULL);
+
+ if (!attributes)
+ return NULL;
+
+ GHashTableIter attributes_iter;
+ gpointer attr_key;
+ gpointer attr_value;
+ g_hash_table_iter_init (&attributes_iter, attributes);
+ char *result = NULL;
+ while (g_hash_table_iter_next (&attributes_iter, &attr_key, &attr_value)) {
+ char attributes_string[SAFE_BUFFER_SIZE];
+ int ret = snprintf(attributes_string, SAFE_BUFFER_SIZE, "(%s=%s)", (char *)attr_key, (char *)attr_value);
+ if (ret >= SAFE_BUFFER_SIZE)
+ fprintf(stderr, "\n%s, %s %d: generated string is too long. Buffer overflow\n", __FILE__, __FUNCTION__, __LINE__);
+
+ _combine_strings(&result, attributes_string);
+ }
+ g_hash_table_unref(attributes);
+
+ int real_truncate_size = (length_limit < ATTR_WIDTH && length_limit > MINIMAL_MODULE_WIDTH) ? length_limit : ATTR_WIDTH;
+ if (result && attributes_are_too_long && strlen(result) > real_truncate_size)
+ *attributes_are_too_long = true;
+
+ _truncate_string(result, real_truncate_size);
+ return result;
+}
+
+static char *_get_info(AtspiAccessible *node, int length_limit, bool *attributes_are_too_long, bool *app_has_relations)
+{
+ if (!node)
+ return NULL;
+
+ char *node_name = atspi_accessible_get_name(node, NULL);
+ char *node_role_name = atspi_accessible_get_role_name(node, NULL);
+ char *unique_id = atspi_accessible_get_unique_id(node, NULL);
+ char *path = atspi_accessible_get_path(node, NULL);
+ unsigned long long eo_ptr = 0;
+ sscanf(path, "%llu", &eo_ptr);
+
+ char *attributes = _get_attributes(node, length_limit, attributes_are_too_long);
+ Box_Size *box_size = _get_box_size(node);
+ char *states = _get_states(node, length_limit);
+
+ GArray *relations = atspi_accessible_get_relation_set(node, NULL);
+ bool current_node_has_relations = (relations && relations->len);
+
+ char result[SAFE_BUFFER_SIZE];
+ int ret = snprintf(result, SAFE_BUFFER_SIZE, "[[%s(%p)],[%s],[%s],[%s,%s,%s,%s],[%s],[%s],[%s]]",
+ unique_id, (uintptr_t)eo_ptr,
+ node_role_name,
+ attributes,
+ box_size ? box_size->x : "nil",
+ box_size ? box_size->y : "nil",
+ box_size ? box_size->width : "nil",
+ box_size ? box_size->height : "nil",
+ node_name,
+ states,
+ current_node_has_relations ? "*" : "");
+
+ if (ret >= SAFE_BUFFER_SIZE)
+ fprintf(stderr, "\n%s, %s %d: generated string is too long. Buffer overflow\n", __FILE__, __FUNCTION__, __LINE__);
+
+ if (current_node_has_relations)
+ *app_has_relations = true;
+
+ free(node_name);
+ free(node_role_name);
+ free(unique_id);
+ free(path);
+ free(attributes);
+ if (box_size) {
+ free(box_size->width);
+ free(box_size->height);
+ free(box_size);
+ }
+ free(states);
+ if (relations)
+ g_array_free(relations, TRUE);
+
+ return g_strdup(result);
+}
+
+static void _test_atspi_parent_child_relation(AtspiAccessible *obj, AtspiAccessible *parent_candidate, int parent_candidate_index)
+{
+ int parent_index = atspi_accessible_get_index_in_parent(obj, NULL);
+ AtspiAccessible *parent = atspi_accessible_get_parent(obj, NULL);
+
+ char output[CHECK_OUTPUT_WIDTH];
+ if (parent_index != parent_candidate_index || parent_candidate != parent) {
+ char parent_status[NUMBER_WIDTH];
+
+ if (parent == NULL)
+ strncpy(parent_status, "_", NUMBER_WIDTH);
+ else
+ snprintf(parent_status, NUMBER_WIDTH, "%d", parent_index);
+
+ char *parent_unique_id = atspi_accessible_get_unique_id(parent, NULL);
+ char *parent_candidate_unique_id = atspi_accessible_get_unique_id(parent_candidate, NULL);
+ snprintf(output, CHECK_OUTPUT_WIDTH, "[FAIL<%d,%s><%s,%s>]", parent_candidate_index, parent_status,
+ parent_candidate_unique_id, parent_unique_id);
+ free(parent_unique_id);
+ free(parent_candidate_unique_id);
+
+ } else {
+ snprintf(output, CHECK_OUTPUT_WIDTH, "[OK]");
+ }
+
+ printf("%-*s\t", CHECK_OUTPUT_WIDTH, output);
+}
+
+static int _print_atspi_tree_verify_maybe_r(int indent_number, AtspiAccessible *object, bool check_integrity, int length_limit,
+ bool *attributes_are_too_long, bool *app_has_relations)
+{
+ char *indent = _multiply_string(' ', indent_number*indent_width);
+ if (indent != NULL) {
+ printf("%s", indent);
+ free(indent);
+ }
+
+ char *node_info = _get_info(object, length_limit, attributes_are_too_long, app_has_relations);
+ if (node_info != NULL) {
+ printf("%s\n", node_info);
+ free(node_info);
+ }
+
+ int count = atspi_accessible_get_child_count(object, NULL);
+ for (int i = 0; i < count; i++) {
+ AtspiAccessible *child = atspi_accessible_get_child_at_index(object, i, NULL);
+ if (child) {
+ if (check_integrity)
+ _test_atspi_parent_child_relation(child, object, i);
+
+ _print_atspi_tree_verify_maybe_r(indent_number + 1, child, check_integrity, length_limit, attributes_are_too_long, app_has_relations);
+ }
+ }
+ return 0;
+}
+
+void _print_help()
+{
+ printf("AT-SPI2-CORE-UTIL\n\n");
+ printf("USAGE: at_spi2_tool [OPTION] [PARAMETER] ...\n\n");
+ printf("OPTION LIST:\n");
+ printf("-h, --help\t\tshow this message\n");
+ printf("-v, --version\t\tshow actual version of tool\n");
+ printf("-g, --show-legend\tprint AT-SPI state legend\n");
+ printf("-l, --list-apps\t\tlist all applications of desktop\n");
+ printf("-a, --at-spi-client <true|false>\tenable/disable org.a11y.Status.IsEnabled property\n");
+ printf("-s, --sleep <N>\tsleep N seconds\n");
+ printf("-d, --tree-dump\t\tdump tree for selected application\n");
+ printf("-c, --tree-check\tcheck tree for selected application\n");
+ printf("-f, --first-match\tperform dump or check only for first matching application\n");
+ printf("-i, --indent\t\tset indentation size, default value stands at 2\n");
+ printf("-t, --truncate\t\tset maximum single field size, default value stands at 30\n");
+ printf("\nEXAMPLE:\n");
+ printf("\tat_spi2_tool -i3 -d quickpanel\n");
+ printf("\t show AT-SPI tree for node \"quickpanel\" using three-space indentation\n");
+ printf("\tat_spi2_tool -i1 -c starter\n");
+ printf("\t show AT-SPI tree with integrity test for node \"starter\" using one-space indentation\n");
+}
+
+void _print_version()
+{
+ printf("AT-SPI2-CORE-UTIL v%s\n", VERSION);
+}
+
+static void _print_horizontal_line_in_relations_table() {
+ for (int i = 0; i < RELATION_TABLE_COLUMN_COUNT; i++) {
+ for (int j = 0; j < RELATION_TABLE_COLUMN_WIDTH; j++)
+ printf("-");
+ printf("+");
+ }
+ printf("\n");
+}
+
+static char *_get_unique_id_of_object_in_relation(AtspiRelation *relation) {
+ if (!relation)
+ return NULL;
+
+ gint last_index = atspi_relation_get_n_targets(relation) - 1;
+ AtspiAccessible *target = atspi_relation_get_target(relation, last_index);
+ return atspi_accessible_get_unique_id(target, NULL);
+}
+
+static void _print_relations_for_object(AtspiAccessible *node) {
+ GArray *relations = atspi_accessible_get_relation_set(node, NULL);
+ if (!relations)
+ return;
+
+ if (!relations->len) {
+ g_array_free(relations, FALSE);
+ return;
+ }
+
+ char **table = calloc(RELATION_TABLE_COLUMN_COUNT, sizeof(char *));
+ if (!table) {
+ fprintf(stderr, "Calloc failed. Can't alloc memory for object relations string\n");
+ return;
+ }
+
+ table[0] = atspi_accessible_get_unique_id(node, NULL);
+ for (int i = 0; i < relations->len; i++) {
+ AtspiRelation *relation = g_array_index(relations, AtspiRelation *, i);
+ AtspiRelationType type = atspi_relation_get_relation_type(relation);
+ int idx;
+ switch (type) {
+ case ATSPI_RELATION_CONTROLLER_FOR: idx = 1; break;
+ case ATSPI_RELATION_CONTROLLED_BY: idx = 2; break;
+ case ATSPI_RELATION_FLOWS_TO: idx = 3; break;
+ case ATSPI_RELATION_FLOWS_FROM: idx = 4; break;
+ case ATSPI_RELATION_DESCRIBED_BY: idx = 5; break;
+ default: idx = 0;
+ }
+
+ if (idx > 0)
+ table[idx] = _get_unique_id_of_object_in_relation(relation);
+ else {
+ char buf[16];
+ snprintf(buf, sizeof(buf), " [%d]", type);
+ _combine_strings(&table[RELATION_TABLE_COLUMN_COUNT - 1], buf);
+ }
+ }
+
+ for (int i = 0; i < RELATION_TABLE_COLUMN_COUNT; i++) {
+ printf("%*s|", RELATION_TABLE_COLUMN_WIDTH, table[i] ? table[i] : "");
+ free(table[i]);
+ }
+ free(table);
+
+ printf("\n");
+ _print_horizontal_line_in_relations_table();
+ if (relations)
+ g_array_free(relations, TRUE);
+}
+
+typedef void (*print_information_about_object_function)(AtspiAccessible *);
+
+static void _iterate_over_tree(print_information_about_object_function func, AtspiAccessible *node) {
+ func(node);
+
+ int count = atspi_accessible_get_child_count(node, NULL);
+ for (int i = 0; i < count; i++) {
+ AtspiAccessible *child = atspi_accessible_get_child_at_index(node, i, NULL);
+ if (child)
+ _iterate_over_tree(func, child);
+ }
+}
+
+static void _print_relations_for_objects_in_tree(AtspiAccessible *node) {
+ _iterate_over_tree(_print_relations_for_object, node);
+}
+
+static void _print_header_for_relation_table() {
+ char *table[] = {"OBJECT", "CONTROLLER_FOR", "CONTROLLED_BY", "FLOWS_TO", "FLOWS_FROM", "DESCRIBED_BY", "OTHER RELATION [ID]"};
+ assert(ARRAY_SIZE(table) == RELATION_TABLE_COLUMN_COUNT);
+
+ _print_horizontal_line_in_relations_table();
+
+ for (int i = 0; i < RELATION_TABLE_COLUMN_COUNT; i++)
+ printf("%*s|", RELATION_TABLE_COLUMN_WIDTH , table[i]);
+
+ printf("\n");
+ _print_horizontal_line_in_relations_table();
+}
+
+static void _print_relations_table(AtspiAccessible *node) {
+ printf("\nRELATIONS TABLE\n");
+ _print_header_for_relation_table();
+ _print_relations_for_objects_in_tree(node);
+}
+
+static void _print_horizontal_line_in_attributes_table() {
+ int size_factor = 1;
+ for (int i = 0; i < ATTRIBUTE_TABLE_COLUMN_COUNT; i++) {
+ if (i == ATTRIBUTE_TABLE_COLUMN_COUNT - 1)
+ size_factor = 4;
+ for (int j = 0; j < ATTRIBUTE_TABLE_BASE_COLUMN_WIDTH * size_factor; j++)
+ printf("-");
+ printf("+");
+ }
+ printf("\n");
+}
+
+static void _print_attributes_for_object(AtspiAccessible *node) {
+ GHashTable *attributes = atspi_accessible_get_attributes(node, NULL);
+
+ if (!attributes)
+ return;
+
+ char *unique_id = atspi_accessible_get_unique_id(node, NULL);
+ GHashTableIter attributes_iter;
+ gpointer attr_key;
+ gpointer attr_value;
+
+ g_hash_table_iter_init (&attributes_iter, attributes);
+ while (g_hash_table_iter_next (&attributes_iter, &attr_key, &attr_value)) {
+ printf("%*s|", ATTRIBUTE_TABLE_BASE_COLUMN_WIDTH, unique_id ? unique_id : "");
+ printf("%*s|", ATTRIBUTE_TABLE_BASE_COLUMN_WIDTH, attr_key ? (char *) attr_key : "");
+ printf("%*s|\n", ATTRIBUTE_TABLE_BASE_COLUMN_WIDTH * 4, attr_value ? (char *) attr_value : "");
+ }
+
+ if (g_hash_table_size (attributes))
+ _print_horizontal_line_in_attributes_table();
+
+ g_hash_table_unref(attributes);
+ free(unique_id);
+}
+
+static void _print_attributes_for_objects_in_tree(AtspiAccessible *node) {
+ _iterate_over_tree(_print_attributes_for_object, node);
+}
+
+static void _print_header_for_attributes_table() {
+ char *table[] = {"OBJECT", "ATTRIBUTE KEY", "ATTRIBUTE VALUE"};
+ assert(ARRAY_SIZE(table) == ATTRIBUTE_TABLE_COLUMN_COUNT);
+
+ _print_horizontal_line_in_attributes_table();
+
+ int size_factor = 1;
+ for (int i = 0; i < ATTRIBUTE_TABLE_COLUMN_COUNT; i++) {
+ if (i == ATTRIBUTE_TABLE_COLUMN_COUNT - 1)
+ size_factor = 4;
+ printf("%*s|", ATTRIBUTE_TABLE_BASE_COLUMN_WIDTH * size_factor , table[i]);
+ }
+
+ printf("\n");
+ _print_horizontal_line_in_attributes_table();
+}
+
+static void _print_attributes_table(AtspiAccessible *node) {
+ printf("\nATTRIBUTES TABLE\n");
+ _print_header_for_attributes_table();
+ _print_attributes_for_objects_in_tree(node);
+}
+
+static void _atspi_tree_traverse(const char *app_name, bool dump, bool check, bool first_match, int length_limit)
+{
+
+ AtspiAccessible *desktop = atspi_get_desktop(0);
+ if (!desktop) {
+ fprintf(stderr, "atspi_get_desktop failed\n");
+ return;
+ }
+
+ int count = atspi_accessible_get_child_count(desktop, NULL);
+ bool app_name_matched = false;
+
+ for (int i = 0; i < count; i++) {
+ AtspiAccessible *child = atspi_accessible_get_child_at_index(desktop, i, NULL);
+ if (child == NULL) {
+ fprintf(stderr, "\n%s, %s %d: Null application occured. Results may be misleading.\n", __FILE__, __FUNCTION__, __LINE__);
+ continue;
+ }
+
+ char *name = atspi_accessible_get_name(child, NULL);
+ bool attributes_are_too_long = false;
+ bool app_has_relations = false;
+
+ if (!dump && !check)
+ printf("%s\n", name);
+
+ if ((check || dump) && name && app_name && !strcmp(name, app_name)) {
+ app_name_matched = true;
+
+ _print_module_legend();
+
+ if (check)
+ _test_atspi_parent_child_relation(child, desktop, i);
+
+ _print_atspi_tree_verify_maybe_r(0, child, check, length_limit, &attributes_are_too_long, &app_has_relations);
+
+ if (app_has_relations)
+ _print_relations_table(child);
+
+ if (attributes_are_too_long)
+ _print_attributes_table(child);
+
+ if (first_match) {
+ free(name);
+ break;
+ } else {
+ printf("\n");
+ }
+
+ free(name);
+ }
+ }
+
+ if (!app_name_matched && (dump || check))
+ fprintf(stderr, "There is no application with name: %s. Try again.\n", app_name);
+
+ g_object_unref(desktop);
+}
+
+static void _at_spi_client_enable(gboolean enabled)
+{
+ static GDBusProxy *proxy = NULL; //we keep proxy (dbus connection) until program exits
+ GVariant *result;
+ GVariant *enabled_variant;
+ GError *error = NULL;
+ GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_NONE;
+
+
+ if (!proxy) {
+ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ flags,
+ NULL, /* GDBusInterfaceInfo */
+ "org.a11y.Bus",
+ "/org/a11y/bus",
+ "org.freedesktop.DBus.Properties",
+ NULL, /* GCancellable */
+ &error);
+ if (error) {
+ fprintf(stderr, "Failed to create proxy object for '/org/a11y/bus': %s\n", error->message);
+ g_error_free(error);
+ return;
+ }
+ }
+
+ enabled_variant = g_variant_new_boolean(enabled);
+ result = g_dbus_proxy_call_sync(proxy,
+ "Set",
+ g_variant_new ("(ssv)", "org.a11y.Status", "IsEnabled", enabled_variant),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (enabled_variant)
+ g_variant_unref(enabled_variant);
+ if (result)
+ g_variant_unref(result);
+
+ if (error) {
+ fprintf(stderr, "Fail to call org.freedesktop.DBus.Properties.Set: %s\n", error->message);
+ g_error_free(error);
+ }
+}
+
+static void _run_command(int argc, char *argv[])
+{
+ struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'v'},
+ {"show-legend", no_argument, 0, 'g'},
+ {"list-apps", no_argument, 0, 'l'},
+ {"at-spi-client", no_argument, 0, 'a'},
+ {"sleep", required_argument, 0, 's'},
+ {"tree-dump", required_argument, 0, 'd'},
+ {"tree-check", required_argument, 0, 'c'},
+ {"first-match", no_argument, 0, 'f'},
+ {"indent", required_argument, 0, 'i'},
+ {"truncate", required_argument, 0, 't'},
+ };
+
+ int command = 0;
+ int option_index = 0;
+ bool traverse_flags[FLAG_NO] = {false};
+ char *app_name = NULL;
+ gboolean enable_at_spi_client;
+
+ while (TRUE) {
+ command = getopt_long(argc, argv, "hvgla:s:d:c:ft:i:", long_options, &option_index);
+
+ if (command == ERROR_STATE)
+ break;
+
+ switch (command) {
+ case 'h':
+ _print_help();
+ break;
+
+ case 'v':
+ _print_version();
+ break;
+
+ case 'g':
+ _print_atspi_states_legend();
+ break;
+
+ case 'l':
+ _atspi_tree_traverse(NULL, false, false, false, module_name_limit);
+ break;
+
+ case 'a':
+ enable_at_spi_client = TRUE;
+ if (optarg[0] == 'f' || optarg[0] == '0')
+ enable_at_spi_client = FALSE;
+
+ _at_spi_client_enable(enable_at_spi_client);
+ break;
+
+ case 's':
+ sleep(atoi(optarg));
+ break;
+
+ case 'd':
+ traverse_flags[DUMP] = true;
+ app_name = optarg;
+ break;
+
+ case 'c':
+ traverse_flags[CHECK] = true;
+ app_name = optarg;
+ break;
+
+ case 'f':
+ traverse_flags[FIRST_MATCH] = true;
+ break;
+
+ case 'i':
+ _set_indent(atoi(optarg));
+ break;
+
+ case 't':
+ _set_module_length_limit(atoi(optarg));
+ break;
+
+ case '?':
+ fprintf(stderr, "Invalid parameter. Use: \"--help\"\n");
+ break;
+
+ default:
+ abort();
+ }
+ }
+
+ if (traverse_flags[DUMP] || traverse_flags[CHECK])
+ _atspi_tree_traverse(app_name, traverse_flags[DUMP], traverse_flags[CHECK], traverse_flags[FIRST_MATCH], module_name_limit);
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc < 2) {
+ printf("Arguments required. Type %s --help.\n", argv[0]);
+ return -1;
+ }
+
+ int result = atspi_init();
+ if (result != 0)
+ {
+ fprintf(stderr, "Unable to initilize AT-SPI infrastructure, atspi_init failed\n");
+ return -1;
+ }
+
+ _run_command(argc, argv);
+
+ return 0;
+}
gint count;
gint i;
AtspiAccessible *accessible;
- GError *error = NULL;
- str = atspi_accessible_get_name (obj, &error);
+ str = atspi_accessible_get_name (obj, NULL);
if (str)
g_free (str);
accessible = atspi_accessible_get_parent (obj, NULL);
if (accessible)
g_object_unref (accessible);
- count = atspi_accessible_get_child_count (obj, &error);
+ count = atspi_accessible_get_child_count (obj, NULL);
for (i = 0; i < count; i++)
{
- accessible = atspi_accessible_get_child_at_index (obj, i, &error);
+ accessible = atspi_accessible_get_child_at_index (obj, i, NULL);
if (accessible)
g_object_unref (accessible);
}