1 /* This file is part of Maliit framework
2 *
3 * Copyright (C) 2012 One Laptop per Child Association
4 *
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the licence, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22 #include "maliitattributeextensionregistry.h"
23 #include "maliitbus.h"
24
25 struct _MaliitAttributeExtensionRegistryPrivate
26 {
27 GHashTable *extensions;
28 };
29
30 static MaliitAttributeExtensionRegistry *global_singleton;
31
G_DEFINE_TYPE(MaliitAttributeExtensionRegistry,maliit_attribute_extension_registry,G_TYPE_OBJECT)32 G_DEFINE_TYPE (MaliitAttributeExtensionRegistry, maliit_attribute_extension_registry, G_TYPE_OBJECT)
33
34 static void
35 maliit_attribute_extension_registry_finalize (GObject *object)
36 {
37 global_singleton = NULL;
38
39 G_OBJECT_CLASS (maliit_attribute_extension_registry_parent_class)->finalize (object);
40 }
41
42 static void
extension_notify(gpointer data,GObject * where_the_object_was)43 extension_notify (gpointer data,
44 GObject *where_the_object_was)
45 {
46 MaliitAttributeExtensionRegistry *registry = MALIIT_ATTRIBUTE_EXTENSION_REGISTRY (data);
47 MaliitAttributeExtensionRegistryPrivate *priv = registry->priv;
48 GHashTableIter iter;
49 MaliitAttributeExtension *extension;
50
51 g_hash_table_iter_init (&iter, priv->extensions);
52 while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&extension)) {
53 if ((gpointer)extension == (gpointer)where_the_object_was) {
54 g_hash_table_iter_steal (&iter);
55 break;
56 }
57 }
58 }
59
60 static void
maliit_attribute_extension_registry_dispose(GObject * object)61 maliit_attribute_extension_registry_dispose (GObject *object)
62 {
63 MaliitAttributeExtensionRegistry *registry = MALIIT_ATTRIBUTE_EXTENSION_REGISTRY (object);
64 MaliitAttributeExtensionRegistryPrivate *priv = registry->priv;
65
66 if (priv->extensions) {
67 GHashTable *extensions = priv->extensions;
68
69 priv->extensions = NULL;
70 g_hash_table_unref (extensions);
71 }
72
73 G_OBJECT_CLASS (maliit_attribute_extension_registry_parent_class)->dispose (object);
74 }
75
76 static GObject*
maliit_attribute_extension_registry_constructor(GType type,guint n_params,GObjectConstructParam * params)77 maliit_attribute_extension_registry_constructor (GType type,
78 guint n_params,
79 GObjectConstructParam *params)
80 {
81 GObject *object;
82
83 if (global_singleton) {
84 object = g_object_ref (G_OBJECT (global_singleton));
85 } else {
86 object = G_OBJECT_CLASS (maliit_attribute_extension_registry_parent_class)->constructor (type,
87 n_params,
88 params);
89 /* We are doing an additional reference here, so object will not
90 * be destroyed when last owner removes its reference. This is a
91 * leak, but for now it ensures that singleton have a lifetime of
92 * application. This needs to be fixed, when object lifetimes are
93 * fixed in gtk-input-context. */
94 global_singleton = MALIIT_ATTRIBUTE_EXTENSION_REGISTRY (g_object_ref (object));
95 }
96
97 return object;
98 }
99
100 static void
maliit_attribute_extension_registry_class_init(MaliitAttributeExtensionRegistryClass * registry_class)101 maliit_attribute_extension_registry_class_init (MaliitAttributeExtensionRegistryClass *registry_class)
102 {
103 GObjectClass *g_object_class = G_OBJECT_CLASS (registry_class);
104
105 g_object_class->finalize = maliit_attribute_extension_registry_finalize;
106 g_object_class->dispose = maliit_attribute_extension_registry_dispose;
107 g_object_class->constructor = maliit_attribute_extension_registry_constructor;
108
109 g_type_class_add_private (registry_class, sizeof (MaliitAttributeExtensionRegistryPrivate));
110 }
111
112 static void
extension_weak_unref(MaliitAttributeExtension * extension,MaliitAttributeExtensionRegistry * registry)113 extension_weak_unref (MaliitAttributeExtension *extension,
114 MaliitAttributeExtensionRegistry *registry)
115 {
116 g_object_weak_unref (G_OBJECT (extension),
117 extension_notify,
118 registry);
119 }
120
121 static void
extension_weak_unref_global(gpointer data)122 extension_weak_unref_global (gpointer data)
123 {
124 MaliitAttributeExtension *extension = MALIIT_ATTRIBUTE_EXTENSION (data);
125
126 extension_weak_unref (extension,
127 global_singleton);
128 }
129
130 static void
register_all_extensions(MaliitServer * server,gpointer user_data)131 register_all_extensions (MaliitServer *server, gpointer user_data)
132 {
133 MaliitAttributeExtensionRegistry *registry = user_data;
134 GList *extensions = maliit_attribute_extension_registry_get_extensions (registry);
135 GList *iter;
136 GError *error = NULL;
137
138 for (iter = extensions; iter; iter = iter->next) {
139 MaliitAttributeExtension *extension = MALIIT_ATTRIBUTE_EXTENSION (iter->data);
140
141 if (maliit_server_call_register_attribute_extension_sync (server,
142 maliit_attribute_extension_get_id (extension),
143 maliit_attribute_extension_get_filename (extension),
144 NULL,
145 &error)) {
146 GHashTable *attributes = maliit_attribute_extension_get_attributes (extension);
147 GHashTableIter attributes_iter;
148 gpointer key;
149 gpointer value;
150
151 g_hash_table_iter_init (&attributes_iter, attributes);
152
153 while (g_hash_table_iter_next (&attributes_iter, &key, &value)) {
154 maliit_attribute_extension_registry_extension_changed(registry, extension, key, value);
155 }
156 } else {
157 g_warning ("Could not register an extension in mass registerer: %s", error->message);
158 g_clear_error (&error);
159 }
160 }
161
162 g_list_free (extensions);
163 }
164
165 static void
connection_established(GObject * source_object G_GNUC_UNUSED,GAsyncResult * res,gpointer user_data)166 connection_established (GObject *source_object G_GNUC_UNUSED,
167 GAsyncResult *res,
168 gpointer user_data)
169 {
170 GError *error = NULL;
171 MaliitServer *server = maliit_get_server_finish (res, &error);
172
173 if (server) {
174 register_all_extensions (server, user_data);
175 } else {
176 g_warning ("Unable to connect to server: %s", error->message);
177 g_clear_error (&error);
178 }
179 }
180
181 static void
maliit_attribute_extension_registry_init(MaliitAttributeExtensionRegistry * registry)182 maliit_attribute_extension_registry_init (MaliitAttributeExtensionRegistry *registry)
183 {
184 MaliitAttributeExtensionRegistryPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (registry,
185 MALIIT_TYPE_ATTRIBUTE_EXTENSION_REGISTRY,
186 MaliitAttributeExtensionRegistryPrivate);
187
188 priv->extensions = g_hash_table_new_full (g_direct_hash,
189 g_direct_equal,
190 NULL,
191 extension_weak_unref_global);
192
193 registry->priv = priv;
194
195 maliit_get_server (NULL, connection_established, registry);
196 }
197
198 MaliitAttributeExtensionRegistry *
maliit_attribute_extension_registry_get_instance(void)199 maliit_attribute_extension_registry_get_instance (void)
200 {
201 return MALIIT_ATTRIBUTE_EXTENSION_REGISTRY (g_object_new (MALIIT_TYPE_ATTRIBUTE_EXTENSION_REGISTRY,
202 NULL));
203 }
204
205 void
maliit_attribute_extension_registry_add_extension(MaliitAttributeExtensionRegistry * registry,MaliitAttributeExtension * extension)206 maliit_attribute_extension_registry_add_extension (MaliitAttributeExtensionRegistry *registry,
207 MaliitAttributeExtension *extension)
208 {
209 MaliitServer *server;
210 GHashTable *extensions;
211 gint id;
212 GError *error = NULL;
213
214 g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION_REGISTRY (registry));
215 g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension));
216
217 extensions = registry->priv->extensions;
218 id = maliit_attribute_extension_get_id (extension);
219
220 if (!g_hash_table_lookup_extended (extensions, GINT_TO_POINTER (id), NULL, NULL)) {
221 g_object_weak_ref (G_OBJECT (extension),
222 extension_notify,
223 registry);
224
225 g_hash_table_insert (extensions,
226 GINT_TO_POINTER (id),
227 extension);
228
229 server = maliit_get_server_sync (NULL, &error);
230
231 if (server) {
232 if (!maliit_server_call_register_attribute_extension_sync (server,
233 id,
234 maliit_attribute_extension_get_filename (extension),
235 NULL,
236 &error)) {
237 g_warning ("Unable to register extension: %s", error->message);
238 g_clear_error (&error);
239 }
240 } else {
241 g_warning ("Unable to connect to server: %s", error->message);
242 g_clear_error (&error);
243 }
244 }
245 }
246
247 void
maliit_attribute_extension_registry_remove_extension(MaliitAttributeExtensionRegistry * registry,MaliitAttributeExtension * extension)248 maliit_attribute_extension_registry_remove_extension (MaliitAttributeExtensionRegistry *registry,
249 MaliitAttributeExtension *extension)
250 {
251 MaliitServer *server;
252 GHashTable *extensions;
253 gint id;
254 GError *error = NULL;
255
256 g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION_REGISTRY (registry));
257 g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension));
258
259 extensions = registry->priv->extensions;
260 id = maliit_attribute_extension_get_id (extension);
261
262 if (g_hash_table_lookup_extended (extensions, GINT_TO_POINTER (id), NULL, NULL)) {
263 g_hash_table_remove (extensions,
264 GINT_TO_POINTER (id));
265
266 server = maliit_get_server_sync (NULL, &error);
267
268 if (server) {
269 if (!maliit_server_call_unregister_attribute_extension_sync (server,
270 id,
271 NULL,
272 &error)) {
273 g_warning ("Unable to unregister extension: %s", error->message);
274 g_clear_error (&error);
275 }
276 } else {
277 g_warning ("Unable to connect to server: %s", error->message);
278 g_clear_error (&error);
279 }
280 }
281 }
282
283 /* For glib < 2.30 */
284 #ifndef G_VALUE_INIT
285 #define G_VALUE_INIT { 0, { { 0 } } }
286 #endif
287
288 void
maliit_attribute_extension_registry_extension_changed(MaliitAttributeExtensionRegistry * registry,MaliitAttributeExtension * extension,const gchar * key,GVariant * value)289 maliit_attribute_extension_registry_extension_changed (MaliitAttributeExtensionRegistry *registry,
290 MaliitAttributeExtension *extension,
291 const gchar *key,
292 GVariant *value)
293 {
294 MaliitServer *server;
295 gchar **parts;
296 GError *error = NULL;
297
298 g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION_REGISTRY (registry));
299 g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension));
300 g_return_if_fail (key != NULL);
301 g_return_if_fail (value != NULL);
302
303 parts = g_strsplit (key + 1, "/", 3);
304
305 if (!parts)
306 return;
307
308 if (g_strv_length (parts) == 3) {
309 gchar *target = g_strdup_printf ("/%s", parts[0]);
310
311 server = maliit_get_server_sync (NULL, &error);
312
313 if (server) {
314 if (!maliit_server_call_set_extended_attribute_sync (server,
315 maliit_attribute_extension_get_id (extension),
316 target,
317 parts[1],
318 parts[2],
319 value,
320 NULL,
321 &error)) {
322 g_warning ("Unable to set extended attribute: %s", error->message);
323 g_clear_error (&error);
324 }
325 } else {
326 g_warning ("Unable to connect to server: %s", error->message);
327 g_clear_error (&error);
328 }
329
330 g_free (target);
331 } else {
332 g_warning("Key `%s' is not valid. It needs to be `/target/item/key'", key);
333 }
334 g_strfreev (parts);
335 }
336
337 static void
fill_list_with_extensions(gpointer key G_GNUC_UNUSED,gpointer value,gpointer user_data)338 fill_list_with_extensions (gpointer key G_GNUC_UNUSED,
339 gpointer value,
340 gpointer user_data)
341 {
342 MaliitAttributeExtension *extension = MALIIT_ATTRIBUTE_EXTENSION (value);
343 GList **list = (GList **)user_data;
344
345 *list = g_list_prepend (*list, extension);
346 }
347
348 GList *
maliit_attribute_extension_registry_get_extensions(MaliitAttributeExtensionRegistry * registry)349 maliit_attribute_extension_registry_get_extensions (MaliitAttributeExtensionRegistry *registry)
350 {
351 GList *list;
352
353 g_return_val_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION_REGISTRY (registry), NULL);
354
355 list = NULL;
356 g_hash_table_foreach (registry->priv->extensions,
357 fill_list_with_extensions,
358 &list);
359
360 return list;
361 }
362
363 void
maliit_attribute_extension_registry_update_attribute(MaliitAttributeExtensionRegistry * registry,gint id,const gchar * target,const gchar * target_item,const gchar * attribute,GVariant * value)364 maliit_attribute_extension_registry_update_attribute (MaliitAttributeExtensionRegistry *registry,
365 gint id,
366 const gchar *target,
367 const gchar *target_item,
368 const gchar *attribute,
369 GVariant *value)
370 {
371 MaliitAttributeExtension *extension;
372
373 g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION_REGISTRY (registry));
374 g_return_if_fail (id >= 0);
375 g_return_if_fail (target != NULL);
376 g_return_if_fail (target_item != NULL);
377 g_return_if_fail (attribute != NULL);
378 g_return_if_fail (value != NULL);
379
380 if (g_hash_table_lookup_extended (registry->priv->extensions,
381 GINT_TO_POINTER (id),
382 NULL,
383 (gpointer *)&extension)) {
384 gchar *key = g_strdup_printf ("%s/%s/%s", target, target_item, attribute);
385
386 maliit_attribute_extension_update_attribute (extension,
387 key,
388 value);
389 g_free (key);
390 } else {
391 g_warning ("Extension %d was not found.", id);
392 }
393 }
394