Merge branch 'upstream/2.26.1' into tizen 04/175804/2 accepted/tizen/unified/20180425.062248 submit/tizen/20180419.063831 submit/tizen/20180423.061623
authorPaweł Stawicki <p.stawicki@samsung.com>
Wed, 4 Apr 2018 13:39:34 +0000 (15:39 +0200)
committerPaweł Stawicki <p.stawicki@samsung.com>
Fri, 13 Apr 2018 16:12:18 +0000 (18:12 +0200)
Change-Id: Iab32f00420decb25c5393dbfdf31bc6a1c7495bf

32 files changed:
.gbs.conf [new file with mode: 0644]
atspi/atspi-accessible.c
atspi/atspi-accessible.h
atspi/atspi-action.c
atspi/atspi-action.h
atspi/atspi-collection.c
atspi/atspi-component.c
atspi/atspi-component.h
atspi/atspi-constants.h
atspi/atspi-event-listener.c
atspi/atspi-misc-private.h
atspi/atspi-misc.c
atspi/atspi-misc.h
atspi/atspi-registry.c
atspi/atspi-stateset.c
atspi/atspi-types.h
bus/Makefile.am
bus/accessibility.conf.in
bus/at-spi-bus-launcher.c
configure.ac
idl/event.didl
packaging/at-spi2-core.manifest [new file with mode: 0644]
packaging/at-spi2-core.spec [new file with mode: 0644]
registryd/Makefile.am
registryd/deviceeventcontroller.c
registryd/introspection.c
registryd/org.a11y.atspi.Registry.service.in
registryd/registry.c
registryd/ucs2keysym.c
test/Makefile.am
test/at_spi2_tool.c [new file with mode: 0644]
test/memory.c

diff --git a/.gbs.conf b/.gbs.conf
new file mode 100644 (file)
index 0000000..00a849f
--- /dev/null
+++ b/.gbs.conf
@@ -0,0 +1,2 @@
+[general]
+upstream_tag = AT_SPI2_CORE_2_16_0
index e7f1446..d2afcd1 100644 (file)
@@ -225,6 +225,522 @@ atspi_accessible_get_name (AtspiAccessible *obj, GError **error)
   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, &current_value);
+  reading_material->value = current_value;
+  dbus_message_iter_next (&iter);
+
+  /* get minimum increment */
+  dbus_message_iter_get_basic (&iter, &current_value);
+  reading_material->increment = current_value;
+  dbus_message_iter_next (&iter);
+
+  /* get maximum value */
+  dbus_message_iter_get_basic (&iter, &current_value);
+  reading_material->upper = current_value;
+  dbus_message_iter_next (&iter);
+
+  /* get minimum value */
+  dbus_message_iter_get_basic (&iter, &current_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.
@@ -523,12 +1039,12 @@ atspi_accessible_get_role_name (AtspiAccessible *obj, GError **error)
  * 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.
  *
  **/
@@ -583,7 +1099,6 @@ atspi_accessible_get_state_set (AtspiAccessible *obj)
     dbus_message_unref (reply);
     _atspi_accessible_add_cache (obj, ATSPI_CACHE_STATES);
   }
-
   return g_object_ref (obj->states);
 }
 
@@ -591,7 +1106,7 @@ atspi_accessible_get_state_set (AtspiAccessible *obj)
  * 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.
@@ -638,7 +1153,7 @@ add_to_attribute_array (gpointer key, gpointer value, gpointer data)
  * 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.
@@ -796,7 +1311,7 @@ atspi_accessible_get_atspi_version (AtspiAccessible *obj, GError **error)
  * 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
@@ -847,7 +1362,7 @@ _atspi_accessible_is_a (AtspiAccessible *accessible,
  * 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,
@@ -877,7 +1392,7 @@ atspi_accessible_is_application (AtspiAccessible *obj)
                              atspi_interface_application);
 }
 
