2.34.0
[platform/upstream/at-spi2-core.git] / atspi / atspi-matchrule.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2001, 2002 Sun Microsystems Inc.,
6  * Copyright 2001, 2002 Ximian, Inc.
7  * Copyright 2010, 2011 Novell, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24
25 #include "atspi-private.h"
26
27 G_DEFINE_TYPE (AtspiMatchRule, atspi_match_rule, G_TYPE_OBJECT)
28
29 static void
30 atspi_match_rule_init (AtspiMatchRule *match_rule)
31 {
32 }
33
34 static void
35 atspi_match_rule_dispose (GObject *object)
36 {
37   AtspiMatchRule *rule = ATSPI_MATCH_RULE (object);
38
39   if (rule->states)
40   {
41     g_object_unref (rule->states);
42     rule->states = NULL;
43   }
44
45   if (rule->attributes)
46   {
47     g_hash_table_unref (rule->attributes);
48     rule->attributes = NULL;
49   }
50
51   G_OBJECT_CLASS (atspi_match_rule_parent_class)->dispose (object);
52 }
53
54 static void
55 atspi_match_rule_finalize (GObject *object)
56 {
57   AtspiMatchRule *rule = ATSPI_MATCH_RULE (object);
58   gint i;
59
60   if (rule->interfaces)
61   {
62     for (i = 0; i < rule->interfaces->len; i++)
63       g_free (g_array_index (rule->interfaces, gchar *, i));
64     g_array_free (rule->interfaces, TRUE);
65   }
66
67   if (rule->attributes)
68     g_hash_table_unref (rule->attributes);
69
70   G_OBJECT_CLASS (atspi_match_rule_parent_class)->finalize (object);
71 }
72
73 static void
74 atspi_match_rule_class_init (AtspiMatchRuleClass *klass)
75 {
76   GObjectClass *object_class = G_OBJECT_CLASS (klass);
77
78   object_class->dispose = atspi_match_rule_dispose;
79   object_class->finalize = atspi_match_rule_finalize;
80 }
81
82 /**
83  * atspi_match_rule_new:
84  * @states: An #AtspiStateSet specifying the states to match or NULL if none.
85  * @statematchtype: An #AtspiCollectionMatchType specifying how to interpret
86  *          @states.
87  * @attributes: (element-type gchar* gchar*): A #GHashTable specifying
88  *          attributes to match. To specify multiple attribute values,
89  *          separate each value with a :: If an attribute value contains a :,
90  *          then it can be escaped by preceding it with a \. A backslash can
91  *          likewise be escaped by inserting a double backslash.
92  * @attributematchtype: An #AtspiCollectionMatchType specifying how to
93  *          interpret @attributes.
94  * @interfaces: (element-type gchar*): An array of interfaces to match, or
95  *          NULL if not applicable.  Interface names should be specified
96  *          by their DBus names (org.a11y.Atspi.Accessible,
97  *          org.a11y.Atspi.Component, etc).
98  * @interfacematchtype: An #AtspiCollectionMatchType specifying how to
99  *          interpret @interfaces.
100  * @roles: (element-type AtspiRole): A #GArray of roles to match, or NULL if
101  *          not applicable.
102  * @rolematchtype: An #AtspiCollectionMatchType specifying how to
103  *          interpret @roles.
104  * @invert: if #TRUE, the match rule should be denied (inverted); if #FALSE,
105  *          it should not. For example, if the match rule defines that a match is
106  *          an object of ROLE_HEADING which has STATE_FOCUSABLE and a click action,
107  *          inverting it would match all objects that are not of ROLE_HEADING,
108  *          focusable and clickable at the same time.
109  *
110  * Creates a new #AtspiMatchRule with specified @states, @attributes, 
111  * @interfaces, and @roles.
112  *
113  * Returns: (transfer full): A new #AtspiMatchRule.
114  **/
115 AtspiMatchRule *
116 atspi_match_rule_new (AtspiStateSet *states,
117                       AtspiCollectionMatchType statematchtype,
118                       GHashTable *attributes,
119                       AtspiCollectionMatchType attributematchtype,
120                       GArray *roles,
121                       AtspiCollectionMatchType rolematchtype,
122                       GArray *interfaces,
123                       AtspiCollectionMatchType interfacematchtype,
124                       gboolean invert)
125 {
126   AtspiMatchRule *rule = g_object_new (ATSPI_TYPE_MATCH_RULE, NULL);
127   int i;
128
129   if (states)
130     rule->states = g_object_ref (states);
131   rule->statematchtype = statematchtype;
132
133   if (attributes)
134   {
135     GHashTableIter hash_table_iter;
136     gchar *key, *value;
137     rule->attributes = g_hash_table_new_full (g_str_hash, g_str_equal,
138                                               (GDestroyNotify) g_free,
139                                               (GDestroyNotify) g_free);
140     g_hash_table_iter_init (&hash_table_iter, attributes);
141             while (g_hash_table_iter_next (&hash_table_iter, (gpointer *)&key,
142                    (gpointer *)&value))
143       g_hash_table_insert (rule->attributes, g_strdup (key), g_strdup (value));
144   } else
145     rule->attributes = NULL;
146   rule->attributematchtype = attributematchtype;
147
148   if (interfaces)
149   {
150     rule->interfaces = g_array_new (TRUE, TRUE, sizeof (gchar *));
151     for (i = 0; i < interfaces->len; i++)
152     {
153       gchar *val = g_strdup (g_array_index (interfaces, gchar *, i));
154       rule->interfaces = g_array_append_val (rule->interfaces, val);
155     }
156   }
157   rule->interfacematchtype = interfacematchtype;
158
159   if (roles)
160   {
161     for (i = 0; i < roles->len; i++)
162     {
163       AtspiRole role = g_array_index (roles, AtspiRole, i);
164       if (role < 128)
165         rule->roles [role / 32] |= (1 << (role % 32));
166       else
167         g_warning ("AT-SPI: unexpected role %d\n", role);
168     }
169   }
170   else
171     rule->roles [0] = rule->roles [1] = 0;
172   rule->rolematchtype = rolematchtype;
173
174   rule->invert = invert;
175
176   return rule;
177 }
178
179 static void
180 append_entry (gpointer key, gpointer val, gpointer data)
181 {
182   DBusMessageIter *iter = data;
183   DBusMessageIter iter_entry;
184
185   if (!dbus_message_iter_open_container (iter, DBUS_TYPE_DICT_ENTRY, NULL,
186                                         &iter_entry))
187     return;
188   dbus_message_iter_append_basic (&iter_entry, DBUS_TYPE_STRING, &key);
189   dbus_message_iter_append_basic (&iter_entry, DBUS_TYPE_STRING, &val);
190   dbus_message_iter_close_container (iter, &iter_entry);
191 }
192
193 gboolean
194 _atspi_match_rule_marshal (AtspiMatchRule *rule, DBusMessageIter *iter)
195 {
196   DBusMessageIter iter_struct, iter_array, iter_dict;
197   dbus_int32_t states [2];
198   dbus_int32_t d_statematchtype = rule->statematchtype;
199   dbus_int32_t d_attributematchtype = rule->attributematchtype;
200   dbus_int32_t d_interfacematchtype = rule->interfacematchtype;
201   dbus_uint32_t d_rolematchtype = rule->rolematchtype;
202   dbus_bool_t d_invert = rule->invert;
203   gint i;
204   dbus_int32_t d_role;
205
206   if (!dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL,
207                                          &iter_struct))
208     return FALSE;
209
210   /* states */
211   if (rule->states)
212   {
213     states [0] = rule->states->states & 0xffffffff;
214     states [1] = rule->states->states >> 32;
215   }
216   else
217   {
218     states [0] = states [1] = 0;
219   }
220   dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "i", &iter_array);
221   dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_INT32, &states [0]);
222   dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_INT32, &states [1]);
223   dbus_message_iter_close_container (&iter_struct, &iter_array);
224   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &d_statematchtype);
225
226   /* attributes */
227   if (!dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "{ss}",
228                                          &iter_dict))
229     return FALSE;
230   if (rule->attributes)
231     g_hash_table_foreach (rule->attributes, append_entry, &iter_dict);
232   dbus_message_iter_close_container (&iter_struct, &iter_dict);
233   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &d_attributematchtype);
234
235   if (!dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "i",
236       &iter_array))
237     return FALSE;
238   d_role = rule->roles [0];
239   dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_INT32, &d_role);
240   d_role = rule->roles [1];
241   dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_INT32, &d_role);
242   d_role = rule->roles [2];
243   dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_INT32, &d_role);
244   d_role = rule->roles [3];
245   dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_INT32, &d_role);
246   dbus_message_iter_close_container (&iter_struct, &iter_array);
247   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32,
248                                   &d_rolematchtype);
249
250   /* interfaces */
251   if (!dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "s",
252       &iter_array))
253     return FALSE;
254   if (rule->interfaces)
255   {
256     for (i = 0; i < rule->interfaces->len; i++)
257     {
258       char *val = g_array_index (rule->interfaces, gchar *, i);
259       dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_STRING, &val);
260     }
261   }
262   dbus_message_iter_close_container (&iter_struct, &iter_array);
263   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &d_interfacematchtype);
264
265   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_BOOLEAN, &d_invert);
266
267   dbus_message_iter_close_container (iter, &iter_struct);
268   return TRUE;
269 }