1 /*
2 A library to communicate a menu object set accross DBus and
3 track updates and maintain consistency.
4 
5 Copyright 2011 Canonical Ltd.
6 
7 Authors:
8     Ted Gould <ted@canonical.com>
9 
10 This program is free software: you can redistribute it and/or modify it
11 under the terms of either or both of the following licenses:
12 
13 1) the GNU Lesser General Public License version 3, as published by the
14 Free Software Foundation; and/or
15 2) the GNU Lesser General Public License version 2.1, as published by
16 the Free Software Foundation.
17 
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranties of
20 MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
21 PURPOSE.  See the applicable version of the GNU Lesser General Public
22 License for more details.
23 
24 You should have received a copy of both the GNU Lesser General Public
25 License version 3 and version 2.1 along with this program.  If not, see
26 <http://www.gnu.org/licenses/>
27 */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include <glib/gi18n-lib.h>
34 
35 #include "defaults.h"
36 #include "menuitem.h"
37 #include "client.h"
38 
39 struct _DbusmenuDefaultsPrivate {
40 	GHashTable * types;
41 };
42 
43 typedef struct _DefaultEntry DefaultEntry;
44 struct _DefaultEntry {
45 	GVariantType * type;
46 	GVariant * value;
47 };
48 
49 #define DBUSMENU_DEFAULTS_GET_PRIVATE(o) \
50 (G_TYPE_INSTANCE_GET_PRIVATE ((o), DBUSMENU_TYPE_DEFAULTS, DbusmenuDefaultsPrivate))
51 
52 static void dbusmenu_defaults_class_init (DbusmenuDefaultsClass *klass);
53 static void dbusmenu_defaults_init       (DbusmenuDefaults *self);
54 static void dbusmenu_defaults_dispose    (GObject *object);
55 static void dbusmenu_defaults_finalize   (GObject *object);
56 
57 static DefaultEntry * entry_create (const GVariantType * type, GVariant * variant);
58 static void entry_destroy (gpointer entry);
59 
60 G_DEFINE_TYPE (DbusmenuDefaults, dbusmenu_defaults, G_TYPE_OBJECT);
61 
62 static void
dbusmenu_defaults_class_init(DbusmenuDefaultsClass * klass)63 dbusmenu_defaults_class_init (DbusmenuDefaultsClass *klass)
64 {
65 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
66 
67 	g_type_class_add_private (klass, sizeof (DbusmenuDefaultsPrivate));
68 
69 	object_class->dispose = dbusmenu_defaults_dispose;
70 	object_class->finalize = dbusmenu_defaults_finalize;
71 	return;
72 }
73 
74 static void
dbusmenu_defaults_init(DbusmenuDefaults * self)75 dbusmenu_defaults_init (DbusmenuDefaults *self)
76 {
77 	self->priv = DBUSMENU_DEFAULTS_GET_PRIVATE(self);
78 
79 	self->priv->types = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_hash_table_destroy);
80 
81 	/* Standard defaults */
82 	dbusmenu_defaults_default_set(self,   DBUSMENU_CLIENT_TYPES_DEFAULT,    DBUSMENU_MENUITEM_PROP_VISIBLE,        G_VARIANT_TYPE_BOOLEAN,   g_variant_new_boolean(TRUE));
83 	dbusmenu_defaults_default_set(self,   DBUSMENU_CLIENT_TYPES_DEFAULT,    DBUSMENU_MENUITEM_PROP_ENABLED,        G_VARIANT_TYPE_BOOLEAN,   g_variant_new_boolean(TRUE));
84 	dbusmenu_defaults_default_set(self,   DBUSMENU_CLIENT_TYPES_DEFAULT,    DBUSMENU_MENUITEM_PROP_LABEL,          G_VARIANT_TYPE_STRING,    g_variant_new_string(_("Label Empty")));
85 	dbusmenu_defaults_default_set(self,   DBUSMENU_CLIENT_TYPES_DEFAULT,    DBUSMENU_MENUITEM_PROP_ICON_NAME,      G_VARIANT_TYPE_STRING,    NULL);
86 	dbusmenu_defaults_default_set(self,   DBUSMENU_CLIENT_TYPES_DEFAULT,    DBUSMENU_MENUITEM_PROP_ICON_DATA,      G_VARIANT_TYPE("ay"),     NULL);
87 	dbusmenu_defaults_default_set(self,   DBUSMENU_CLIENT_TYPES_DEFAULT,    DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE,    G_VARIANT_TYPE_STRING,    NULL);
88 	dbusmenu_defaults_default_set(self,   DBUSMENU_CLIENT_TYPES_DEFAULT,    DBUSMENU_MENUITEM_PROP_TOGGLE_STATE,   G_VARIANT_TYPE_INT32,     NULL);
89 	dbusmenu_defaults_default_set(self,   DBUSMENU_CLIENT_TYPES_DEFAULT,    DBUSMENU_MENUITEM_PROP_SHORTCUT,       G_VARIANT_TYPE("aas"),    NULL);
90 	dbusmenu_defaults_default_set(self,   DBUSMENU_CLIENT_TYPES_DEFAULT,    DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY,  G_VARIANT_TYPE_STRING,    NULL);
91 	dbusmenu_defaults_default_set(self,   DBUSMENU_CLIENT_TYPES_DEFAULT,    DBUSMENU_MENUITEM_PROP_DISPOSITION,    G_VARIANT_TYPE_STRING,    g_variant_new_string(DBUSMENU_MENUITEM_DISPOSITION_NORMAL));
92 	dbusmenu_defaults_default_set(self,   DBUSMENU_CLIENT_TYPES_DEFAULT,    DBUSMENU_MENUITEM_PROP_ACCESSIBLE_DESC,G_VARIANT_TYPE_STRING,    NULL);
93 
94 	/* Separator defaults */
95 	dbusmenu_defaults_default_set(self,   DBUSMENU_CLIENT_TYPES_SEPARATOR,  DBUSMENU_MENUITEM_PROP_VISIBLE,        G_VARIANT_TYPE_BOOLEAN,   g_variant_new_boolean(TRUE));
96 
97 	return;
98 }
99 
100 static void
dbusmenu_defaults_dispose(GObject * object)101 dbusmenu_defaults_dispose (GObject *object)
102 {
103 	DbusmenuDefaults * self = DBUSMENU_DEFAULTS(object);
104 
105 	if (self->priv->types != NULL) {
106 		g_hash_table_destroy(self->priv->types);
107 		self->priv->types = NULL;
108 	}
109 
110 	G_OBJECT_CLASS (dbusmenu_defaults_parent_class)->dispose (object);
111 	return;
112 }
113 
114 static void
dbusmenu_defaults_finalize(GObject * object)115 dbusmenu_defaults_finalize (GObject *object)
116 {
117 
118 	G_OBJECT_CLASS (dbusmenu_defaults_parent_class)->finalize (object);
119 	return;
120 }
121 
122 /* Create a new entry based on the info provided */
123 static DefaultEntry *
entry_create(const GVariantType * type,GVariant * variant)124 entry_create (const GVariantType * type, GVariant * variant)
125 {
126 	DefaultEntry * defentry = g_new0(DefaultEntry, 1);
127 
128 	if (type != NULL) {
129 		defentry->type = g_variant_type_copy(type);
130 	}
131 
132 	if (variant != NULL) {
133 		defentry->value = variant;
134 		g_variant_ref_sink(variant);
135 	}
136 
137 	return defentry;
138 }
139 
140 /* Destroy an entry */
141 static void
entry_destroy(gpointer entry)142 entry_destroy (gpointer entry)
143 {
144 	DefaultEntry * defentry = (DefaultEntry *)entry;
145 
146 	if (defentry->type != NULL) {
147 		g_variant_type_free(defentry->type);
148 		defentry->type = NULL;
149 	}
150 
151 	if (defentry->value != NULL) {
152 		g_variant_unref(defentry->value);
153 		defentry->value = NULL;
154 	}
155 
156 	g_free(defentry);
157 	return;
158 }
159 
160 static DbusmenuDefaults * default_defaults = NULL;
161 
162 /*
163  * dbusmenu_defaults_ref_default:
164  *
165  * Get a reference to the default instance.  If it doesn't exist this
166  * function will create it.
167  *
168  * Return value: (transfer full): A reference to the defaults
169  */
170 DbusmenuDefaults *
dbusmenu_defaults_ref_default(void)171 dbusmenu_defaults_ref_default (void)
172 {
173 	if (default_defaults == NULL) {
174 		default_defaults = DBUSMENU_DEFAULTS(g_object_new(DBUSMENU_TYPE_DEFAULTS, NULL));
175 		g_object_add_weak_pointer(G_OBJECT(default_defaults), (gpointer *)&default_defaults);
176 	} else {
177 		g_object_ref(default_defaults);
178 	}
179 
180 	return default_defaults;
181 }
182 
183 /*
184  * dbusmenu_defaults_default_set:
185  * @defaults: The #DbusmenuDefaults object to add to
186  * @type: (allow-none): The #DbusmenuMenuitem type for this default if #NULL will default to #DBUSMENU_CLIENT_TYPE_DEFAULT
187  * @property: Property name for the default
188  * @prop_type: (allow-none): Type of the property for runtime checking.  To disable checking set to #NULL.
189  * @value: (allow-none): Default value for @property.  #NULL if by default it is unset, but you want type checking from @prop_type.
190  *
191  * Sets up an entry in the defaults database for a given @property
192  * and menuitem type @type.  @prop_type and @value can both be #NULL
193  * but both of them can not.
194  */
195 void
dbusmenu_defaults_default_set(DbusmenuDefaults * defaults,const gchar * type,const gchar * property,const GVariantType * prop_type,GVariant * value)196 dbusmenu_defaults_default_set (DbusmenuDefaults * defaults, const gchar * type, const gchar * property, const GVariantType * prop_type, GVariant * value)
197 {
198 	g_return_if_fail(DBUSMENU_IS_DEFAULTS(defaults));
199 	g_return_if_fail(property != NULL);
200 	g_return_if_fail(prop_type != NULL || value != NULL);
201 
202 	if (type == NULL) {
203 		type = DBUSMENU_CLIENT_TYPES_DEFAULT;
204 	}
205 
206 	GHashTable * prop_table = (GHashTable *)g_hash_table_lookup(defaults->priv->types, type);
207 
208 	/* We've never had a default for this type, so we need
209 	   to create a table for it. */
210 	if (prop_table == NULL) {
211 		prop_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, entry_destroy);
212 
213 		g_hash_table_insert(prop_table, g_strdup(property), entry_create(prop_type, value));
214 		g_hash_table_insert(defaults->priv->types, g_strdup(type), prop_table);
215 	} else {
216 		g_hash_table_replace(prop_table, g_strdup(property), entry_create(prop_type, value));
217 	}
218 
219 	return;
220 }
221 
222 /*
223  * dbusmenu_defaults_default_get:
224  * @defaults: The default database to use
225  * @type: (allow-none): The #DbusmenuMenuitem type for this default if #NULL will default to #DBUSMENU_CLIENT_TYPE_DEFAULT
226  * @property: Property name to lookup
227  *
228  * Gets an entry in the database for a give @property and @type.
229  *
230  * Return value: (transfer none): Returns a variant that does not
231  * have its ref count increased.  If you want to keep it, you should
232  * do that.
233  */
234 GVariant *
dbusmenu_defaults_default_get(DbusmenuDefaults * defaults,const gchar * type,const gchar * property)235 dbusmenu_defaults_default_get (DbusmenuDefaults * defaults, const gchar * type, const gchar * property)
236 {
237 	g_return_val_if_fail(DBUSMENU_IS_DEFAULTS(defaults), NULL);
238 	g_return_val_if_fail(property != NULL, NULL);
239 
240 	if (type == NULL) {
241 		type = DBUSMENU_CLIENT_TYPES_DEFAULT;
242 	}
243 
244 	GHashTable * prop_table = (GHashTable *)g_hash_table_lookup(defaults->priv->types, type);
245 
246 	if (prop_table == NULL) {
247 		return NULL;
248 	}
249 
250 	DefaultEntry * entry = (DefaultEntry *)g_hash_table_lookup(prop_table, property);
251 
252 	if (entry == NULL) {
253 		return NULL;
254 	}
255 
256 	return entry->value;
257 }
258 
259 /*
260  * dbusmenu_defaults_default_get_type:
261  * @defaults: The default database to use
262  * @type: (allow-none): The #DbusmenuMenuitem type for this default if #NULL will default to #DBUSMENU_CLIENT_TYPE_DEFAULT
263  * @property: Property name to lookup
264  *
265  * Gets the type for an entry in the database for a give @property and @type.
266  *
267  * Return value: (transfer none): Returns a type for the given
268  * @property value.
269  */
270 GVariantType *
dbusmenu_defaults_default_get_type(DbusmenuDefaults * defaults,const gchar * type,const gchar * property)271 dbusmenu_defaults_default_get_type (DbusmenuDefaults * defaults, const gchar * type, const gchar * property)
272 {
273 	g_return_val_if_fail(DBUSMENU_IS_DEFAULTS(defaults), NULL);
274 	g_return_val_if_fail(property != NULL, NULL);
275 
276 	if (type == NULL) {
277 		type = DBUSMENU_CLIENT_TYPES_DEFAULT;
278 	}
279 
280 	GHashTable * prop_table = (GHashTable *)g_hash_table_lookup(defaults->priv->types, type);
281 
282 	if (prop_table == NULL) {
283 		return NULL;
284 	}
285 
286 	DefaultEntry * entry = (DefaultEntry *)g_hash_table_lookup(prop_table, property);
287 
288 	if (entry == NULL) {
289 		return NULL;
290 	}
291 
292 	return entry->type;
293 }
294 
295