-/**                      
+/**
  * atspi_accessible_is_collection:
  * @obj: a pointer to the #AtspiAccessible instance to query.
  *
@@ -943,7 +1458,7 @@ atspi_accessible_is_editable_text (AtspiAccessible *obj)
   return _atspi_accessible_is_a (obj,
                              atspi_interface_editable_text);
 }
-                                                                                                                                                                        
+
 /**
  * atspi_accessible_is_hypertext:
  * @obj: a pointer to the #AtspiAccessible instance to query.
@@ -965,7 +1480,7 @@ atspi_accessible_is_hypertext (AtspiAccessible *obj)
  * 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,
@@ -1072,7 +1587,7 @@ atspi_accessible_is_streamable_content (AtspiAccessible *obj)
  * 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,
@@ -1117,7 +1632,7 @@ AtspiAction *
 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);
 }
 
 /**
@@ -1133,7 +1648,7 @@ AtspiAction *
 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);
 }
 
 /**
@@ -1151,7 +1666,7 @@ AtspiCollection *
 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);
 }
 
 /**
@@ -1167,7 +1682,7 @@ AtspiCollection *
 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);
 }
 
 /**
@@ -1219,7 +1734,7 @@ AtspiDocument *
 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);
 }
 
 /**
@@ -1235,7 +1750,7 @@ AtspiDocument *
 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);
 }
 
 /**
@@ -1253,7 +1768,7 @@ AtspiEditableText *
 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);
 }
 
 /**
@@ -1269,7 +1784,7 @@ AtspiEditableText *
 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);
 }
 
 /**
@@ -1303,7 +1818,7 @@ AtspiHypertext *
 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);
 }
 
 /**
@@ -1319,7 +1834,7 @@ AtspiHypertext *
 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);
 }
 
 /**
@@ -1337,7 +1852,7 @@ AtspiImage *
 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);
 }
 
 /**
@@ -1353,7 +1868,7 @@ AtspiImage *
 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);
 }
 
 /**
@@ -1371,7 +1886,7 @@ AtspiSelection *
 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);
 }
 
 /**
@@ -1387,7 +1902,7 @@ AtspiSelection *
 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
@@ -1404,7 +1919,7 @@ AtspiStreamableContent *
 atspi_accessible_get_streamable_content (AtspiAccessible *accessible)
 {
   return (_atspi_accessible_is_a (accessible, atspi_interface_streamable_content) ?
-          accessible : NULL);  
+          accessible : NULL);
 }
 #endif
 
@@ -1423,7 +1938,7 @@ AtspiTable *
 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);
 }
 
 /**
@@ -1439,7 +1954,7 @@ AtspiTable *
 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);
 }
 
 /**
@@ -1455,7 +1970,7 @@ AtspiTableCell *
 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);
 }
 
 /**
@@ -1507,7 +2022,7 @@ AtspiValue *
 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);
 }
 
 /**
@@ -1523,7 +2038,7 @@ AtspiValue *
 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
@@ -1548,10 +2063,12 @@ append_const_val (GArray *array, const gchar *val)
 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");
@@ -1583,11 +2100,11 @@ atspi_accessible_get_interfaces (AtspiAccessible *obj)
   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);
 
index 443e395..9e209e3 100644 (file)
@@ -5,7 +5,7 @@
  * 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
@@ -45,6 +45,41 @@ G_BEGIN_DECLS
 
 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;
@@ -66,7 +101,7 @@ struct _AtspiAccessibleClass
   AtspiObjectClass parent_class;
 };
 
-GType atspi_accessible_get_type (void); 
+GType atspi_accessible_get_type (void);
 
 AtspiAccessible *
 _atspi_accessible_new (AtspiApplication *app, const gchar *path);
@@ -75,6 +110,20 @@ gchar * atspi_accessible_get_name (AtspiAccessible *obj, GError **error);
 
 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);
index 731773a..ccf05bd 100644 (file)
@@ -214,6 +214,28 @@ atspi_action_do_action (AtspiAction *obj, gint i, 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)
 {
index 99de8af..d30395e 100644 (file)
@@ -57,6 +57,7 @@ gchar * atspi_action_get_key_binding (AtspiAction *obj, gint i, GError **error);
 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);
index f4e33ef..c893b49 100644 (file)
@@ -81,10 +81,12 @@ static GArray *
 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);
 
index 0ab552b..c246348 100644 (file)
@@ -122,6 +122,7 @@ atspi_component_get_accessible_at_point (AtspiComponent *obj,
   return _atspi_dbus_return_accessible_from_message (reply);
 }
 
+
 /**
  * atspi_component_get_extents:
  * @obj: a pointer to the #AtspiComponent to query.
@@ -215,7 +216,7 @@ atspi_component_get_size (AtspiComponent *obj, GError **error)
  * 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.
@@ -237,7 +238,7 @@ atspi_component_get_layer (AtspiComponent *obj, GError **error)
  * 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
@@ -271,14 +272,54 @@ atspi_component_grab_focus (AtspiComponent *obj, GError **error)
 }
 
 /**
+ * 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;
@@ -412,6 +453,23 @@ atspi_component_set_size (AtspiComponent *obj,
   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)
 {
index dd3455a..4363e55 100644 (file)
@@ -4,7 +4,7 @@
  *
  * 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
@@ -44,7 +44,7 @@ struct _AtspiRect
 
 /**
  * ATSPI_TYPE_RECT:
- * 
+ *
  * The #GType for a boxed type holding a #AtspiRect.
  */
 #define        ATSPI_TYPE_RECT (atspi_rect_get_type ())
