2 * Copyright © 2012 Canonical Limited
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the licence, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 * Author: Ryan Lortie <desrt@desrt.ca>
22 #include "dconf-service.h"
24 #include "dconf-generated.h"
25 #include "dconf-writer.h"
26 #include "dconf-blame.h"
28 #include <glib-unix.h>
32 typedef GApplicationClass DConfServiceClass
;
35 GApplication parent_instance
;
37 GIOExtensionPoint
*extension_point
;
46 G_DEFINE_TYPE (DConfService
, dconf_service
, G_TYPE_APPLICATION
)
49 dconf_service_signalled (gpointer user_data
)
51 DConfService
*service
= user_data
;
53 if (!service
->released
)
54 g_application_release (G_APPLICATION (service
));
56 service
->released
= TRUE
;
58 return G_SOURCE_REMOVE
;
62 string_set_free (GHashTable
*set
)
70 n_items
= g_hash_table_size (set
);
71 result
= g_new (gchar
*, n_items
+ 1);
73 g_hash_table_iter_init (&iter
, set
);
74 while (g_hash_table_iter_next (&iter
, &key
, NULL
))
77 g_hash_table_iter_steal (&iter
);
81 g_assert_cmpint (n_items
, ==, i
);
82 g_hash_table_unref (set
);
90 return g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, NULL
);
94 string_set_add (GHashTable
*set
,
97 g_hash_table_add (set
, g_strdup (string
));
101 dconf_service_find_writer_type (DConfService
*service
,
102 const gchar
*object_path
,
103 GHashTable
**writers
)
105 GIOExtension
*extension
;
109 path
= object_path
+ strlen ("/ca/desrt/dconf");
110 g_assert (*path
== '/');
113 extension
= g_io_extension_point_get_extension_by_name (service
->extension_point
, path
);
114 g_assert (extension
!= NULL
);
116 table
= g_hash_table_lookup (service
->writers
, path
);
119 table
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_object_unref
);
120 g_hash_table_insert (service
->writers
, g_strdup (path
), table
);
125 return g_io_extension_get_type (extension
);
129 dconf_service_subtree_enumerate (GDBusConnection
*connection
,
131 const gchar
*object_path
,
134 DConfService
*service
= user_data
;
141 set
= string_set_new ();
142 writer_type
= dconf_service_find_writer_type (service
, object_path
, &writers
);
143 g_hash_table_iter_init (&iter
, writers
);
144 while (g_hash_table_iter_next (&iter
, &key
, NULL
))
145 string_set_add (set
, key
);
147 dconf_writer_list (writer_type
, set
);
149 return string_set_free (set
);
152 static GDBusInterfaceInfo
**
153 dconf_service_subtree_introspect (GDBusConnection
*connection
,
155 const gchar
*object_path
,
159 GDBusInterfaceInfo
**result
;
164 result
= g_new (GDBusInterfaceInfo
*, 2);
165 result
[0] = dconf_dbus_writer_interface_info ();
172 dconf_service_get_writer (DConfService
*service
,
173 GDBusConnection
*connection
,
174 const gchar
*base_path
,
177 GDBusInterfaceSkeleton
*writer
;
181 writer_type
= dconf_service_find_writer_type (service
, base_path
, &writers
);
183 writer
= g_hash_table_lookup (writers
, name
);
187 GError
*error
= NULL
;
190 writer
= dconf_writer_new (writer_type
, name
);
191 g_hash_table_insert (writers
, g_strdup (name
), writer
);
192 object_path
= g_strjoin ("/", base_path
, name
, NULL
);
193 g_dbus_interface_skeleton_export (writer
, connection
, object_path
, &error
);
194 g_assert_no_error (error
);
195 g_free (object_path
);
201 static const GDBusInterfaceVTable
*
202 dconf_service_subtree_dispatch (GDBusConnection
*connection
,
204 const gchar
*object_path
,
205 const gchar
*interface_name
,
207 gpointer
*out_user_data
,
210 DConfService
*service
= user_data
;
212 g_assert_cmpstr (interface_name
, ==, "ca.desrt.dconf.Writer");
213 g_assert (node
!= NULL
);
215 *out_user_data
= dconf_service_get_writer (service
, connection
, object_path
, node
);
217 return g_dbus_interface_skeleton_get_vtable (*out_user_data
);
221 dconf_service_dbus_register (GApplication
*application
,
222 GDBusConnection
*connection
,
223 const gchar
*object_path
,
226 const GDBusSubtreeVTable subtree_vtable
= {
227 dconf_service_subtree_enumerate
,
228 dconf_service_subtree_introspect
,
229 dconf_service_subtree_dispatch
231 DConfService
*service
= DCONF_SERVICE (application
);
232 GError
*local_error
= NULL
;
236 service
->extension_point
= g_io_extension_point_register ("dconf-backend");
237 g_io_extension_point_set_required_type (service
->extension_point
, DCONF_TYPE_WRITER
);
238 g_io_extension_point_implement ("dconf-backend", DCONF_TYPE_WRITER
, "Writer", 0);
239 g_io_extension_point_implement ("dconf-backend", DCONF_TYPE_KEYFILE_WRITER
, "keyfile", 0);
240 g_io_extension_point_implement ("dconf-backend", DCONF_TYPE_SHM_WRITER
, "shm", 0);
242 service
->blame
= dconf_blame_get ();
245 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (service
->blame
),
246 connection
, object_path
, &local_error
);
247 g_assert_no_error (local_error
);
250 for (node
= g_io_extension_point_get_extensions (service
->extension_point
); node
; node
= node
->next
)
254 path
= g_strconcat ("/ca/desrt/dconf/", g_io_extension_get_name (node
->data
), NULL
);
255 id
= g_dbus_connection_register_subtree (connection
, path
, &subtree_vtable
,
256 G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES
,
257 g_object_ref (service
), g_object_unref
, &local_error
);
258 g_assert_no_error (local_error
);
259 g_array_append_vals (service
->subtree_ids
, &id
, 1);
267 dconf_service_dbus_unregister (GApplication
*application
,
268 GDBusConnection
*connection
,
269 const gchar
*object_path
)
271 DConfService
*service
= DCONF_SERVICE (application
);
276 g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (service
->blame
));
277 g_object_unref (service
->blame
);
278 service
->blame
= NULL
;
281 for (i
= 0; i
< service
->subtree_ids
->len
; i
++)
282 g_dbus_connection_unregister_subtree (connection
, g_array_index (service
->subtree_ids
, guint
, i
));
283 g_array_set_size (service
->subtree_ids
, 0);
287 dconf_service_startup (GApplication
*application
)
289 DConfService
*service
= DCONF_SERVICE (application
);
291 G_APPLICATION_CLASS (dconf_service_parent_class
)
292 ->startup (application
);
294 g_unix_signal_add (SIGTERM
, dconf_service_signalled
, service
);
295 g_unix_signal_add (SIGINT
, dconf_service_signalled
, service
);
296 g_unix_signal_add (SIGHUP
, dconf_service_signalled
, service
);
298 g_application_hold (application
);
302 dconf_service_shutdown (GApplication
*application
)
304 G_APPLICATION_CLASS (dconf_service_parent_class
)
305 ->shutdown (application
);
309 dconf_service_init (DConfService
*service
)
311 service
->writers
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_object_unref
);
312 service
->subtree_ids
= g_array_new (FALSE
, TRUE
, sizeof (guint
));
316 dconf_service_finalize (GObject
*object
)
318 DConfService
*service
= (DConfService
*) object
;
320 g_assert_cmpint (service
->subtree_ids
->len
, ==, 0);
321 g_array_free (service
->subtree_ids
, TRUE
);
323 G_OBJECT_CLASS (dconf_service_parent_class
)->finalize (object
);
327 dconf_service_class_init (GApplicationClass
*class)
329 GObjectClass
*object_class
= G_OBJECT_CLASS (class);
331 object_class
->finalize
= dconf_service_finalize
;
333 class->dbus_register
= dconf_service_dbus_register
;
334 class->dbus_unregister
= dconf_service_dbus_unregister
;
335 class->startup
= dconf_service_startup
;
336 class->shutdown
= dconf_service_shutdown
;
340 dconf_service_new (void)
342 return g_object_new (DCONF_TYPE_SERVICE
,
343 "application-id", "ca.desrt.dconf",
344 "flags", G_APPLICATION_IS_SERVICE
,