gconf r2628 - in trunk: . defaults gconf po



Author: matthiasc
Date: Fri Jul 11 16:34:29 2008
New Revision: 2628
URL: http://svn.gnome.org/viewvc/gconf?rev=2628&view=rev

Log:
2008-07-11  Matthias Clasen  <mclasen redhat com>

        Bug 531169 â A mechanism for setting defaults

        The cache-clearing part of this patch is thanks
        to Behdad Esfahbod.

        * defaults/*: A DBus system bus service that can copy a
        subtree of GConf values from the callers db to a system-wide
        db, using PolicyKit to control access.

        * configure.in: Add --enable-defaults-service to optionally
        build the defaults service.

        * gconf/gconf-database.[hc]: Add
        gconf_database_clear_cache_for_sources.

        * gconf/gconf-sources.[hc]: Add gconf_sources_clear_cache_for_sources.

        * gconf/gconfd.c: Listen for changes in the system-wide
        databases by the defaults service, and clear the cache.

        * po/POTFILES.in: Glue
        * Makefile.am: Glue




Added:
   trunk/defaults/
   trunk/defaults/Makefile.am
   trunk/defaults/gconf-defaults-main.c
   trunk/defaults/gconf-defaults.c
   trunk/defaults/gconf-defaults.h
   trunk/defaults/gconf-defaults.xml
   trunk/defaults/org.gnome.GConf.Defaults.conf
   trunk/defaults/org.gnome.GConf.Defaults.service.in
   trunk/defaults/org.gnome.gconf.defaults.policy.in
Modified:
   trunk/ChangeLog
   trunk/Makefile.am
   trunk/configure.in
   trunk/gconf/gconf-database.c
   trunk/gconf/gconf-database.h
   trunk/gconf/gconf-sources.c
   trunk/gconf/gconf-sources.h
   trunk/gconf/gconfd.c
   trunk/po/POTFILES.in

Modified: trunk/Makefile.am
==============================================================================
--- trunk/Makefile.am	(original)
+++ trunk/Makefile.am	Fri Jul 11 16:34:29 2008
@@ -1,6 +1,10 @@
 
-SUBDIRS = gconf backends po doc examples
-DIST_SUBDIRS=tests $(SUBDIRS)
+SUBDIRS = gconf backends po doc examples 
+DIST_SUBDIRS=tests defaults $(SUBDIRS) 
+
+if ENABLE_DEFAULTS_SERVICE
+SUBDIRS += defaults
+endif
 
 EXTRA_DIST =                \
 	TODO                \

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Fri Jul 11 16:34:29 2008
@@ -166,6 +166,30 @@
 AC_SUBST(DEPENDENT_WITH_XML_AND_GTK_LIBS)
 AC_SUBST(DEPENDENT_WITH_XML_AND_GTK_CFLAGS)
 
+AC_ARG_ENABLE(defaults-service,
+              [AC_HELP_STRING([--enable-defaults-service],
+                              [build the defaults DBus service [default=auto]])],
+              [enable_defaults_service="$enableval"],
+              [enable_defaults_service=auto])
+if test "x$enable_defaults_service" != "xno" ; then
+  PKG_CHECK_MODULES(DEFAULTS, glib-2.0 gobject-2.0 dbus-1 dbus-glib-1 polkit-dbus, HAVE_POLKIT=yes, HAVE_POLKIT=no)
+  if test "x$HAVE_POLKIT" = "xno"; then
+    if test "x$enable_defaults_service" = "xyes" ; then
+      AC_MSG_ERROR([[
+*** Could not find PolicyKit.]])
+    else
+      enable_defaults_service=no
+    fi
+  else
+    enable_defaults_service=yes
+  fi
+fi
+
+if test "x$enable_defaults_service" != "xno" ; then
+  AC_DEFINE(ENABLE_DEFAULTS_SERVICE, 1, [enable defaults DBus service])
+fi
+
+AM_CONDITIONAL(ENABLE_DEFAULTS_SERVICE, [test "x$enable_defaults_service" != "xno"])
 
 ORBIT_IDL="`$PKG_CONFIG --variable=orbit_idl ORBit-2.0`"
 AC_SUBST(ORBIT_IDL)
@@ -261,6 +285,7 @@
 doc/gconf/Makefile
 examples/Makefile
 tests/Makefile
+defaults/Makefile
 gconf-2.0.pc
 ])
 

Added: trunk/defaults/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/defaults/Makefile.am	Fri Jul 11 16:34:29 2008
@@ -0,0 +1,56 @@
+libexec_PROGRAMS = gconf-defaults-mechanism
+
+gconf-defaults-glue.h: $(srcdir)/gconf-defaults.xml
+	dbus-binding-tool --prefix=gconf_defaults --mode=glib-server      \
+			  --output=gconf-defaults-glue.h                  \
+			  $(srcdir)/gconf-defaults.xml
+
+
+gconf_defaults_mechanism_SOURCES = \
+	gconf-defaults.h \
+	gconf-defaults.c \
+	gconf-defaults-glue.h \
+	gconf-defaults-main.c
+
+INCLUDES = \
+	-I$(top_srcdir) \
+	-I$(top_builddir) \
+	$(DEFAULTS_CFLAGS)
+
+gconf_defaults_mechanism_LDADD = \
+	$(top_builddir)/gconf/libgconf-2.la \
+	$(DEFAULTS_LIBS) 
+
+BUILT_SOURCES = gconf-defaults-glue.h
+
+dbus_servicesdir = $(datadir)/dbus-1/system-services
+dbus_confdir = $(sysconfdir)/dbus-1/system.d
+polkitdir = $(datadir)/PolicyKit/policy
+
+dbus_services_in_files = org.gnome.GConf.Defaults.service.in
+polkit_in_files = org.gnome.gconf.defaults.policy.in
+
+dbus_services_DATA = $(dbus_services_in_files:.service.in=.service)
+
+$(dbus_services_DATA): $(dbus_services_in_files)
+	sed -e "s|\ LIBEXECDIR\@|$(libexecdir)|" $< > $@
+
+dbus_conf_DATA = org.gnome.GConf.Defaults.conf
+
+ INTLTOOL_POLICY_RULE@
+polkit_DATA = $(polkit_in_files:.policy.in=.policy)
+
+check:
+	$(POLKIT_POLICY_FILE_VALIDATE) $(polkit_DATA)
+
+EXTRA_DIST =					\
+	$(dbus_services_in_files)		\
+	org.gnome.GConf.Defaults.conf		\
+	$(polkit_in_files)			\
+	gconf-defaults.xml
+
+CLEANFILES =			\
+	$(BUILT_SOURCES)	\
+	$(polkit_DATA)		\
+	$(dbus_services_DATA)
+

Added: trunk/defaults/gconf-defaults-main.c
==============================================================================
--- (empty file)
+++ trunk/defaults/gconf-defaults-main.c	Fri Jul 11 16:34:29 2008
@@ -0,0 +1,174 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Matthias Clasen <mclasen redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+
+#include "gconf-defaults.h"
+
+static DBusGProxy *
+get_bus_proxy (DBusGConnection *connection)
+{
+        DBusGProxy *bus_proxy;
+
+	bus_proxy = dbus_g_proxy_new_for_name (connection,
+                                               DBUS_SERVICE_DBUS,
+                                               DBUS_PATH_DBUS,
+                                               DBUS_INTERFACE_DBUS);
+        return bus_proxy;
+}
+
+#define BUS_NAME "org.gnome.GConf.Defaults"
+
+static gboolean
+acquire_name_on_proxy (DBusGProxy *bus_proxy)
+{
+        GError     *error;
+        guint       result;
+        gboolean    res;
+        gboolean    ret;
+
+        ret = FALSE;
+
+        if (bus_proxy == NULL) {
+                goto out;
+        }
+
+        error = NULL;
+	res = dbus_g_proxy_call (bus_proxy,
+                                 "RequestName",
+                                 &error,
+                                 G_TYPE_STRING, BUS_NAME,
+                                 G_TYPE_UINT, 0,
+                                 G_TYPE_INVALID,
+                                 G_TYPE_UINT, &result,
+                                 G_TYPE_INVALID);
+        if (! res) {
+                if (error != NULL) {
+                        g_warning ("Failed to acquire %s: %s", BUS_NAME, error->message);
+                        g_error_free (error);
+                } else {
+                        g_warning ("Failed to acquire %s", BUS_NAME);
+                }
+                goto out;
+	}
+
+ 	if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+                if (error != NULL) {
+                        g_warning ("Failed to acquire %s: %s", BUS_NAME, error->message);
+                        g_error_free (error);
+                } else {
+                        g_warning ("Failed to acquire %s", BUS_NAME);
+                }
+                goto out;
+        }
+
+        ret = TRUE;
+
+ out:
+        return ret;
+}
+
+static DBusGConnection *
+get_system_bus (void)
+{
+        GError          *error;
+        DBusGConnection *bus;
+        DBusConnection  *connection;
+
+        error = NULL;
+        bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+        if (bus == NULL) {
+                g_warning ("Couldn't connect to system bus: %s", error->message);
+                g_error_free (error);
+                goto out;
+        }
+
+        connection = dbus_g_connection_get_connection (bus);
+ out:
+        return bus;
+}
+
+int
+main (int argc, char **argv)
+{
+        GMainLoop           *loop;
+        GConfDefaults       *mechanism;
+        DBusGProxy          *bus_proxy;
+        DBusGConnection     *connection;
+        int                  ret;
+
+        ret = 1;
+
+        if (! g_thread_supported ()) {
+                g_thread_init (NULL);
+        }
+        dbus_g_thread_init ();
+        g_type_init ();
+
+        connection = get_system_bus ();
+        if (connection == NULL) {
+                goto out;
+        }
+
+        bus_proxy = get_bus_proxy (connection);
+        if (bus_proxy == NULL) {
+                g_warning ("Could not construct bus_proxy object; bailing out");
+                goto out;
+        }
+
+        mechanism = gconf_defaults_new ();
+
+        if (mechanism == NULL) {
+                goto out;
+        }
+
+        if (!acquire_name_on_proxy (bus_proxy)) {
+                g_warning ("Could not acquire name; bailing out");
+                goto out;
+        }
+
+        loop = g_main_loop_new (NULL, FALSE);
+
+        g_main_loop_run (loop);
+
+        g_object_unref (mechanism);
+        g_main_loop_unref (loop);
+        ret = 0;
+
+out:
+        return ret;
+}

Added: trunk/defaults/gconf-defaults.c
==============================================================================
--- (empty file)
+++ trunk/defaults/gconf-defaults.c	Fri Jul 11 16:34:29 2008
@@ -0,0 +1,753 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Matthias Clasen <mclasen redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <polkit-dbus/polkit-dbus.h>
+#include <polkit/polkit.h>
+
+#define GCONF_ENABLE_INTERNALS
+#include <gconf/gconf-client.h>
+#include <gconf/gconf-engine.h>
+
+#include "gconf-defaults.h"
+#include "gconf-defaults-glue.h"
+
+static gboolean
+do_exit (gpointer user_data)
+{
+        g_debug ("Exiting due to inactivity");
+        exit (1);
+        return FALSE;
+}
+
+static guint timer_id = 0;
+
+static void
+stop_killtimer (void)
+{
+        if (timer_id > 0) {
+                g_source_remove (timer_id);
+		timer_id = 0;
+        }
+}
+
+static void
+start_killtimer (void)
+{
+        g_debug ("Setting killtimer to 30 seconds...");
+        timer_id = g_timeout_add_seconds (30, do_exit, NULL);
+}
+
+struct GConfDefaultsPrivate
+{
+        DBusGConnection *system_bus_connection;
+        DBusGProxy      *system_bus_proxy;
+        PolKitContext   *pol_ctx;
+};
+
+static void gconf_defaults_finalize (GObject *object);
+
+G_DEFINE_TYPE (GConfDefaults, gconf_defaults, G_TYPE_OBJECT)
+
+#define GCONF_DEFAULTS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GCONF_TYPE_DEFAULTS, GConfDefaultsPrivate))
+
+GQuark
+gconf_defaults_error_quark (void)
+{
+        static GQuark ret = 0;
+
+        if (ret == 0) {
+                ret = g_quark_from_static_string ("gconf_defaults_error");
+        }
+
+        return ret;
+}
+
+
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType
+gconf_defaults_error_get_type (void)
+{
+        static GType etype = 0;
+        
+        if (etype == 0)
+        {
+                static const GEnumValue values[] =
+                        {
+                                ENUM_ENTRY (GCONF_DEFAULTS_ERROR_GENERAL, "GeneralError"),
+                                ENUM_ENTRY (GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED, "NotPrivileged"),
+                                { 0, 0, 0 }
+                        };
+                
+                g_assert (GCONF_DEFAULTS_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
+                
+                etype = g_enum_register_static ("GConfDefaultsError", values);
+        }
+        
+        return etype;
+}
+
+
+static GObject *
+gconf_defaults_constructor (GType                  type,
+                            guint                  n_construct_properties,
+                            GObjectConstructParam *construct_properties)
+{
+        GConfDefaults      *mechanism;
+        GConfDefaultsClass *klass;
+
+        klass = GCONF_DEFAULTS_CLASS (g_type_class_peek (GCONF_TYPE_DEFAULTS));
+
+        mechanism = GCONF_DEFAULTS (G_OBJECT_CLASS (gconf_defaults_parent_class)->constructor (
+                                                type,
+                                                n_construct_properties,
+                                                construct_properties));
+
+        return G_OBJECT (mechanism);
+}
+
+enum {
+	SYSTEM_SET,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+gconf_defaults_class_init (GConfDefaultsClass *klass)
+{
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+
+        object_class->constructor = gconf_defaults_constructor;
+        object_class->finalize = gconf_defaults_finalize;
+
+	signals[SYSTEM_SET] = g_signal_new ("system-set",
+					    G_OBJECT_CLASS_TYPE (object_class),
+					    G_SIGNAL_RUN_FIRST,
+					    G_STRUCT_OFFSET (GConfDefaultsClass, system_set),
+					    NULL, NULL,
+					    g_cclosure_marshal_VOID__BOXED,
+					    G_TYPE_NONE, 1, G_TYPE_STRV);
+ 
+        g_type_class_add_private (klass, sizeof (GConfDefaultsPrivate));
+
+        dbus_g_object_type_install_info (GCONF_TYPE_DEFAULTS, &dbus_glib_gconf_defaults_object_info);
+
+        dbus_g_error_domain_register (GCONF_DEFAULTS_ERROR, NULL, GCONF_DEFAULTS_TYPE_ERROR);
+
+}
+
+static void
+gconf_defaults_init (GConfDefaults *mechanism)
+{
+        mechanism->priv = GCONF_DEFAULTS_GET_PRIVATE (mechanism);
+}
+
+static void
+gconf_defaults_finalize (GObject *object)
+{
+        GConfDefaults *mechanism;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (GCONF_IS_DEFAULTS (object));
+
+        mechanism = GCONF_DEFAULTS (object);
+
+        g_return_if_fail (mechanism->priv != NULL);
+
+        g_object_unref (mechanism->priv->system_bus_proxy);
+
+        G_OBJECT_CLASS (gconf_defaults_parent_class)->finalize (object);
+}
+
+static gboolean
+pk_io_watch_have_data (GIOChannel *channel, GIOCondition condition, gpointer user_data)
+{
+        int fd;
+        PolKitContext *pk_context = user_data;
+        fd = g_io_channel_unix_get_fd (channel);
+        polkit_context_io_func (pk_context, fd);
+        return TRUE;
+}
+
+static int 
+pk_io_add_watch (PolKitContext *pk_context, int fd)
+{
+        guint id = 0;
+        GIOChannel *channel;
+        channel = g_io_channel_unix_new (fd);
+        if (channel == NULL)
+                goto out;
+        id = g_io_add_watch (channel, G_IO_IN, pk_io_watch_have_data, pk_context);
+        if (id == 0) {
+                g_io_channel_unref (channel);
+                goto out;
+        }
+        g_io_channel_unref (channel);
+out:
+        return id;
+}
+
+static void 
+pk_io_remove_watch (PolKitContext *pk_context, int watch_id)
+{
+        g_source_remove (watch_id);
+}
+
+static gboolean
+register_mechanism (GConfDefaults *mechanism)
+{
+        GError *error = NULL;
+
+        mechanism->priv->pol_ctx = polkit_context_new ();
+        polkit_context_set_io_watch_functions (mechanism->priv->pol_ctx, pk_io_add_watch, pk_io_remove_watch);
+        if (!polkit_context_init (mechanism->priv->pol_ctx, NULL)) {
+                g_critical ("cannot initialize libpolkit");
+                goto error;
+        }
+
+        error = NULL;
+        mechanism->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+        if (mechanism->priv->system_bus_connection == NULL) {
+                if (error != NULL) {
+                        g_critical ("error getting system bus: %s", error->message);
+                        g_error_free (error);
+                }
+                goto error;
+        }
+
+        dbus_g_connection_register_g_object (mechanism->priv->system_bus_connection, "/", 
+                                             G_OBJECT (mechanism));
+
+        mechanism->priv->system_bus_proxy = dbus_g_proxy_new_for_name (mechanism->priv->system_bus_connection,
+                                                                      DBUS_SERVICE_DBUS,
+                                                                      DBUS_PATH_DBUS,
+                                                                      DBUS_INTERFACE_DBUS);
+
+        start_killtimer ();
+
+        return TRUE;
+
+error:
+        return FALSE;
+}
+
+
+GConfDefaults *
+gconf_defaults_new (void)
+{
+        GObject *object;
+        gboolean res;
+
+        object = g_object_new (GCONF_TYPE_DEFAULTS, NULL);
+
+        res = register_mechanism (GCONF_DEFAULTS (object));
+        if (! res) {
+                g_object_unref (object);
+                return NULL;
+        }
+
+        return GCONF_DEFAULTS (object);
+}
+
+static const char *
+polkit_action_for_gconf_path (GConfDefaults *mechanism,
+			      const char    *annotation_key,
+			      const char    *path)
+{
+	PolKitPolicyCache *cache;
+	PolKitPolicyFileEntry *entry;
+	char *prefix, *p;
+	const char *action;
+
+	cache = polkit_context_get_policy_cache (mechanism->priv->pol_ctx);	
+	prefix = g_strdup (path);
+
+	while (1) {
+		entry = polkit_policy_cache_get_entry_by_annotation (cache,
+								     annotation_key,
+								     prefix);
+		if (entry) {
+			action = polkit_policy_file_entry_get_id (entry);
+			break;
+		}
+		
+		p = strrchr (prefix, '/');
+
+		if (p == NULL || p == prefix) {
+			action = NULL;
+			break;
+		}
+	
+		*p = 0;
+	}
+
+	g_free (prefix);
+
+	return action;
+}
+
+static gboolean
+check_polkit_for_action (GConfDefaults         *mechanism,
+                         DBusGMethodInvocation *context,
+                         const char            *action)
+{
+        const char *sender;
+        GError *error;
+        DBusError dbus_error;
+        PolKitCaller *pk_caller;
+        PolKitAction *pk_action;
+        PolKitResult pk_result;
+
+        error = NULL;
+
+        /* Check that caller is privileged */
+        sender = dbus_g_method_get_sender (context);
+        dbus_error_init (&dbus_error);
+        pk_caller = polkit_caller_new_from_dbus_name (
+                dbus_g_connection_get_connection (mechanism->priv->system_bus_connection),
+                sender,
+                &dbus_error);
+        if (pk_caller == NULL) {
+                error = g_error_new (GCONF_DEFAULTS_ERROR,
+                                     GCONF_DEFAULTS_ERROR_GENERAL,
+                                     "Error getting information about caller: %s: %s",
+                                     dbus_error.name, dbus_error.message);
+                dbus_error_free (&dbus_error);
+                dbus_g_method_return_error (context, error);
+                g_error_free (error);
+                return FALSE;
+        }
+
+        pk_action = polkit_action_new ();
+        polkit_action_set_action_id (pk_action, action);
+        pk_result = polkit_context_is_caller_authorized (mechanism->priv->pol_ctx, pk_action, pk_caller, TRUE, NULL);
+        polkit_caller_unref (pk_caller);
+
+        if (pk_result != POLKIT_RESULT_YES) {
+		dbus_error_init (&dbus_error);
+		polkit_dbus_error_generate (pk_action, pk_result, &dbus_error);
+		dbus_set_g_error (&error, &dbus_error);
+                dbus_g_method_return_error (context, error);
+                dbus_error_free (&dbus_error);
+                g_error_free (error);
+        	polkit_action_unref (pk_action);
+                return FALSE;
+        }
+
+        polkit_action_unref (pk_action);
+        return TRUE;
+}
+
+static char *
+gconf_address_for_caller (GConfDefaults          *mechanism,
+			  DBusGMethodInvocation  *context,
+			  GError                **gerror)
+{
+        char *sender;
+	DBusConnection *conn;
+	uid_t uid;
+	struct passwd *pwd;
+	char *result;
+	DBusError error;
+
+	conn = dbus_g_connection_get_connection (mechanism->priv->system_bus_connection);
+        sender = dbus_g_method_get_sender (context);
+
+	dbus_error_init (&error);
+	uid = dbus_bus_get_unix_user (conn, sender, &error);
+	g_free (sender);
+	if (uid == (unsigned)-1) {
+		dbus_set_g_error (gerror, &error);
+		dbus_error_free (&error);
+		return NULL;
+	}
+	
+	pwd = getpwuid (uid);
+	if (pwd == NULL) {
+		g_set_error (gerror, 
+			     0, 0, 
+			     "Failed to get passwd information for uid %d", uid);
+		return NULL;
+	}
+
+	result = g_strconcat ("xml:merged:", pwd->pw_dir, "/.gconf", NULL);
+	return result;
+}
+
+static gboolean
+path_is_excluded (const char  *path,
+		  const char **excludes)
+{
+	int i;
+
+	for (i = 0; excludes && excludes[i]; i++) {
+		if (g_str_has_prefix (path, excludes[i]))
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void
+copy_tree (GConfClient     *src,
+	   const char      *path,
+	   GConfChangeSet  *changes,
+	   const char     **excludes)
+{
+	GSList *list, *l;
+	GConfEntry *entry;
+
+	if (path_is_excluded (path, excludes)) 
+		return;
+
+	list = gconf_client_all_entries (src, path, NULL);
+	for (l = list; l; l = l->next) {
+		entry = l->data;
+		if (!path_is_excluded (entry->key, excludes)) 
+			gconf_change_set_set (changes, entry->key, entry->value);
+	}
+	g_slist_foreach (list, (GFunc)gconf_entry_free, NULL);
+	g_slist_free (list);
+
+	list = gconf_client_all_dirs (src, path, NULL);
+	for (l = list; l; l = l->next)
+		copy_tree (src, (const char *)l->data, changes, excludes);
+	g_slist_foreach (list, (GFunc)g_free, NULL);
+	g_slist_free (list);
+}
+
+static void
+copy_entry (GConfClient     *src,
+	    const char      *path,
+	    GConfChangeSet  *changes,
+	    const char     **excludes)
+{
+	GConfValue *value;
+
+	if (path_is_excluded (path, excludes)) 
+		return;
+
+	value = gconf_client_get (src, path, NULL);
+	if (value) {
+		gconf_change_set_set (changes, path, value);
+		gconf_value_free (value);
+	}
+}
+
+
+static void
+do_copy (GConfDefaults          *mechanism,
+	 gboolean                mandatory,
+	 const char            **includes,
+	 const char            **excludes,
+	 DBusGMethodInvocation  *context,
+	 GConfChangeSet        **changeset_out)
+{
+        char *address = NULL;
+	GConfClient *source = NULL; 
+	GConfClient *dest = NULL;
+	GConfChangeSet *changes = NULL;
+	GConfEngine *engine;
+	GError *error;
+	GError *error2;
+	const char *action;
+	const char *annotation_key;
+	const char *default_action;
+	const char *dest_address;
+	int i;
+
+	if (changeset_out)
+		*changeset_out = NULL;
+
+        stop_killtimer ();
+
+	/* check privileges for each include */
+	if (mandatory) {
+		annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix"; 
+		default_action = "org.gnome.gconf.defaults.set-mandatory";
+		dest_address = "xml:merged:/etc/gconf/gconf.xml.mandatory";
+	}
+	else {
+		annotation_key = "org.gnome.gconf.defaults.set-system.prefix"; 
+		default_action = "org.gnome.gconf.defaults.set-system";
+		dest_address = "xml:merged:/etc/gconf/gconf.xml.system";
+	}
+
+	for (i = 0; includes[i]; i++) {
+		action = polkit_action_for_gconf_path (mechanism, annotation_key, includes[i]);
+		if (action == NULL) 
+			action = default_action;
+
+		if (!check_polkit_for_action (mechanism, context, action)) 
+			goto out;
+	}
+
+	error = NULL;
+	engine = gconf_engine_get_local (dest_address, &error);
+	if (error) 
+		goto cleanup;	
+
+	dest = gconf_client_get_for_engine (engine);
+	gconf_engine_unref (engine);
+
+	/* find the address to from the caller id */
+        address = gconf_address_for_caller (mechanism, context, &error);
+	if (error)
+		goto cleanup;
+
+	engine = gconf_engine_get_local (address, &error);
+	if (error) 
+		goto cleanup;
+
+	source = gconf_client_get_for_engine (engine);
+	gconf_engine_unref (engine);
+
+	changes = gconf_change_set_new ();
+
+ 	/* recursively copy each include, leaving out the excludes */
+	for (i = 0; includes[i]; i++) {
+		if (gconf_client_dir_exists (source, includes[i], NULL))
+			copy_tree (source, includes[i], changes, excludes);
+		else
+			copy_entry (source, includes[i], changes, excludes);
+	}
+
+	gconf_client_commit_change_set (dest, changes, FALSE, &error);
+	gconf_client_suggest_sync (dest, NULL);
+
+	if (changeset_out) {
+		*changeset_out = changes;
+		changes = NULL;
+	}
+
+cleanup:
+	g_free (address);
+	if (changes)
+		gconf_change_set_unref (changes);
+	if (dest) 
+		g_object_unref (dest);
+	if (source)
+		g_object_unref (source);
+
+	if (error) {
+		g_print ("failed to set GConf values:  %s\n", error->message);
+		error2 = g_error_new (GCONF_DEFAULTS_ERROR,
+				      GCONF_DEFAULTS_ERROR_GENERAL,
+				      error->message);
+		g_error_free (error);
+
+		dbus_g_method_return_error (context, error2);
+		g_error_free (error2);
+	}
+	else
+        	dbus_g_method_return (context);
+
+out:
+	start_killtimer ();
+}
+
+static void
+append_key (GConfChangeSet *cs,
+	    const gchar *key,
+	    GConfValue *value,
+	    gpointer user_data)
+{
+	GPtrArray *keys = (GPtrArray *) user_data;
+
+	g_ptr_array_add (keys, (gpointer) key);
+}
+
+void
+gconf_defaults_set_system (GConfDefaults          *mechanism,
+			   const char            **includes,
+			   const char            **excludes,
+			   DBusGMethodInvocation  *context)
+{
+	GConfChangeSet *changes = NULL;
+	GPtrArray *keys;
+
+	do_copy (mechanism, FALSE, includes, excludes, context, &changes);
+
+	if (!changes)
+		return;
+
+	keys = g_ptr_array_new ();
+	gconf_change_set_foreach (changes, append_key, keys);
+	g_ptr_array_add (keys, NULL);
+
+	g_signal_emit (mechanism, signals[SYSTEM_SET], 0, keys->pdata);
+
+	g_ptr_array_free (keys, TRUE);
+	gconf_change_set_unref (changes);
+}
+
+void
+gconf_defaults_set_mandatory (GConfDefaults          *mechanism,
+                              const char            **includes,
+                              const char            **excludes,
+                              DBusGMethodInvocation  *context)
+{
+	do_copy (mechanism, TRUE, includes, excludes, context, NULL);
+}
+
+static void
+unset_tree (GConfClient     *dest,
+            const char      *path,
+	    GConfChangeSet  *changes,
+            const char     **excludes)
+{
+	GSList *list, *l;
+	GConfEntry *entry;
+
+	if (path_is_excluded (path, excludes)) 
+		return;
+
+	list = gconf_client_all_entries (dest, path, NULL);
+	for (l = list; l; l = l->next) {
+		entry = l->data;
+		if (!path_is_excluded (entry->key, excludes)) 
+			gconf_change_set_unset (changes, entry->key);
+	}
+	g_slist_foreach (list, (GFunc)gconf_entry_free, NULL);
+	g_slist_free (list);
+
+	list = gconf_client_all_dirs (dest, path, NULL);
+	for (l = list; l; l = l->next)
+		unset_tree (dest, (const char *)l->data, changes, excludes);
+	g_slist_foreach (list, (GFunc)g_free, NULL);
+	g_slist_free (list);
+}
+            
+static void
+unset_entry (GConfClient     *dest,
+             const char      *path,
+	     GConfChangeSet  *changes,
+             const char     **excludes)
+{
+	if (path_is_excluded (path, excludes)) 
+		return;
+
+	gconf_change_set_unset (changes, path);
+}
+            
+static void
+unset_in_db (GConfDefaults  *mechanism,
+	     const char     *address,
+             const char    **includes,
+             const char    **excludes,
+	     GError        **error)
+{
+	GConfEngine *engine;
+	GConfClient *dest = NULL;
+	GConfChangeSet *changes = NULL;
+	int i;
+
+	engine = gconf_engine_get_local (address, error);
+	if (*error) 
+		goto out;
+
+	dest = gconf_client_get_for_engine (engine);
+	gconf_engine_unref (engine);
+
+	changes = gconf_change_set_new ();
+
+ 	/* recursively copy each include, leaving out the excludes */
+	for (i = 0; includes[i]; i++) {
+		if (gconf_client_dir_exists (dest, includes[i], NULL))
+			unset_tree (dest, includes[i], changes, excludes);
+		else
+			unset_entry (dest, includes[i], changes, excludes);
+	}
+
+	gconf_client_commit_change_set (dest, changes, TRUE, error);
+	gconf_client_suggest_sync (dest, NULL);
+
+out:
+	if (dest)
+		g_object_unref (dest);
+	if (changes)
+		gconf_change_set_unref (changes);
+}
+
+void
+gconf_defaults_unset_mandatory (GConfDefaults          *mechanism,
+                                const char            **includes,
+                                const char            **excludes,
+                                DBusGMethodInvocation  *context)
+{
+	const char *annotation_key;
+	const char *default_action;
+	int i;
+	const char *action;
+	GError *error;
+	GError *error2;
+
+	stop_killtimer ();
+
+	annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix"; 
+	default_action = "org.gnome.gconf.defaults.set-mandatory";
+
+	for (i = 0; includes[i]; i++) {
+		action = polkit_action_for_gconf_path (mechanism, annotation_key, includes[i]);
+		if (action == NULL) 
+			action = default_action;
+
+		if (!check_polkit_for_action (mechanism, context, action)) 
+			goto out;
+	}
+
+	error = NULL;
+	unset_in_db (mechanism,"xml:merged:/etc/gconf/gconf.xml.mandatory", 
+		     includes, excludes, &error);
+
+	if (error) {
+		error2 = g_error_new (GCONF_DEFAULTS_ERROR,
+				      GCONF_DEFAULTS_ERROR_GENERAL,
+				      error->message);
+		g_error_free (error);
+
+		dbus_g_method_return_error (context, error2);
+		g_error_free (error2);
+	}
+	else
+        	dbus_g_method_return (context);
+out:
+	start_killtimer();
+}

Added: trunk/defaults/gconf-defaults.h
==============================================================================
--- (empty file)
+++ trunk/defaults/gconf-defaults.h	Fri Jul 11 16:34:29 2008
@@ -0,0 +1,88 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008  Matthias Clasen  <mclasen redhat com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef GCONF_DEFAULTS_H
+#define GCONF_DEFAULTS_H
+
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+
+G_BEGIN_DECLS
+
+#define GCONF_TYPE_DEFAULTS         (gconf_defaults_get_type ())
+#define GCONF_DEFAULTS(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GCONF_TYPE_DEFAULTS, GConfDefaults))
+#define GCONF_DEFAULTS_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GCONF_TYPE_DEFAULTS, GConfDefaultsClass))
+#define GCONF_IS_DEFAULTS(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GCONF_TYPE_DEFAULTS))
+#define GCONF_IS_DEFAULTS_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GCONF_TYPE_DEFAULTS))
+#define GCONF_DEFAULTS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GCONF_TYPE_DEFAULTS, GConfDefaultsClass))
+
+typedef struct GConfDefaultsPrivate GConfDefaultsPrivate;
+
+typedef struct
+{
+        GObject        parent;
+        GConfDefaultsPrivate *priv;
+} GConfDefaults;
+
+typedef struct
+{
+        GObjectClass   parent_class;
+
+	void (* system_set) (GConfDefaults  *defaults,
+                             const char    **keys);
+
+} GConfDefaultsClass;
+
+typedef enum
+{
+        GCONF_DEFAULTS_ERROR_GENERAL,
+        GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
+        GCONF_DEFAULTS_NUM_ERRORS
+} GConfDefaultsError;
+
+#define GCONF_DEFAULTS_ERROR gconf_defaults_error_quark ()
+
+GType gconf_defaults_error_get_type (void);
+#define GCONF_DEFAULTS_TYPE_ERROR (gconf_defaults_error_get_type ())
+
+
+GQuark         gconf_defaults_error_quark    (void);
+GType          gconf_defaults_get_type       (void);
+GConfDefaults *gconf_defaults_new            (void);
+
+/* exported methods */
+void           gconf_defaults_set_system        (GConfDefaults          *mechanism,
+                                                 const char            **includes,
+                                                 const char            **excludes,
+                                                 DBusGMethodInvocation  *context);
+
+void           gconf_defaults_set_mandatory     (GConfDefaults          *mechanism,
+                                                 const char            **includes,
+                                                 const char            **excludes,
+                                                 DBusGMethodInvocation  *context);
+
+void           gconf_defaults_unset_mandatory   (GConfDefaults          *mechanism,
+                                                 const char            **includes,
+                                                 const char            **excludes,
+                                                 DBusGMethodInvocation  *context);
+
+G_END_DECLS
+
+#endif /* GCONF_DEFAULTS_H */

Added: trunk/defaults/gconf-defaults.xml
==============================================================================
--- (empty file)
+++ trunk/defaults/gconf-defaults.xml	Fri Jul 11 16:34:29 2008
@@ -0,0 +1,64 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd";>
+<node name="/">
+  <interface name="org.gnome.GConf.Defaults">
+    <!--
+      includes: an array of GConf paths to copy from the 
+                callers GConf database to the system database
+      excludes: an array of GConf paths to omit
+
+      Copies values from the callers GConf database to the system-wide 
+      database. The subtree below each included path is copied recursively, 
+      skipping the excluded subtrees.
+      To decide which PolicyKit privilege to require for the copying of
+      each path in includes, the mechanism looks for a privilege with an
+      annotation with key org.gnome.gconf.defaults.set-system.prefix whose
+      value is a prefix of the path. If no privilege is found this way, the
+      org.gnome.gconf.defaults.set-system privilege is required.
+    -->
+    <method name="SetSystem">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <arg name="includes" direction="in" type="as"/>
+      <arg name="excludes" direction="in" type="as"/>
+    </method>
+
+    <signal name="SystemSet">
+      <arg name="keys" type="as"/>
+    </signal>
+    <!--
+      includes: an array of GConf paths to copy from the 
+                callers GConf database to the mandatory database
+      excludes: an array of GConf paths to omit
+
+      Copies values from the callers GConf database to the system-wide 
+      mandatory database. The subtree below each included path is copied 
+      recursively, skipping the excluded subtrees.
+      To decide which PolicyKit privilege to require for the copying of
+      each path in includes, the mechanism looks for a privilege with an
+      annotation with key org.gnome.gconf.defaults.set-mandatory.prefix whose
+      value is a prefix of the path. If no privilege is found this way, the
+      org.gnome.gconf.defaults.set-mandatory privilege is required.
+    -->
+    <method name="SetMandatory">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <arg name="includes" direction="in" type="as"/>
+      <arg name="excludes" direction="in" type="as"/>
+    </method>
+
+    <!--
+      Unsets keys in the system-wide mandatory GConf database, making the
+      keys writable again. The subtree below each included path is copied 
+      recursively, skipping the excluded subtrees.
+      To decide which PolicyKit privilege to require for the copying of
+      each path in includes, the mechanism looks for a privilege with an
+      annotation with key org.gnome.gconf.defaults.set-mandatory.prefix whose
+      value is a prefix of the path. If no privilege is found this way, the
+      org.gnome.gconf.defaults.set-mandatory privilege is required.
+    -->
+    <method name="UnsetMandatory">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <arg name="includes" direction="in" type="as"/>
+      <arg name="excludes" direction="in" type="as"/>
+    </method>
+   
+  </interface>
+</node>

Added: trunk/defaults/org.gnome.GConf.Defaults.conf
==============================================================================
--- (empty file)
+++ trunk/defaults/org.gnome.GConf.Defaults.conf	Fri Jul 11 16:34:29 2008
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->
+
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd";>
+<busconfig>
+
+  <!-- Only root can own the service -->
+  <policy user="root">
+    <allow own="org.gnome.GConf.Defaults"/>
+    <allow send_interface="org.gnome.GConf.Defaults.SetSystem"/>
+    <allow send_interface="org.gnome.GConf.Defaults.SetMandatory"/>
+    <allow send_interface="org.gnome.GConf.Defaults.UnsetMandatory"/>
+  </policy>
+
+  <!-- Allow anyone to invoke methods on the interfaces -->
+  <policy context="default">
+    <allow send_interface="org.gnome.GConf.Defaults.SetSystem"/>
+    <allow send_interface="org.gnome.GConf.Defaults.SetMandatory"/>
+    <allow send_interface="org.gnome.GConf.Defaults.UnsetMandatory"/>
+  </policy>
+
+</busconfig>

Added: trunk/defaults/org.gnome.GConf.Defaults.service.in
==============================================================================
--- (empty file)
+++ trunk/defaults/org.gnome.GConf.Defaults.service.in	Fri Jul 11 16:34:29 2008
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name=org.gnome.GConf.Defaults
+Exec= LIBEXECDIR@/gconf-defaults-mechanism
+User=root

Added: trunk/defaults/org.gnome.gconf.defaults.policy.in
==============================================================================
--- (empty file)
+++ trunk/defaults/org.gnome.gconf.defaults.policy.in	Fri Jul 11 16:34:29 2008
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE policyconfig PUBLIC
+ "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd";>
+<policyconfig>
+  <vendor>The GNOME Project</vendor>
+  <vendor_url>http://www.gnome.org/projects/gconf/</vendor_url>
+  <icon_name>gconf-editor</icon_name>
+
+  <action id="org.gnome.gconf.defaults.set-system">
+    <_description>Change GConf system values</_description>
+    <_message>Privileges are required to change GConf system values</_message>
+    <defaults>
+      <allow_inactive>no</allow_inactive>
+      <allow_active>auth_admin</allow_active>
+    </defaults>
+  </action>
+
+  <action id="org.gnome.gconf.defaults.set-mandatory">
+    <_description>Change GConf mandatory values</_description>
+    <_message>Privileges are required to change GConf mandatory values</_message>
+    <defaults>
+      <allow_inactive>no</allow_inactive>
+      <allow_active>auth_admin</allow_active>
+    </defaults>
+  </action>
+
+</policyconfig>

Modified: trunk/gconf/gconf-database.c
==============================================================================
--- trunk/gconf/gconf-database.c	(original)
+++ trunk/gconf/gconf-database.c	Fri Jul 11 16:34:29 2008
@@ -1722,6 +1722,18 @@
   gconf_sources_clear_cache(db->sources);
 }
 
+void
+gconf_database_clear_cache_for_sources (GConfDatabase  *db,
+					GConfSources   *sources,
+					GError        **err)
+{
+  g_assert(db->listeners != NULL);
+
+  db->last_access = time(NULL);
+
+  gconf_sources_clear_cache_for_sources(db->sources, sources);
+}
+
 const gchar *
 gconf_database_get_persistent_name (GConfDatabase *db)
 {

Modified: trunk/gconf/gconf-database.h
==============================================================================
--- trunk/gconf/gconf-database.h	(original)
+++ trunk/gconf/gconf-database.h	Fri Jul 11 16:34:29 2008
@@ -133,6 +133,9 @@
                                           GError    **err);
 void     gconf_database_clear_cache      (GConfDatabase  *db,
                                           GError    **err);
+void     gconf_database_clear_cache_for_sources (GConfDatabase  *db,
+						 GConfSources   *sources,
+						 GError        **err);
 
 
 void gconfd_locale_cache_expire (void);

Modified: trunk/gconf/gconf-sources.c
==============================================================================
--- trunk/gconf/gconf-sources.c	(original)
+++ trunk/gconf/gconf-sources.c	Fri Jul 11 16:34:29 2008
@@ -34,6 +34,8 @@
 #include <errno.h>
 #include <ctype.h>
 
+static const char * get_address_resource (const char *address);
+
 /* 
  *  Sources
  */
@@ -487,6 +489,44 @@
     }
 }
 