@@ -62,7 +62,7 @@ struct _AtspiPoint
 
 /**
  * ATSPI_TYPE_POINT:
- * 
+ *
  * The #GType for a boxed type holding a #AtspiPoint.
  */
 #define        ATSPI_TYPE_POINT (atspi_point_get_type ())
@@ -107,6 +107,12 @@ gboolean atspi_component_set_position (AtspiComponent *obj, gint x, gint y, Atsp
 
 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_ */
index 1af391d..1727434 100644 (file)
@@ -91,13 +91,13 @@ extern "C" {
 /**
  * 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.
  *
@@ -124,7 +124,7 @@ typedef enum {
 /**
  * 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
@@ -136,6 +136,11 @@ typedef enum {
     ATSPI_COORD_TYPE_WINDOW,
 } AtspiCoordType;
 
+typedef enum {
+       ATSPI_NEIGHBOR_SEARCH_FORWARD = 1,
+       ATSPI_NEIGHBOR_SEARCH_BACKWARD = 2,
+} AtspiNeighborSearchDirection;
+
 /**
  * ATSPI_COORD_TYPE_COUNT:
  *
@@ -178,14 +183,14 @@ typedef enum {
 
 /**
  * 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.
  *
@@ -244,9 +249,9 @@ typedef enum {
  * 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.
@@ -255,23 +260,23 @@ typedef enum {
  * @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.
  *
  */
@@ -296,15 +301,15 @@ typedef enum {
 
 /**
  * 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
@@ -323,7 +328,7 @@ typedef enum {
  * 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.
  *
@@ -409,7 +414,7 @@ typedef enum {
 
 /**
  * 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.
@@ -432,7 +437,7 @@ typedef enum {
  * @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.
@@ -469,10 +474,10 @@ typedef enum {
  * 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.
@@ -484,19 +489,19 @@ typedef enum {
  * 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"
@@ -505,14 +510,14 @@ typedef enum {
  * 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
@@ -531,13 +536,13 @@ typedef enum {
  * 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
@@ -550,7 +555,7 @@ typedef enum {
  * 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
@@ -570,12 +575,18 @@ typedef enum {
  * @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.
  *
  **/
@@ -624,6 +635,8 @@ typedef enum {
     ATSPI_STATE_CHECKABLE,
     ATSPI_STATE_HAS_POPUP,
     ATSPI_STATE_READ_ONLY,
+    ATSPI_STATE_HIGHLIGHTED,
+    ATSPI_STATE_HIGHLIGHTABLE,
     ATSPI_STATE_LAST_DEFINED,
 } AtspiStateType;
 
@@ -656,18 +669,18 @@ typedef enum {
 
 /**
  * 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 {
@@ -692,14 +705,14 @@ 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
@@ -776,7 +789,7 @@ typedef enum {
  * 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
@@ -792,10 +805,10 @@ typedef enum {
  * 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
@@ -803,9 +816,9 @@ typedef enum {
  * @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.
@@ -847,24 +860,24 @@ typedef enum {
  * 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.
  *
@@ -946,7 +959,7 @@ typedef enum {
  * 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.
@@ -997,7 +1010,7 @@ typedef enum {
  * @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.
@@ -1005,7 +1018,7 @@ typedef enum {
  * 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.
@@ -1014,7 +1027,7 @@ typedef enum {
  * @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.
@@ -1043,7 +1056,7 @@ typedef enum {
  * 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
@@ -1055,11 +1068,11 @@ typedef enum {
  * @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
@@ -1073,13 +1086,13 @@ typedef enum {
  * 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
@@ -1089,7 +1102,7 @@ typedef enum {
  * 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
@@ -1107,22 +1120,22 @@ typedef enum {
  * 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.
@@ -1154,7 +1167,7 @@ typedef enum {
  * @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
@@ -1370,6 +1383,26 @@ typedef enum {
  */
 #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,
index 752547d..1717b75 100644 (file)
@@ -786,6 +786,7 @@ atspi_event_listener_deregister_from_callback (AtspiEventListenerCB callback,
   GPtrArray *matchrule_array;
   gint i;
   GList *l;
+  gboolean result = TRUE;
 
   if (!convert_event_type_to_dbus (event_type, &category, &name, &detail, &matchrule_array))
   {
@@ -820,8 +821,10 @@ atspi_event_listener_deregister_from_callback (AtspiEventListenerCB callback,
            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)
@@ -837,7 +840,7 @@ atspi_event_listener_deregister_from_callback (AtspiEventListenerCB callback,
   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;
 }
 
 /**
@@ -891,7 +894,7 @@ detail_matches_listener (const char *event_detail, const char *listener_detail)
     return TRUE;
 
   if (!event_detail)
-    return (listener_detail ? FALSE : TRUE);
+    return FALSE;
 
   return !(listener_detail [strcspn (listener_detail, ":")] == '\0'
                ? strncmp (listener_detail, event_detail,
@@ -971,16 +974,20 @@ _atspi_dbus_handle_event (DBusConnection *bus, DBusMessage *message, void *data)
 
   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);
index fe5ca56..27b3717 100644 (file)
@@ -5,7 +5,7 @@
  * 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
index eebbed4..40958e8 100644 (file)
@@ -110,7 +110,7 @@ _atspi_get_iface_num (const char *iface)
 GHashTable *
 _atspi_get_live_refs (void)
 {
-  if (!live_refs) 
+  if (!live_refs)
     {
       live_refs = g_hash_table_new (g_direct_hash, g_direct_equal);
     }
@@ -180,6 +180,7 @@ handle_get_bus_address (DBusPendingCall *pending, void *user_data)
   DBusMessage *message;
   const char *address;
   DBusPendingCall *new_pending;
+  dbus_bool_t result;
 
   if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
   {
@@ -218,9 +219,9 @@ handle_get_bus_address (DBusPendingCall *pending, void *user_data)
                                           "/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);
 }
@@ -232,6 +233,7 @@ get_application (const char *bus_name)
   char *bus_name_dup;
   DBusMessage *message;
   DBusPendingCall *pending = NULL;
+  dbus_bool_t result;
 
   if (!app_hash)
   {
@@ -252,9 +254,9 @@ get_application (const char *bus_name)
   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;
@@ -263,7 +265,7 @@ get_application (const char *bus_name)
   return app;
 }
 
-static AtspiAccessible *
+AtspiAccessible *
 ref_accessible (const char *app_name, const char *path)
 {
   AtspiApplication *app;
@@ -390,7 +392,7 @@ handle_name_owner_changed (DBusConnection *bus, DBusMessage *message, void *user
   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;
@@ -672,7 +674,7 @@ _atspi_dbus_return_hyperlink_from_message (DBusMessage *message)
   DBusMessageIter iter;
   AtspiHyperlink *retval = NULL;
   const char *signature;
-   
+
   if (!message)
     return NULL;
 
@@ -887,7 +889,7 @@ spi_display_name (void)
  *
  * 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)
@@ -907,7 +909,8 @@ 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);
@@ -984,7 +987,7 @@ atspi_event_quit (void)
 /**
  * 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.
@@ -1035,6 +1038,7 @@ check_for_hang (DBusMessage *message, DBusError *error, DBusConnection *bus, con
     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;
@@ -1043,9 +1047,9 @@ check_for_hang (DBusMessage *message, DBusError *error, DBusConnection *bus, con
                                             "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);
@@ -1142,9 +1146,11 @@ _atspi_dbus_call_partial (gpointer obj,
                           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;
 }
 
 
@@ -1158,9 +1164,9 @@ _atspi_dbus_call_partial_va (gpointer obj,
 {
   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);
 
@@ -1185,11 +1191,13 @@ out:
   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);
@@ -1198,7 +1206,6 @@ out:
     dbus_message_unref (reply);
     return NULL;
   }
-
   return reply;
 }
 
@@ -1487,7 +1494,7 @@ get_accessibility_bus_address_x11 (void)
       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),
@@ -1535,7 +1542,7 @@ get_accessibility_bus_address_dbus (void)
     dbus_error_free (&error);
     goto out;
   }
-  
+
   {
     const char *tmp_address;
     if (!dbus_message_get_args (reply,
@@ -1621,7 +1628,7 @@ atspi_get_a11y_bus (void)
          return NULL;
        }
     }
-  
+
   /* Simulate a weak ref on the bus */
   dbus_connection_set_data (a11y_bus, a11y_dbus_slot, a11y_bus, a11y_bus_free);
 
@@ -1821,7 +1828,7 @@ _atspi_dbus_update_cache_from_dict (AtspiAccessible *accessible, DBusMessageIter
       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);
   }
 
index f13596f..e39d7b8 100644 (file)
@@ -47,6 +47,9 @@ void
 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_ */
index c9b11f0..759a1aa 100644 (file)
@@ -270,7 +270,7 @@ atspi_deregister_keystroke_listener (AtspiDeviceListener *listener,
                                      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;
@@ -282,6 +282,7 @@ atspi_deregister_keystroke_listener (AtspiDeviceListener *listener,
     {
       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)
@@ -363,7 +364,7 @@ atspi_register_device_event_listener (AtspiDeviceListener  *listener,
 {
   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);
@@ -371,6 +372,7 @@ atspi_register_device_event_listener (AtspiDeviceListener  *listener,
     {
       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))
@@ -400,7 +402,7 @@ atspi_deregister_device_event_listener (AtspiDeviceListener *listener,
                                   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);
@@ -409,6 +411,7 @@ atspi_deregister_device_event_listener (AtspiDeviceListener *listener,
     {
       return FALSE;
     }
+  path = _atspi_device_listener_get_path (listener);
 
   event_types |= (1 << ATSPI_BUTTON_PRESSED_EVENT);
   event_types |= (1 << ATSPI_BUTTON_RELEASED_EVENT);
index 366c48b..3a53a8c 100644 (file)
@@ -101,6 +101,7 @@ atspi_state_set_set_by_name (AtspiStateSet *set, const gchar *name, gboolean ena
   if (!value)
   {
     g_warning ("AT-SPI: Attempt to set unknown state '%s'", name);
+    return;
   }
   else
     if (enabled)
index e458a8e..d09a972 100644 (file)
@@ -43,6 +43,8 @@ typedef struct _AtspiTable AtspiTable;
 typedef struct _AtspiTableCell AtspiTableCell;
 typedef struct _AtspiText AtspiText;
 typedef struct _AtspiValue AtspiValue;
+typedef struct _AtspiAccessibleReadingMaterial AtspiAccessibleReadingMaterial;
+typedef struct _AtspiAccessibleDefaultLabelInfo AtspiAccessibleDefaultLabelInfo;
 
 typedef guint AtspiControllerEventMask;
 
index 688f82a..8190888 100644 (file)
@@ -8,8 +8,9 @@ at_spi_bus_launcher_SOURCES = at-spi-bus-launcher.c
 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),"
 
index 31b6a79..9336ad7 100644 (file)
@@ -8,9 +8,7 @@
 
   <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 -->
@@ -18,7 +16,7 @@
     <!-- 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>
index 261353f..118379f 100644 (file)
 #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,
@@ -43,17 +78,30 @@ typedef enum {
 } 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;
@@ -229,7 +277,7 @@ setup_bus_child (gpointer data)
 #ifdef __linux
 #include <sys/prctl.h>
   prctl (PR_SET_PDEATHSIG, 15);
-#endif  
+#endif
 }
 
 /**
@@ -261,7 +309,7 @@ on_bus_exited (GPid     pid,
                gpointer data)
 {
   A11yBusLauncher *app = data;
-  
+
   app->a11y_bus_pid = -1;
   app->state = A11Y_BUS_STATE_ERROR;
   if (app->a11y_launch_error_message == NULL)
@@ -274,7 +322,7 @@ on_bus_exited (GPid     pid,
         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)
@@ -293,11 +341,11 @@ 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,
@@ -320,7 +368,7 @@ ensure_a11y_bus (A11yBusLauncher *app)
 
   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));
@@ -333,7 +381,7 @@ ensure_a11y_bus (A11yBusLauncher *app)
 
   /* 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
   {
@@ -353,7 +401,7 @@ ensure_a11y_bus (A11yBusLauncher *app)
 #endif
 
   return TRUE;
-  
+
  error:
   close (app->pipefd[0]);
   close (app->pipefd[1]);
@@ -452,11 +500,6 @@ handle_screen_reader_enabled_change (A11yBusLauncher *app, gboolean enabled,
   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)
@@ -478,12 +521,66 @@ handle_screen_reader_enabled_change (A11yBusLauncher *app, gboolean enabled,
                                                 &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,
@@ -496,7 +593,7 @@ handle_set_property  (GDBusConnection       *connection,
   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,
@@ -508,7 +605,10 @@ handle_set_property  (GDBusConnection       *connection,
 
   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)
@@ -546,7 +646,7 @@ on_bus_acquired (GDBusConnection *connection,
   A11yBusLauncher *app = user_data;
   GError *error;
   guint registration_id;
-  
+
   if (connection == NULL)
     {
       g_main_loop_quit (app->loop);
@@ -626,7 +726,7 @@ on_sigterm_pipe (GIOChannel  *channel,
                  gpointer     data)
 {
   A11yBusLauncher *app = data;
-  
+
   g_main_loop_quit (app->loop);
 
   return FALSE;
@@ -664,7 +764,7 @@ already_running ()
   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),
@@ -712,7 +812,6 @@ static void
 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);
@@ -720,23 +819,237 @@ gsettings_key_changed (GSettings *gsettings, const gchar *key, void *user_data)
     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++)
     {
@@ -783,7 +1096,7 @@ main (int    argc,
   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,
@@ -792,12 +1105,15 @@ main (int    argc,
                                   _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.
    */
index a84dcbd..0d7313f 100644 (file)
@@ -64,6 +64,17 @@ PKG_CHECK_MODULES(GIO, [gio-2.0 >= 2.28])
 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
 
index d4c75cc..a048a23 100644 (file)
@@ -31,6 +31,7 @@ namespace org.freestandards.atspi.Event {
                signal TextAttributesChanged {Event event;}
                signal TextCaretMoved {Event event;}
                signal AttributesChanged {Event event;}
+               signal MoveOuted {Event event;}
        }
 
        interface Window {
diff --git a/packaging/at-spi2-core.manifest b/packaging/at-spi2-core.manifest
new file mode 100644 (file)
index 0000000..017d22d
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+ <request>
+    <domain name="_"/>
+ </request>
+</manifest>
diff --git a/packaging/at-spi2-core.spec b/packaging/at-spi2-core.spec
new file mode 100644 (file)
index 0000000..a053eb1
--- /dev/null
@@ -0,0 +1,124 @@
+%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
index 6a4b1d8..99b9dce 100644 (file)
@@ -3,7 +3,9 @@ EXTRA_DIST = \
 
 libexec_PROGRAMS = at-spi2-registryd
 
+at_spi2_registryd_LDFLAGS = -pie
 at_spi2_registryd_CFLAGS =     \
+       -fPIE \
        $(GLIB_CFLAGS)          \
        $(GIO_CFLAGS)           \
        $(DBUS_CFLAGS)          \
index 0c965ef..b4c393d 100644 (file)
@@ -927,6 +927,7 @@ send_and_allow_reentry (DBusConnection *bus, DBusMessage *message, int timeout,
       {
         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,
@@ -936,9 +937,9 @@ send_and_allow_reentry (DBusConnection *bus, DBusMessage *message, int timeout,
                                                 "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,
@@ -1365,6 +1366,7 @@ impl_register_keystroke_listener (DBusConnection *bus,
     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);
@@ -1575,6 +1577,7 @@ impl_deregister_keystroke_listener (DBusConnection *bus,
 
     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);
index 5b694ad..68604af 100644 (file)
@@ -226,6 +226,14 @@ const char *spi_org_a11y_atspi_Component =
 "    <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>"
index de93790..13f1875 100644 (file)
@@ -1,3 +1,3 @@
 [D-BUS Service]
 Name=org.a11y.atspi.Registry
-Exec=@libexecdir@/at-spi2-registryd --use-gnome-session
+Exec=@libexecdir@/at-spi2-registryd
index cbf0c1b..1cb4431 100644 (file)
@@ -542,6 +542,30 @@ impl_GrabFocus (DBusConnection * bus, DBusMessage * message, void *user_data)
 }
 
 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;
@@ -1248,6 +1272,10 @@ handle_method_root (DBusConnection *bus, DBusMessage *message, void *user_data)
           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
index b4967be..539685c 100644 (file)
@@ -30,8 +30,9 @@
  * 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 {
index b76db0a..e99c237 100644 (file)
@@ -1,9 +1,18 @@
 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
 
diff --git a/test/at_spi2_tool.c b/test/at_spi2_tool.c
new file mode 100644 (file)
index 0000000..7039fb5
--- /dev/null
@@ -0,0 +1,822 @@
+#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;
+}
index df5e0a1..2db9871 100644 (file)
@@ -13,18 +13,17 @@ basic (AtspiAccessible *obj)
   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);
   }