2 * Copyright © 2010 Codethink Limited
3 * Copyright © 2012 Canonical Limited
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the licence, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: Ryan Lortie <desrt@desrt.ca>
23 #include "dconf-writer.h"
25 #include "../shm/dconf-shm.h"
26 #include "dconf-gvdb-utils.h"
27 #include "dconf-generated.h"
28 #include "dconf-blame.h"
37 struct _DConfWriterPrivate
45 DConfChangeset
*uncommited_values
;
46 DConfChangeset
*commited_values
;
48 GQueue uncommited_changes
;
49 GQueue commited_changes
;
54 DConfChangeset
*changeset
;
58 static void dconf_writer_iface_init (DConfDBusWriterIface
*iface
);
60 G_DEFINE_TYPE_WITH_CODE (DConfWriter
, dconf_writer
, DCONF_DBUS_TYPE_WRITER_SKELETON
,
61 G_IMPLEMENT_INTERFACE (DCONF_DBUS_TYPE_WRITER
, dconf_writer_iface_init
))
64 dconf_writer_real_list (GHashTable
*set
)
70 dirname
= g_build_filename (g_get_user_config_dir (), "dconf", NULL
);
71 dir
= g_dir_open (dirname
, 0, NULL
);
76 while ((name
= g_dir_read_name (dir
)))
77 g_hash_table_add (set
, g_strdup (name
));
83 dconf_writer_get_tag (DConfWriter
*writer
)
85 GDBusConnection
*connection
;
87 connection
= g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (writer
));
89 return g_strdup_printf ("%s:%s:%" G_GUINT64_FORMAT
,
90 g_dbus_connection_get_unique_name (connection
),
91 writer
->priv
->name
, writer
->priv
->tag
++);
95 dconf_writer_real_begin (DConfWriter
*writer
,
98 /* If this is the first time, populate the value table with the
101 if (writer
->priv
->commited_values
== NULL
)
103 writer
->priv
->commited_values
= dconf_gvdb_utils_read_file (writer
->priv
->filename
, error
);
105 if (!writer
->priv
->commited_values
)
109 writer
->priv
->uncommited_values
= dconf_changeset_new_database (writer
->priv
->commited_values
);
115 dconf_writer_real_change (DConfWriter
*writer
,
116 DConfChangeset
*changeset
,
119 g_return_if_fail (writer
->priv
->uncommited_values
!= NULL
);
121 dconf_changeset_change (writer
->priv
->uncommited_values
, changeset
);
125 TaggedChange
*change
;
127 change
= g_slice_new (TaggedChange
);
128 change
->changeset
= dconf_changeset_ref (changeset
);
129 change
->tag
= g_strdup (tag
);
131 g_queue_push_tail (&writer
->priv
->uncommited_changes
, change
);
136 dconf_writer_real_commit (DConfWriter
*writer
,
139 gint invalidate_fd
= -1;
141 if (!writer
->priv
->native
)
142 /* If it fails, it doesn't matter... */
143 invalidate_fd
= open (writer
->priv
->filename
, O_WRONLY
);
145 if (!dconf_gvdb_utils_write_file (writer
->priv
->filename
, writer
->priv
->uncommited_values
, error
))
148 if (writer
->priv
->native
)
149 dconf_shm_flag (writer
->priv
->name
);
151 if (invalidate_fd
!= -1)
153 write (invalidate_fd
, "\0\0\0\0\0\0\0\0", 8);
154 close (invalidate_fd
);
157 if (writer
->priv
->commited_values
)
158 dconf_changeset_unref (writer
->priv
->commited_values
);
159 writer
->priv
->commited_values
= writer
->priv
->uncommited_values
;
160 writer
->priv
->uncommited_values
= NULL
;
163 GQueue empty_queue
= G_QUEUE_INIT
;
165 g_assert (g_queue_is_empty (&writer
->priv
->commited_changes
));
166 writer
->priv
->commited_changes
= writer
->priv
->uncommited_changes
;
167 writer
->priv
->uncommited_changes
= empty_queue
;
174 dconf_writer_real_end (DConfWriter
*writer
)
176 while (!g_queue_is_empty (&writer
->priv
->uncommited_changes
))
178 TaggedChange
*change
= g_queue_pop_head (&writer
->priv
->uncommited_changes
);
179 g_free (change
->tag
);
180 g_slice_free (TaggedChange
, change
);
183 while (!g_queue_is_empty (&writer
->priv
->commited_changes
))
185 TaggedChange
*change
= g_queue_pop_head (&writer
->priv
->commited_changes
);
187 const gchar
* const *paths
;
189 dconf_changeset_describe (change
->changeset
, &prefix
, &paths
, NULL
);
190 dconf_dbus_writer_emit_notify_signal (DCONF_DBUS_WRITER (writer
), prefix
, paths
, change
->tag
);
191 dconf_changeset_unref (change
->changeset
);
192 g_free (change
->tag
);
193 g_slice_free (TaggedChange
, change
);
196 g_clear_pointer (&writer
->priv
->uncommited_values
, dconf_changeset_unref
);
200 dconf_writer_begin (DConfWriter
*writer
,
203 return DCONF_WRITER_GET_CLASS (writer
)->begin (writer
, error
);
207 dconf_writer_change (DConfWriter
*writer
,
208 DConfChangeset
*changeset
,
211 DCONF_WRITER_GET_CLASS (writer
)->change (writer
, changeset
, tag
);
215 dconf_writer_commit (DConfWriter
*writer
,
218 return DCONF_WRITER_GET_CLASS (writer
)->commit (writer
, error
);
222 dconf_writer_end (DConfWriter
*writer
)
224 return DCONF_WRITER_GET_CLASS (writer
)->end (writer
);
228 dconf_writer_handle_init (DConfDBusWriter
*dbus_writer
,
229 GDBusMethodInvocation
*invocation
)
231 DConfWriter
*writer
= DCONF_WRITER (dbus_writer
);
232 GError
*error
= NULL
;
234 dconf_blame_record (invocation
);
236 dconf_writer_begin (writer
, &error
) && dconf_writer_commit (writer
, &error
);
240 g_dbus_method_invocation_return_gerror (invocation
, error
);
241 g_error_free (error
);
245 g_dbus_method_invocation_return_value (invocation
, NULL
);
247 dconf_writer_end (writer
);
253 dconf_writer_handle_change (DConfDBusWriter
*dbus_writer
,
254 GDBusMethodInvocation
*invocation
,
257 DConfWriter
*writer
= DCONF_WRITER (dbus_writer
);
258 DConfChangeset
*changeset
;
259 GError
*error
= NULL
;
260 GVariant
*tmp
, *args
;
263 dconf_blame_record (invocation
);
265 tmp
= g_variant_new_from_data (G_VARIANT_TYPE ("a{smv}"),
266 g_variant_get_data (blob
), g_variant_get_size (blob
), FALSE
,
267 (GDestroyNotify
) g_variant_unref
, g_variant_ref (blob
));
268 g_variant_ref_sink (tmp
);
269 args
= g_variant_get_normal_form (tmp
);
270 g_variant_unref (tmp
);
272 changeset
= dconf_changeset_deserialise (args
);
273 g_variant_unref (args
);
275 tag
= dconf_writer_get_tag (writer
);
277 if (!dconf_writer_begin (writer
, &error
))
280 dconf_writer_change (writer
, changeset
, tag
);
281 dconf_changeset_unref (changeset
);
283 if (!dconf_writer_commit (writer
, &error
))
289 g_dbus_method_invocation_return_gerror (invocation
, error
);
290 g_error_free (error
);
294 g_dbus_method_invocation_return_value (invocation
, g_variant_new ("(s)", tag
));
298 dconf_writer_end (writer
);
304 dconf_writer_iface_init (DConfDBusWriterIface
*iface
)
306 iface
->handle_init
= dconf_writer_handle_init
;
307 iface
->handle_change
= dconf_writer_handle_change
;
311 dconf_writer_init (DConfWriter
*writer
)
313 writer
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (writer
, DCONF_TYPE_WRITER
, DConfWriterPrivate
);
314 writer
->priv
->basepath
= g_build_filename (g_get_user_config_dir (), "dconf", NULL
);
315 writer
->priv
->native
= TRUE
;
319 dconf_writer_set_property (GObject
*object
, guint prop_id
,
320 const GValue
*value
, GParamSpec
*pspec
)
322 DConfWriter
*writer
= DCONF_WRITER (object
);
324 g_assert_cmpint (prop_id
, ==, 1);
326 g_assert (!writer
->priv
->name
);
327 writer
->priv
->name
= g_value_dup_string (value
);
329 writer
->priv
->filename
= g_build_filename (writer
->priv
->basepath
, writer
->priv
->name
, NULL
);
333 dconf_writer_class_init (DConfWriterClass
*class)
335 GObjectClass
*object_class
= G_OBJECT_CLASS (class);
337 object_class
->set_property
= dconf_writer_set_property
;
339 class->begin
= dconf_writer_real_begin
;
340 class->change
= dconf_writer_real_change
;
341 class->commit
= dconf_writer_real_commit
;
342 class->end
= dconf_writer_real_end
;
343 class->list
= dconf_writer_real_list
;
345 g_object_class_install_property (object_class
, 1,
346 g_param_spec_string ("name", "name", "name", NULL
,
347 G_PARAM_STATIC_STRINGS
| G_PARAM_CONSTRUCT_ONLY
|
350 g_type_class_add_private (class, sizeof (DConfWriterPrivate
));
354 dconf_writer_set_basepath (DConfWriter
*writer
,
357 g_free (writer
->priv
->basepath
);
358 writer
->priv
->basepath
= g_build_filename (g_get_user_runtime_dir (), "dconf-service", name
, NULL
);
359 writer
->priv
->native
= FALSE
;
363 dconf_writer_get_name (DConfWriter
*writer
)
365 return writer
->priv
->name
;
369 dconf_writer_list (GType type
,
372 DConfWriterClass
*class;
374 g_return_if_fail (g_type_is_a (type
, DCONF_TYPE_WRITER
));
376 class = g_type_class_ref (type
);
378 g_type_class_unref (class);
381 GDBusInterfaceSkeleton
*
382 dconf_writer_new (GType type
,
385 g_return_val_if_fail (g_type_is_a (type
, DCONF_TYPE_WRITER
), NULL
);
387 return g_object_new (type
, "name", name
, NULL
);