Add first pass at MatchRule/Collection implementation
[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   if (rule->roles)
43     g_array_free (rule->roles, TRUE);
44   /* TODO: Check that interfaces don't leak */
45   if (rule->interfaces)
46     g_array_free (rule->interfaces, TRUE);
47 }
48
49 static void
50 atspi_match_rule_class_init (AtspiMatchRuleClass *klass)
51 {
52   GObjectClass *object_class = G_OBJECT_CLASS (klass);
53
54   object_class->finalize = atspi_match_rule_finalize;
55 }
56
57 /**
58  * atspi_match_rule_new:
59  *
60  * @states: An #AtspiStateSet specifying the states to match or NULL if none.
61  * @statematchtype: An #AtspiCollectionMatchType specifying how to interpret
62  *                  @states.
63  * @attributes: (element-type gchar* gchar*): A #GHashTable specifying
64  *              attributes to match.
65  * @attributematchtype: An #AtspiCollectionMatchType specifying how to
66  *                      interpret @attributes.
67  * @roles: (element-type AtspiRole): A #GArray of roles to match, or NULL if
68  *         not applicable.
69  * @interfaces: (element-type gchar*): An array of interfaces to match, or
70  *              NUL if not appliable.  Interface names should be specified
71  *              by their DBus names (org.a11y.Atspi.Accessible,
72  *              org.a11y.Atspi.Component, etc).
73  * @interfacematchtype: An #AtspiCollectionMatchType specifying how to
74  *                      interpret @interfaces.
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                       gboolean invert)
88 {
89   AtspiMatchRule *rule = g_object_new (ATSPI_TYPE_MATCH_RULE, NULL);
90
91   if (!rule)
92     return NULL;
93
94   if (states)
95     rule->states = g_object_ref (states);
96   rule->statematchtype = statematchtype;
97
98   if (attributes)
99     rule->attributes = g_object_ref (attributes);
100     rule->attributematchtype = attributematchtype;
101
102   if (roles)
103     rule->roles = g_array_ref(roles);
104   rule->rolematchtype = rolematchtype;
105
106   rule->invert = invert;
107
108   return rule;
109 }
110
111 static void
112 append_entry (gpointer *key, gpointer *val, gpointer data)
113 {
114   DBusMessageIter *iter = data;
115   DBusMessageIter iter_entry;
116
117   if (!dbus_message_iter_open_container (iter, DBUS_TYPE_DICT_ENTRY, NULL,
118                                         &iter_entry))
119     return;
120   dbus_message_iter_append_basic (&iter_entry, DBUS_TYPE_STRING, &key);
121   dbus_message_iter_append_basic (&iter_entry, DBUS_TYPE_STRING, &val);
122   dbus_message_iter_close_container (iter, &iter_entry);
123 }
124
125 gboolean
126 _atspi_match_rule_marshal (AtspiMatchRule *rule, DBusMessageIter *iter)
127 {
128   DBusMessageIter iter_struct, iter_array, iter_dict;
129   dbus_int32_t states [2];
130   dbus_int32_t d_statematchtype = rule->statematchtype;
131   dbus_int32_t d_attributematchtype = rule->attributematchtype;
132   dbus_int32_t d_interfacematchtype = rule->interfacematchtype;
133   dbus_uint32_t d_rolematchtype = rule->rolematchtype;
134   dbus_bool_t d_invert = rule->invert;
135   gint i;
136
137   if (!dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, "(aiiasiaiisib)",
138                                          &iter_struct))
139     return FALSE;
140
141   /* states */
142   if (rule->states)
143   {
144     states [0] = rule->states->states & 0xffffffff;
145     states [1] = rule->states->states >> 32;
146   }
147   else
148   {
149     states [0] = states [1] = 0;
150   }
151   dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "u", &iter_array);
152   dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_INT32, &states [0]);
153   dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_INT32, &states [1]);
154   dbus_message_iter_close_container (&iter_struct, &iter_array);
155   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &d_statematchtype);
156
157   /* attributes */
158   if (!dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, "{ss}",
159                                          &iter_dict))
160     return FALSE;
161   g_hash_table_foreach (rule->attributes, append_entry, &iter_dict);
162   dbus_message_iter_close_container (iter, &iter_dict);
163   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32, &d_attributematchtype);
164
165   /* roles */
166   if (!dbus_message_iter_open_container (&iter_struct, DBUS_TYPE_ARRAY, "i",
167       &iter_array))
168     return FALSE;
169   if (rule->roles)
170   {
171     for (i = 0; i < rule->roles->len; i++)
172     {
173       dbus_int32_t d_role = g_array_index (rule->roles, AtspiRole, i);
174       dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_INT32, &d_role);
175     }
176   }
177   dbus_message_iter_close_container (&iter_struct, &iter_array);
178   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_INT32,
179                                   &d_rolematchtype);
180
181   dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_BOOLEAN, &d_invert);
182
183   dbus_message_iter_close_container (iter, &iter_struct);
184   return TRUE;
185 }