+void
+gconf_sources_clear_cache_for_sources (GConfSources  *sources,
+				       GConfSources  *affected)
+{
+  GList* tmp;
+
+  tmp = sources->sources;
+
+  while (tmp != NULL)
+    {
+      GConfSource* source = tmp->data;
+      const char *source_resource = get_address_resource (source->address);
+
+      GList* tmp2;
+
+      if (source->backend->vtable.clear_cache == NULL)
+        continue;
+
+      tmp2 = affected->sources;
+
+      while (tmp2 != NULL)
+	{
+	  GConfSource* affected_source = tmp2->data;
+
+	  if (source->backend == affected_source->backend &&
+	      strcmp (source_resource, get_address_resource (affected_source->address)) == 0)
+	    {
+	      if (source->backend->vtable.clear_cache)
+		(*source->backend->vtable.clear_cache)(source);
+	    }
+
+	  tmp2 = g_list_next(tmp2);
+	}
+      
+      tmp = g_list_next(tmp);
+    }
+}
+
 GConfValue*   
 gconf_sources_query_value (GConfSources* sources, 
                            const gchar* key,

Modified: trunk/gconf/gconf-sources.h
==============================================================================
--- trunk/gconf/gconf-sources.h	(original)
+++ trunk/gconf/gconf-sources.h	Fri Jul 11 16:34:29 2008
@@ -82,6 +82,8 @@
 GConfSources* gconf_sources_new_from_source    (GConfSource   *source);
 void          gconf_sources_free               (GConfSources  *sources);
 void          gconf_sources_clear_cache        (GConfSources  *sources);
+void          gconf_sources_clear_cache_for_sources (GConfSources  *sources,
+						     GConfSources  *affected);
 GConfValue*   gconf_sources_query_value        (GConfSources  *sources,
                                                 const gchar   *key,
                                                 const gchar  **locales,

Modified: trunk/gconf/gconfd.c
==============================================================================
--- trunk/gconf/gconfd.c	(original)
+++ trunk/gconf/gconfd.c	Fri Jul 11 16:34:29 2008
@@ -521,7 +521,7 @@
 static DBusHandlerResult
 bus_message_handler (DBusConnection *connection,
                      DBusMessage    *message,
-                     GMainLoop      *loop)
+                     void           *user_data)
 {
   DBusMessage *reply;
 
@@ -617,6 +617,102 @@
   return connection;
 }
 
+#ifdef ENABLE_DEFAULTS_SERVICE
+/* listen on system bus for defaults changes */
+
+static DBusHandlerResult
+system_bus_message_handler (DBusConnection *connection,
+			    DBusMessage    *message,
+			    void           *user_data)
+{
+  DBusMessage *reply;
+
+  reply = NULL;
+
+  if (dbus_message_is_signal (message,
+			      "org.gnome.GConf.Defaults",
+                              "SystemSet"))
+    {
+      DBusError bus_error;
+      char **keys;
+      int n_keys;
+
+      dbus_error_init (&bus_error);
+      if (dbus_message_get_args (message, &bus_error,
+				 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &keys, &n_keys,
+				 DBUS_TYPE_INVALID))
+	{
+	  char **key;
+	  GConfSources *system_sources;
+	  GSList addresses;
+
+	  gconf_log (GCL_DEBUG, "System defaults changed.  Notifying.");
+
+	  addresses.data = "xml:merged:/etc/gconf/gconf.xml.system";
+	  addresses.next = NULL;
+	  system_sources = gconf_sources_new_from_addresses (&addresses, NULL);
+
+	  gconfd_clear_cache_for_sources (system_sources);
+
+	  for (key = keys; *key; key++)
+	    gconfd_notify_other_listeners (NULL, system_sources, *key);
+
+	  gconf_sources_free (system_sources);
+
+	  dbus_free_string_array (keys);
+	}
+      else
+        {
+	  gconf_log (GCL_DEBUG, "SystemSet signal received, but error getting message: %s", bus_error.message);
+	}
+      dbus_error_free (&bus_error);
+
+      return DBUS_HANDLER_RESULT_HANDLED;
+    }
+
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusConnection *
+get_on_system_bus (void)
+{
+  DBusConnection *connection;
+  DBusError bus_error;
+  int result;
+
+  dbus_error_init (&bus_error);
+  connection = dbus_bus_get (DBUS_BUS_SYSTEM, &bus_error);
+
+  if (dbus_error_is_set (&bus_error))
+    {
+      gconf_log (GCL_ERR, _("Could not connect to system bus: %s"), bus_error.message);
+      dbus_error_free (&bus_error);
+      return NULL;
+    }
+
+  dbus_connection_setup_with_g_main (connection, NULL);
+
+  dbus_bus_add_match (connection, "type='signal',interface='org.gnome.GConf.Defaults'", &bus_error);
+  dbus_connection_flush(connection);
+  if (dbus_error_is_set (&bus_error))
+    {
+      gconf_log (GCL_DEBUG, "Failed to add signal match to system bus: %s", bus_error.message);
+      dbus_connection_unref (connection);
+      return NULL;
+    }
+
+  if (!dbus_connection_add_filter (connection, (DBusHandleMessageFunction)
+                                   system_bus_message_handler, NULL, NULL))
+    {
+      gconf_log (GCL_DEBUG, "Failed to add message filter to system bus.");
+      dbus_connection_unref (connection);
+      return NULL;
+    }
+
+  return connection;
+}
+#endif  /* ENABLE_DEFAULTS_SERVICE */
+
 int 
 main(int argc, char** argv)
 {
@@ -778,7 +874,11 @@
 
   /* Read saved log file, if any */
   logfile_read ();
-  
+ 
+#ifdef ENABLE_DEFAULTS_SERVICE 
+  get_on_system_bus ();
+#endif
+
   gconf_main ();
 
   if (in_shutdown)
@@ -1207,6 +1307,22 @@
     }
 }
 
+void
+gconfd_clear_cache_for_sources (GConfSources *sources)
+{
+  GList *tmp;
+
+  tmp = db_list;
+  while (tmp != NULL)
+    {
+      GConfDatabase *db = tmp->data;
+
+      gconf_database_clear_cache_for_sources (db, sources, NULL);
+
+      tmp = tmp->next;
+    }
+}
+
 /*
  * Cleanup
  */

Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in	(original)
+++ trunk/po/POTFILES.in	Fri Jul 11 16:34:29 2008
@@ -9,6 +9,7 @@
 backends/xml-cache.c
 backends/xml-dir.c
 backends/xml-entry.c
+defaults/org.gnome.gconf.defaults.policy.in
 gconf/gconf-backend.c
 gconf/gconf-client.c
 gconf/gconf-database.c
@@ -21,3 +22,4 @@
 gconf/gconf.c
 gconf/gconfd.c
 gconf/gconftool.c
+defaults/org.gnome.gconf.defaults.policy.in



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]