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 "maliitattributeextension.h"
23 #include "maliitattributeextensionprivate.h"
24 #include "maliitattributeextensionregistry.h"
25 #include "maliitmarshallers.h"
26
27 /**
28 * SECTION:maliitattributeextension
29 * @short_description: attribute extensions
30 * @title: MaliitAttributeExtension
31 * @stability: Stable
32 * @include: maliit/maliitattributeextension.h
33 *
34 * #MaliitAttributeExtension class can be used by application to
35 * override some aspect of IM plugin currently used, like the looks of
36 * action key.
37 */
38
39 struct _MaliitAttributeExtensionPrivate
40 {
41 int id;
42 gchar *filename;
43 GHashTable *attributes;
44 MaliitAttributeExtensionRegistry *registry;
45 };
46
47 G_DEFINE_TYPE (MaliitAttributeExtension, maliit_attribute_extension, G_TYPE_OBJECT)
48
49 enum
50 {
51 EXTENDED_ATTRIBUTE_CHANGED,
52
53 LAST_SIGNAL
54 };
55
56 enum
57 {
58 PROP_0,
59
60 PROP_ID,
61 PROP_FILENAME,
62 PROP_ATTRIBUTES
63 };
64
65 static guint signals[LAST_SIGNAL] = { 0 };
66
67 static void
maliit_attribute_extension_finalize(GObject * object)68 maliit_attribute_extension_finalize (GObject *object)
69 {
70 MaliitAttributeExtension *extension = MALIIT_ATTRIBUTE_EXTENSION (object);
71 MaliitAttributeExtensionPrivate *priv = extension->priv;
72
73 g_free (priv->filename);
74
75 G_OBJECT_CLASS (maliit_attribute_extension_parent_class)->finalize (object);
76 }
77
78 static void
maliit_attribute_extension_dispose(GObject * object)79 maliit_attribute_extension_dispose (GObject *object)
80 {
81 MaliitAttributeExtension *extension = MALIIT_ATTRIBUTE_EXTENSION (object);
82 MaliitAttributeExtensionPrivate *priv = extension->priv;
83
84 if (priv->registry) {
85 MaliitAttributeExtensionRegistry *registry = priv->registry;
86
87 priv->registry = NULL;
88 maliit_attribute_extension_registry_remove_extension (registry,
89 extension);
90 g_object_unref (registry);
91 }
92
93 if (priv->attributes) {
94 GHashTable *attributes = priv->attributes;
95
96 priv->attributes = NULL;
97 g_hash_table_unref (attributes);
98 }
99
100 G_OBJECT_CLASS (maliit_attribute_extension_parent_class)->dispose (object);
101 }
102
103 static void
maliit_attribute_extension_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)104 maliit_attribute_extension_set_property (GObject *object,
105 guint prop_id,
106 const GValue *value,
107 GParamSpec *pspec)
108 {
109 MaliitAttributeExtension *extension = MALIIT_ATTRIBUTE_EXTENSION (object);
110 MaliitAttributeExtensionPrivate *priv = extension->priv;
111
112 switch (prop_id) {
113 case PROP_ID:
114 priv->id = g_value_get_int (value);
115 break;
116 case PROP_FILENAME:
117 g_free (extension->priv->filename);
118 priv->filename = g_value_dup_string (value);
119 break;
120 /* PROP_ATTRIBUTES is read only. */
121 default:
122 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
123 break;
124 }
125 }
126
127 static void
maliit_attribute_extension_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)128 maliit_attribute_extension_get_property (GObject *object,
129 guint prop_id,
130 GValue *value,
131 GParamSpec *pspec)
132 {
133 MaliitAttributeExtension *extension = MALIIT_ATTRIBUTE_EXTENSION (object);
134 MaliitAttributeExtensionPrivate *priv = extension->priv;
135
136 switch (prop_id) {
137 case PROP_ID:
138 g_value_set_int (value, priv->id);
139 break;
140 case PROP_FILENAME:
141 g_value_set_string (value, priv->filename);
142 break;
143 case PROP_ATTRIBUTES:
144 g_value_set_boxed (value, priv->attributes);
145 default:
146 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
147 break;
148 }
149 }
150
151 static void
maliit_attribute_extension_constructed(GObject * object)152 maliit_attribute_extension_constructed (GObject *object)
153 {
154 static int id_counter = 0;
155 MaliitAttributeExtension *extension = MALIIT_ATTRIBUTE_EXTENSION (object);
156 MaliitAttributeExtensionPrivate *priv = extension->priv;
157
158 if (priv->id == 0) {
159 priv->id = id_counter++;
160 }
161
162 maliit_attribute_extension_registry_add_extension (priv->registry,
163 extension);
164
165 G_OBJECT_CLASS (maliit_attribute_extension_parent_class)->constructed (object);
166 }
167
168 static void
maliit_attribute_extension_class_init(MaliitAttributeExtensionClass * extension_class)169 maliit_attribute_extension_class_init (MaliitAttributeExtensionClass *extension_class)
170 {
171 GObjectClass *g_object_class = G_OBJECT_CLASS (extension_class);
172
173 g_object_class->finalize = maliit_attribute_extension_finalize;
174 g_object_class->dispose = maliit_attribute_extension_dispose;
175 g_object_class->set_property = maliit_attribute_extension_set_property;
176 g_object_class->get_property = maliit_attribute_extension_get_property;
177 g_object_class->constructed = maliit_attribute_extension_constructed;
178
179 /**
180 * MaliitAttributeExtension:id:
181 *
182 * ID of the extension.
183 */
184 g_object_class_install_property (g_object_class,
185 PROP_ID,
186 g_param_spec_int ("id",
187 "ID", /* TODO: mark as translatable? */
188 "ID of the extension", /* TODO: mark as translatable? */
189 G_MININT,
190 G_MAXINT,
191 0,
192 G_PARAM_READABLE |
193 G_PARAM_WRITABLE |
194 G_PARAM_CONSTRUCT_ONLY |
195 G_PARAM_STATIC_NAME |
196 G_PARAM_STATIC_BLURB |
197 G_PARAM_STATIC_NICK));
198
199 /**
200 * MaliitAttributeExtension:id:
201 *
202 * Path to file where definitions of overrides are defined.
203 */
204 g_object_class_install_property (g_object_class,
205 PROP_FILENAME,
206 g_param_spec_string ("filename",
207 "Filename", /* TODO: mark as translatable? */
208 "Filename of the extension", /* TODO: mark as translatable? */
209 NULL,
210 G_PARAM_READABLE |
211 G_PARAM_WRITABLE |
212 G_PARAM_CONSTRUCT_ONLY |
213 G_PARAM_STATIC_NAME |
214 G_PARAM_STATIC_BLURB |
215 G_PARAM_STATIC_NICK));
216
217 g_object_class_install_property (g_object_class,
218 PROP_ATTRIBUTES,
219 g_param_spec_boxed ("attributes",
220 "Attributes", /* TODO: mark as translatable? */
221 "Attributes overrides", /* TODO: mark as translatable? */
222 G_TYPE_HASH_TABLE,
223 G_PARAM_READABLE |
224 G_PARAM_STATIC_NAME |
225 G_PARAM_STATIC_BLURB |
226 G_PARAM_STATIC_NICK));
227
228 /**
229 * MaliitAttributeExtension::extended-attribute-changed:
230 * @extension: The #MaliitAttributeExtension emitting the signal.
231 * @key: A string specifying the target for the attribute.
232 * @value: A new value.
233 *
234 * Informs application that input method server has changed the
235 * extended attribute.
236 */
237 signals[EXTENDED_ATTRIBUTE_CHANGED] =
238 g_signal_new ("extended-attribute-changed",
239 MALIIT_TYPE_ATTRIBUTE_EXTENSION,
240 G_SIGNAL_RUN_FIRST,
241 0,
242 NULL,
243 NULL,
244 maliit_marshal_VOID__STRING_VARIANT,
245 G_TYPE_NONE,
246 2,
247 G_TYPE_STRING,
248 G_TYPE_VARIANT);
249
250 g_type_class_add_private (extension_class, sizeof (MaliitAttributeExtensionPrivate));
251 }
252
253 static void
maliit_attribute_extension_init(MaliitAttributeExtension * extension)254 maliit_attribute_extension_init (MaliitAttributeExtension *extension)
255 {
256 MaliitAttributeExtensionPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (extension,
257 MALIIT_TYPE_ATTRIBUTE_EXTENSION,
258 MaliitAttributeExtensionPrivate);
259
260 priv->id = 0;
261 priv->filename = NULL;
262 priv->attributes = g_hash_table_new_full (g_str_hash,
263 g_str_equal,
264 g_free,
265 (GDestroyNotify) g_variant_unref);
266 priv->registry = maliit_attribute_extension_registry_get_instance ();
267
268 extension->priv = priv;
269 }
270
271 /**
272 * maliit_attribute_extension_new:
273 *
274 * Creates new attribute extension, which is not associated with any file.
275 *
276 * Returns: (transfer full): The newly created
277 * #MaliitAttributeExtension.
278 */
279 MaliitAttributeExtension *
maliit_attribute_extension_new(void)280 maliit_attribute_extension_new (void)
281 {
282 return MALIIT_ATTRIBUTE_EXTENSION (g_object_new (MALIIT_TYPE_ATTRIBUTE_EXTENSION,
283 NULL));
284 }
285
286 /**
287 * maliit_attribute_extension_new_with_id: (skip)
288 * @id: An overriden id.
289 *
290 * Creates a new attribute extension with already existing id. Used
291 * internally by #MaliitSettingsManager.
292 *
293 * Returns: (transfer full): The newly created
294 * #MaliitAttributeExtension.
295 */
296 MaliitAttributeExtension *
maliit_attribute_extension_new_with_id(int id)297 maliit_attribute_extension_new_with_id (int id)
298 {
299 return MALIIT_ATTRIBUTE_EXTENSION (g_object_new (MALIIT_TYPE_ATTRIBUTE_EXTENSION,
300 "id", id,
301 NULL));
302 }
303
304 /**
305 * maliit_attribute_extension_new_with_filename:
306 * @filename: (transfer none) (type filename): Filename where overrides are stored.
307 *
308 * Creates new attribute extension, which is associated with file
309 * given as @filename.
310 *
311 * Returns: (transfer full): The newly created
312 * #MaliitAttributeExtension.
313 */
314 MaliitAttributeExtension *
maliit_attribute_extension_new_with_filename(const gchar * filename)315 maliit_attribute_extension_new_with_filename (const gchar *filename)
316 {
317 return MALIIT_ATTRIBUTE_EXTENSION (g_object_new (MALIIT_TYPE_ATTRIBUTE_EXTENSION,
318 "filename", filename,
319 NULL));
320 }
321
322 /**
323 * maliit_attribute_extension_get_attributes:
324 * @extension: (transfer none): The #MaliitAttributeExtension which attributes you want to get.
325 *
326 * Gets all attributes of this extension that were set previously with
327 * maliit_attribute_extension_set_attribute().
328 *
329 * Returns: (transfer none) (element-type utf8 GLib.Variant): The #GHashTable
330 * containing strings as keys and #GVariant<!-- -->s as values. Should not be
331 * freed nor modified.
332 */
333 GHashTable *
maliit_attribute_extension_get_attributes(MaliitAttributeExtension * extension)334 maliit_attribute_extension_get_attributes (MaliitAttributeExtension *extension)
335 {
336 g_return_val_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension), NULL);
337
338 return extension->priv->attributes;
339 }
340
341 /**
342 * maliit_attribute_extension_get_filename:
343 * @extension: (transfer none): The #MaliitAttributeExtension which filename you want to get.
344 *
345 * Gets filename of this extension that were set previously with
346 * maliit_attribute_extension_new_with_filename().
347 *
348 * Returns: (transfer none) (type filename): The string being a
349 * filename of this extension or %NULL. Returned string should not be
350 * freed nor modified.
351 */
352 const gchar *
maliit_attribute_extension_get_filename(MaliitAttributeExtension * extension)353 maliit_attribute_extension_get_filename (MaliitAttributeExtension *extension)
354 {
355 g_return_val_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension), NULL);
356
357 return extension->priv->filename;
358 }
359
360 /**
361 * maliit_attribute_extension_get_id:
362 * @extension: (transfer none): The #MaliitAttributeExtension which ID you want to get.
363 *
364 * Gets ID of this extension.
365 *
366 * Returns: The ID of this extension.
367 */
368 int
maliit_attribute_extension_get_id(MaliitAttributeExtension * extension)369 maliit_attribute_extension_get_id (MaliitAttributeExtension *extension)
370 {
371 g_return_val_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension), -1);
372
373 return extension->priv->id;
374 }
375
376 /**
377 * maliit_attribute_extension_update_attribute:
378 * @extension: (transfer none): The #MaliitAttributeExtension which attribute you want to update.
379 * @key: (transfer none): Attribute name to update.
380 * @value: (transfer none): Attribute value to update.
381 *
382 * Updates the @extension's attribute described by @key with
383 * @value. This function always emits a
384 * #MaliitAttributeExtension::extended-attribute-changed signal.
385 */
386 void
maliit_attribute_extension_update_attribute(MaliitAttributeExtension * extension,const gchar * key,GVariant * value)387 maliit_attribute_extension_update_attribute (MaliitAttributeExtension *extension,
388 const gchar *key,
389 GVariant *value)
390 {
391 g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension));
392 g_return_if_fail (key != NULL);
393 g_return_if_fail (value != NULL);
394
395 g_hash_table_replace (extension->priv->attributes,
396 g_strdup (key),
397 g_variant_ref (value));
398
399 g_signal_emit (extension,
400 signals[EXTENDED_ATTRIBUTE_CHANGED],
401 0,
402 key,
403 value);
404 }
405
406 /**
407 * maliit_attribute_extension_set_attribute:
408 * @extension: (transfer none): The #MaliitAttributeExtension which attribute you want to set.
409 * @key: (transfer none): Attribute name to update.
410 * @value: (transfer none): Attribute value to update.
411 *
412 * Sets an attribute in @extension described by @key to value in @value.
413 */
maliit_attribute_extension_set_attribute(MaliitAttributeExtension * extension,const gchar * key,GVariant * value)414 void maliit_attribute_extension_set_attribute (MaliitAttributeExtension *extension,
415 const gchar *key,
416 GVariant *value)
417 {
418 MaliitAttributeExtensionPrivate *priv;
419 GHashTable *attributes;
420 GVariant *orig_value;
421
422 g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension));
423 g_return_if_fail (key != NULL);
424 g_return_if_fail (value != NULL);
425
426 priv = extension->priv;
427 attributes = priv->attributes;
428
429 if (!g_hash_table_lookup_extended (attributes, key, NULL, (gpointer *)&orig_value) ||
430 !g_variant_equal (orig_value, value)) {
431
432 g_hash_table_replace (attributes,
433 g_strdup (key),
434 g_variant_ref (value));
435
436 maliit_attribute_extension_registry_extension_changed (priv->registry,
437 extension,
438 key,
439 value);
440 }
441 }
442
443 /**
444 * maliit_attribute_extension_attach_to_object:
445 * @extension: (transfer none): The #MaliitAttributeExtension which you want to be attached.
446 * @object: (transfer none): The #GObject to which @extension will be attached.
447 *
448 * Attaches @extension to @object, so input context can retrieve it
449 * from @object. Note that attaching extensions to non-input
450 * #GObject<!-- -->s does not have much sense.
451 */
452 void
maliit_attribute_extension_attach_to_object(MaliitAttributeExtension * extension,GObject * object)453 maliit_attribute_extension_attach_to_object (MaliitAttributeExtension *extension,
454 GObject *object)
455 {
456 g_return_if_fail (MALIIT_IS_ATTRIBUTE_EXTENSION (extension));
457 g_return_if_fail (G_IS_OBJECT (object));
458
459 g_object_set_qdata_full (object, MALIIT_ATTRIBUTE_EXTENSION_DATA_QUARK,
460 extension, g_object_unref);
461 }
462