Really commit fixes; make unit tests pass
[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  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #include "atspi-private.h"
25
26 G_DEFINE_TYPE (AtspiMatchRule, atspi_match_rule, G_TYPE_OBJECT)
27
28 static void
29 atspi_match_rule_init (AtspiMatchRule *match_rule)
30 {
31 }
32
33 static void
34 atspi_match_rule_finalize (GObject *obj)
35 {
36   AtspiMatchRule *rule = ATSPI_MATCH_RULE (obj);
37
38   if (rule->states)
39     g_object_unref (rule->states);
40   if (rule->attributes)
41     g_hash_table_unref (rule->attributes);
42   /* TODO: Check that interfaces don't leak */
43   if (rule->interfaces)
44     g_array_free (rule->interfaces, TRUE);
45 }
46
47 static void
48 atspi_match_rule_class_init (AtspiMatchRuleClass *klass)
49 {
50   GObjectClass *object_class = G_OBJECT_CLASS (klass);
51
52   object_class->finalize = atspi_match_rule_finalize;
53 }
54
55 /**
56  * atspi_match_rule_new:
57  *
58  * @states: An #AtspiStateSet specifying the states to match or NULL if none.
59  * @statematchtype: An #AtspiCollectionMatchType specifying how to interpret
60  *                  @states.
61  * @attributes: (element-type gchar* gchar*): A #GHashTable specifying
62  *              attributes to match.
63  * @attributematchtype: An #AtspiCollectionMatchType specifying how to
64  *                      interpret @attributes.
65  * @interfaces: (element-type gchar*): An array of interfaces to match, or
66  *              NUL if not applicable.  Interface names should be specified
67  *              by their DBus names (org.a11y.Atspi.Accessible,
68  *              org.a11y.Atspi.Component, etc).
69  * @interfacematchtype: An #AtspiCollectionMatchType specifying how to
70  *                      interpret @interfaces.
71  * @roles: (element-type AtspiRole): A #GArray of roles to match, or NULL if
72  *         not applicable.
73  * @rolematchtype: An #AtspiCollectionMatchType specifying how to
74  *                      interpret @roles.
75  * @invert: Specifies whether results should be inverted.
76  * TODO: Document this parameter better.
77  *
78  * Returns: (transfer full): A new #AtspiMatchRule.
79  */
80 AtspiMatchRule *
81 atspi_match_rule_new (AtspiStateSet *states,
82                       AtspiCollectionMatchType statematchtype,
83                       GHashTable *attributes,
84                       AtspiCollectionMatchType attributematchtype,
85                       GArray *roles,
86                       AtspiCollectionMatchType rolematchtype,
87                       GArray *interfaces,
88                       AtspiCollectionMatchType interfacematchtype,
89                       gboolean invert)
90 {
91   AtspiMatchRule *rule = g_object_new (ATSPI_TYPE_MATCH_RULE, NULL);
92   int i;
93
94   if (!rule)
95     return NULL;
96
97   if (states)
98     rule->states = g_object_ref (states);
99   rule->statematchtype = statematchtype;
100
101   if (attributes)
102     rule->attributes = g_hash_table_ref (attributes);
103     rule->attributematchtype = attributematchtype;
104
105   if (interfaces)
106     rule->interfaces = g_array_ref (interfaces);
107   rule->interfacematchtype = interfacematchtype;
108
109   if (roles)
110   {
111     for (i = 0; i < roles->len; i++)
112     {
113       AtspiRole role = g_array_index (roles, AtspiRole, i);
114       if (role < 128)
115         rule->roles [role / 32] |= (1 << (role % 32));
116       else
117         g_warning ("Atspi: unexpected role %d\n", role);
118     }
119   }
120   else
121     rule->roles [0] = rule->roles [1] = 0;
122   rule->rolematchtype = rolematchtype;
123
124   rule->invert = invert;
125
126   return rule;
127 }
128
129 static void
130 append_entry (gpointer *key, gpointer *val, gpointer data)
131 {
132   DBusMessageIter *iter = data;
133   DBusMessageIter iter_entry;
134
135   if (!dbus_message_iter_open_container (iter, DBUS_TYPE_DICT_ENTRY, NULL,
136                                         &iter_entry))
137     return;
138   dbus_message_iter_append_basic (&iter_entry, DBUS_TYPE_STRING, &key);
139   dbus_message_iter_append_basic (&iter_entry, DBUS_TYPE_STRING, &val);
140   dbus_message_iter_close_container (iter, &iter_entry);
141 }
142
143 gboolean
144 _atspi_match_rule_marshal (AtspiMatchRule *rule, DBusMessageIter *iter)
145 {
146   DBusMessageIter iter_struct, iter_array, iter_dict;
147   dbus_int32_t states [2];
148   dbus_int32_t d_statematchtype = rule->statematchtype;
149   dbus_int32_t d_attributematchtype = rule->attributematchtype;
150   dbus_int32_t d_interfacematchtype = rule->interfacematchtype;
151   dbus_uint32_t d_rolematchtype = rule->rolematchtype;
152   dbus_bool_t d_invert = rule->invert;
153   gint i;
154   dbus_int32_t d_role;
155
156   if (!dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL,
157                                          &iter_struct))
158     return FALSE;
159
160   /* states */
161   if (rule->states)
162   {
163     states [0] = rule->states->states & 0xffffffff;
164     states [1] = rule->states->states >> 32;
165   }
166   else
167   {
168     states [0] = states [1] = 0;
169   }
170   dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "i", &iter_array);
171   dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_INT32, &states [0]);
172   dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_INT32, &states [1]);
173   dbus_message_iter_close_container (&iter_struct, &iter_array);
174   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &d_statematchtype);
175
176   /* attributes */
177   if (!dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "{ss}",
178                                          &iter_dict))
179     return FALSE;
180   g_hash_table_foreach (rule->attributes, append_entry, &iter_dict);
181   dbus_message_iter_close_container (&iter_struct, &iter_dict);
182   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &d_attributematchtype);
183
184   if (!dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "i",
185       &iter_array))
186     return FALSE;
187   d_role = rule->roles [0];
188   dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_INT32, &d_role);
189   d_role = rule->roles [1];
190   dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_INT32, &d_role);
191   d_role = rule->roles [2];
192   dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_INT32, &d_role);
193   d_role = rule->roles [3];
194   dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_INT32, &d_role);
195   dbus_message_iter_close_container (&iter_struct, &iter_array);
196   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32,
197                                   &d_rolematchtype);
198
199   /* interfaces */
200   if (!dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "s",
201       &iter_array))
202     return FALSE;
203   if (rule->interfaces)
204   {
205     for (i = 0; i < rule->interfaces->len; i++)
206     {
207       char *val = g_array_index (rule->interfaces, gchar *, i);
208       dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_STRING, &val);
209     }
210   }
211   dbus_message_iter_close_container (&iter_struct, &iter_array);
212   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &d_interfacematchtype);
213
214   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_BOOLEAN, &d_invert);
215
216   dbus_message_iter_close_container (iter, &iter_struct);
217   return TRUE;
218 }