Index: gconf-editor-window.c
===================================================================
--- gconf-editor-window.c	(révision 1435)
+++ gconf-editor-window.c	(copie de travail)
@@ -27,6 +27,7 @@
 #include "gconf-cell-renderer.h"
 #include "gconf-editor-application.h"
 #include "gconf-key-editor.h"
+#include "gconf-policykit.h"
 #include "gconf-stock-icons.h"
 #include "gconf-util.h"
 #include "gedit-output-window.h"
@@ -34,6 +35,7 @@
 
 #include <gconf/gconf.h>
 #include <glib/gi18n.h>
+#include <gdk/gdkx.h>
 #include <string.h>
 #include <stdlib.h>
 
@@ -639,23 +641,25 @@ gconf_editor_window_row_expanded (GtkTre
 }
 
 static void
+gconf_editor_popup_policykit_callback (GtkWindow *window, GError *error)
+{
+  if (error)
+    gconf_editor_window_popup_error_dialog (window, _("Could not set value. Error was:\n%s"), error);
+}
+
+static void
 gconf_editor_popup_window_set_as_default (GtkAction *action, GtkWidget *callback_data)
 {
   GConfEditorWindow *gconfwindow = GCONF_EDITOR_WINDOW (callback_data);
   GtkWindow *window = GTK_WINDOW (callback_data);
 
-  GConfClient *client;
-  GError *error = NULL;
   GtkTreeIter iter;
   GConfValue *value;
   char *path = NULL;
+  gboolean can_use_pk;
+  
+  can_use_pk = (gconfwindow->type == GCONF_EDITOR_WINDOW_TYPE_NORMAL);
   
-  client = gconf_editor_window_get_client (GCONF_EDITOR_WINDOW_TYPE_DEFAULTS);
-  if (client == NULL) {
-    g_print ("Could not create GConf client\n");
-    return;
-  }
-	
   gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (gconfwindow->list_view)),
                                    NULL, &iter);
   gtk_tree_model_get (gconfwindow->sorted_list_model, &iter,
@@ -663,13 +667,33 @@ gconf_editor_popup_window_set_as_default
                       GCONF_LIST_MODEL_VALUE_COLUMN, &value,
                       -1);
 
-  gconf_client_set (client, path, value, NULL);
+  if (gconf_util_can_edit_defaults ()) {
+    GConfClient *client;
 
-  gconf_client_suggest_sync (client, &error);
-  if (error) {
-    gconf_editor_window_popup_error_dialog (window, _("Could not sync value. Error was:\n%s"), error);
+    client = gconf_editor_window_get_client (GCONF_EDITOR_WINDOW_TYPE_DEFAULTS);
+    if (client != NULL) {
+      GError *error = NULL;
+
+      gconf_client_set (client, path, value, NULL);
+      gconf_client_suggest_sync (client, &error);
+      g_object_unref (client);
+
+      if (!error)
+        return;
+
+      if (!can_use_pk)
+        gconf_editor_window_popup_error_dialog (window, _("Could not sync value. Error was:\n%s"), error);
+      g_error_free (error);
+    }
+  }
+
+  if (can_use_pk) {
+    gconf_client_suggest_sync (gconfwindow->client, NULL);
+    gconf_pk_set_default_async (path,
+                                GDK_WINDOW_XWINDOW (GTK_WIDGET (window)->window),
+                                (GFunc) gconf_editor_popup_policykit_callback,
+                                g_object_ref (window), g_object_unref);
   }
-  g_object_unref (client);
 }
 
 static void
@@ -678,19 +702,13 @@ gconf_editor_popup_window_set_as_mandato
   GConfEditorWindow *gconfwindow = GCONF_EDITOR_WINDOW (callback_data);
   GtkWindow *window = GTK_WINDOW (callback_data);
 
-  GError *error = NULL;
   GtkTreeIter iter;
   GConfValue *value;
   char *path = NULL;
-  GConfClient *client;
+  gboolean can_use_pk;
   
+  can_use_pk = (gconfwindow->type == GCONF_EDITOR_WINDOW_TYPE_NORMAL);
 
-  client = gconf_editor_window_get_client (GCONF_EDITOR_WINDOW_TYPE_MANDATORY);
-  if (client == NULL) {
-    g_print ("Could not create GConf client\n");
-    return;
-  }
-	
   gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (gconfwindow->list_view)),
                                    NULL, &iter);
   gtk_tree_model_get (gconfwindow->sorted_list_model, &iter,
@@ -698,13 +716,33 @@ gconf_editor_popup_window_set_as_mandato
                       GCONF_LIST_MODEL_VALUE_COLUMN, &value,
                       -1);
 
-  gconf_client_set (client, path, value, NULL);
+  if (gconf_util_can_edit_mandatory ()) {
+    GConfClient *client;
 
-  gconf_client_suggest_sync (client, &error);
-  if (error) {
-    gconf_editor_window_popup_error_dialog (window, _("Could not sync value. Error was:\n%s"), error);
+    client = gconf_editor_window_get_client (GCONF_EDITOR_WINDOW_TYPE_MANDATORY);
+    if (client != NULL) {
+      GError *error = NULL;
+
+      gconf_client_set (client, path, value, NULL);
+      gconf_client_suggest_sync (client, &error);
+      g_object_unref (client);
+
+      if (!error)
+        return;
+      
+      if (!can_use_pk)
+        gconf_editor_window_popup_error_dialog (window, _("Could not sync value. Error was:\n%s"), error);
+      g_error_free (error);
+    }
+  }
+
+  if (can_use_pk) {
+    gconf_client_suggest_sync (gconfwindow->client, NULL);
+    gconf_pk_set_mandatory_async (path,
+                                  GDK_WINDOW_XWINDOW (GTK_WIDGET (window)->window),
+                                  (GFunc) gconf_editor_popup_policykit_callback,
+                                  g_object_ref (window), g_object_unref);
   }
-  g_object_unref (client);
 }
 
 static GtkActionEntry entries[] = {
@@ -897,11 +935,11 @@ list_view_button_press_event (GtkTreeVie
 			gtk_widget_set_sensitive (gtk_ui_manager_get_widget (window->ui_manager, "/GConfKeyPopupMenu/UnsetKey"), 
 						  window->type != GCONF_EDITOR_WINDOW_TYPE_DEFAULTS);
 			gtk_widget_set_sensitive (gtk_ui_manager_get_widget (window->ui_manager, "/GConfKeyPopupMenu/DefaultKey"), 
-						  gconf_util_can_edit_defaults () &&
-						  window->type != GCONF_EDITOR_WINDOW_TYPE_DEFAULTS);
+						  (gconf_util_can_edit_defaults () && window->type != GCONF_EDITOR_WINDOW_TYPE_DEFAULTS) ||
+						  (gconf_pk_can_set_default () && window->type == GCONF_EDITOR_WINDOW_TYPE_NORMAL));
 			gtk_widget_set_sensitive (gtk_ui_manager_get_widget (window->ui_manager, "/GConfKeyPopupMenu/MandatoryKey"), 
-						  gconf_util_can_edit_mandatory () &&
-						  window->type != GCONF_EDITOR_WINDOW_TYPE_MANDATORY);
+						  (gconf_util_can_edit_mandatory () && window->type != GCONF_EDITOR_WINDOW_TYPE_MANDATORY) ||
+						  (gconf_pk_can_set_mandatory () && window->type == GCONF_EDITOR_WINDOW_TYPE_NORMAL));
 			
 			gtk_tree_path_free (path);
 		}
@@ -1000,11 +1038,11 @@ gconf_editor_window_list_view_popup_menu
 		gtk_widget_set_sensitive (gtk_ui_manager_get_widget (window->ui_manager, "/GConfKeyPopupMenu/UnsetKey"), 
 					  window->type != GCONF_EDITOR_WINDOW_TYPE_DEFAULTS);
 		gtk_widget_set_sensitive (gtk_ui_manager_get_widget (window->ui_manager, "/GConfKeyPopupMenu/DefaultKey"), 
-					  gconf_util_can_edit_defaults () &&
-					  window->type != GCONF_EDITOR_WINDOW_TYPE_DEFAULTS);
+					  (gconf_util_can_edit_defaults () && window->type != GCONF_EDITOR_WINDOW_TYPE_DEFAULTS) ||
+					  (gconf_pk_can_set_default () && window->type == GCONF_EDITOR_WINDOW_TYPE_NORMAL));
 		gtk_widget_set_sensitive (gtk_ui_manager_get_widget (window->ui_manager, "/GConfKeyPopupMenu/MandatoryKey"), 
-					  gconf_util_can_edit_mandatory () &&
-					  window->type != GCONF_EDITOR_WINDOW_TYPE_MANDATORY);
+					  (gconf_util_can_edit_mandatory () && window->type != GCONF_EDITOR_WINDOW_TYPE_MANDATORY) ||
+					  (gconf_pk_can_set_mandatory () && window->type == GCONF_EDITOR_WINDOW_TYPE_NORMAL));
 			
 	}
 	else {
Index: gconf-policykit.c
===================================================================
--- gconf-policykit.c	(révision 0)
+++ gconf-policykit.c	(révision 0)
@@ -0,0 +1,436 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Vincent Untz <vuntz@gnome.org>
+ *
+ * Based on set-timezone.c from gnome-panel which was GPLv2+ with this
+ * copyright:
+ *    Copyright (C) 2007 David Zeuthen <david@fubar.dk>
+ *
+ * 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <polkit/polkit.h>
+#include <polkit-dbus/polkit-dbus.h>
+
+#include "gconf-policykit.h"
+
+#define CACHE_VALIDITY_SEC 10
+
+static DBusGConnection *
+get_session_bus (void)
+{
+        GError          *error;
+        static DBusGConnection *bus = NULL;
+
+        if (bus == NULL) {
+                error = NULL;
+                bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+                if (bus == NULL) {
+                               g_warning ("Couldn't connect to session bus: %s",
+                                   error->message);
+                        g_error_free (error);
+                }
+        }
+
+        return bus;
+}
+
+static DBusGConnection *
+get_system_bus (void)
+{
+        GError          *error;
+        static DBusGConnection *bus = NULL;
+
+        if (bus == NULL) {
+                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);
+                }
+        }
+
+        return bus;
+}
+
+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_fn (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_fn (PolKitContext *pk_context, int watch_id)
+{
+        g_source_remove (watch_id);
+}
+
+static PolKitContext *
+get_pk_context (void)
+{
+        static PolKitContext *pk_context = NULL;
+
+        if (pk_context == NULL) {
+                pk_context = polkit_context_new ();
+                polkit_context_set_io_watch_functions (pk_context,
+                                                       pk_io_add_watch_fn,
+                                                       pk_io_remove_watch_fn);
+                if (!polkit_context_init (pk_context, NULL)) {
+                        polkit_context_unref (pk_context);
+                        pk_context = NULL;
+                }
+        }
+
+        return pk_context;
+}
+
+static gint
+can_do (const gchar *pk_action_id)
+{
+        DBusConnection *system_bus;
+        PolKitCaller *pk_caller;
+        PolKitAction *pk_action;
+        PolKitResult pk_result;
+        PolKitContext *pk_context;
+        DBusError dbus_error;
+        gint res = 0;
+
+        pk_caller = NULL;
+        pk_action = NULL;
+
+        system_bus = dbus_g_connection_get_connection (get_system_bus ());
+        if (system_bus == NULL)
+                goto out;
+
+        pk_context = get_pk_context ();
+        if (pk_context == NULL)
+                goto out;
+
+        pk_action = polkit_action_new ();
+        polkit_action_set_action_id (pk_action, pk_action_id);
+
+        dbus_error_init (&dbus_error);
+        pk_caller = polkit_caller_new_from_pid (system_bus, getpid (), &dbus_error);
+        if (pk_caller == NULL) {
+                fprintf (stderr, "cannot get caller from dbus name\n");
+                goto out;
+        }
+
+        pk_result = polkit_context_is_caller_authorized (pk_context, pk_action, pk_caller, FALSE, NULL);
+
+        switch (pk_result) {
+        case POLKIT_RESULT_UNKNOWN:
+        case POLKIT_RESULT_NO:
+                 res = 0;
+                break;
+        case POLKIT_RESULT_YES:
+                res = 2;
+                break;
+        default:
+                /* This covers all the
+                 * POLKIT_RESULT_ONLY_VIA_[SELF|ADMIN]_AUTH_* cases as more of
+                 * these may be added in the future.
+                 */
+                res = 1;
+                break;
+        }
+
+out:
+        if (pk_action != NULL)
+                polkit_action_unref (pk_action);
+        if (pk_caller != NULL)
+                polkit_caller_unref (pk_caller);
+
+        return res;
+}
+
+gint
+gconf_pk_can_set_default (void)
+{
+        static gboolean cache = FALSE;
+        static time_t   last_refreshed = 0;
+        time_t          now;
+
+        time (&now);
+        if (ABS (now - last_refreshed) > CACHE_VALIDITY_SEC) {
+                cache = can_do ("org.gnome.gconf.defaults.set-system");
+                last_refreshed = now;
+        }
+
+        return cache;
+}
+
+gint
+gconf_pk_can_set_mandatory (void)
+{
+        static gboolean cache = FALSE;
+        static time_t   last_refreshed = 0;
+        time_t          now;
+
+        time (&now);
+        if (ABS (now - last_refreshed) > CACHE_VALIDITY_SEC) {
+                cache = can_do ("org.gnome.gconf.defaults.set-mandatory");
+                last_refreshed = now;
+        }
+
+        return cache;
+}
+
+typedef struct {
+        gint            ref_count;
+        const gchar    *call;
+        gchar          *key;
+        guint           transient_parent_xid;
+        GFunc           callback;
+        gpointer        data;
+        GDestroyNotify  notify;
+} GConfPKCallbackData;
+
+static gpointer
+_gconf_pk_data_ref (gpointer d)
+{
+        GConfPKCallbackData *data = d;
+
+        data->ref_count++;
+
+        return data;
+}
+
+static void
+_gconf_pk_data_unref (gpointer d)
+{
+        GConfPKCallbackData *data = d;
+
+        data->ref_count--;
+        if (data->ref_count == 0) {
+                if (data->notify)
+                        data->notify (data->data);
+                g_free (data->key);
+                g_slice_free (GConfPKCallbackData, data);
+        }
+}
+
+static void set_key_async (GConfPKCallbackData *data);
+
+static void
+auth_notify (DBusGProxy     *proxy,
+             DBusGProxyCall *call,
+             void           *user_data)
+{
+        GConfPKCallbackData *data = user_data;
+        GError *error = NULL;
+        gboolean gained_privilege;
+
+        if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_BOOLEAN, &gained_privilege, G_TYPE_INVALID)) {
+                if (gained_privilege)
+                        set_key_async (data);
+        }
+        else {
+                if (data->callback)
+                        data->callback (data->data, error);
+                else
+                        g_error_free (error);
+        }
+}
+
+static void
+do_auth_async (const gchar         *action,
+               const gchar         *result,
+               GConfPKCallbackData *data)
+{
+        DBusGConnection *bus;
+        DBusGProxy *proxy;
+
+        /* Now ask the user for auth... */
+        bus = get_session_bus ();
+        if (bus == NULL)
+                return;
+
+        proxy = dbus_g_proxy_new_for_name (bus,
+                                        "org.gnome.PolicyKit",
+                                        "/org/gnome/PolicyKit/Manager",
+                                        "org.gnome.PolicyKit.Manager");
+
+        dbus_g_proxy_begin_call_with_timeout (proxy,
+                                              "ShowDialog",
+                                              auth_notify,
+                                              _gconf_pk_data_ref (data),
+                                              _gconf_pk_data_unref,
+                                              INT_MAX,
+                                              G_TYPE_STRING, action,
+                                              G_TYPE_UINT, data->transient_parent_xid,
+                                              G_TYPE_INVALID);
+}
+
+static void
+set_key_notify (DBusGProxy     *proxy,
+                DBusGProxyCall *call,
+                void           *user_data)
+{
+        GConfPKCallbackData *data = user_data;
+        GError *error = NULL;
+
+        if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) {
+                if (data->callback)
+                        data->callback (data->data, NULL);
+        }
+        else {
+                if (error->domain == DBUS_GERROR &&
+                    error->code == DBUS_GERROR_NO_REPLY) {
+                        /* these errors happen because dbus doesn't
+                         * use monotonic clocks
+                         */
+                        g_warning ("ignoring no-reply error when setting key");
+                        g_error_free (error);
+                        if (data->callback)
+                                data->callback (data->data, NULL);
+                }
+                else if (dbus_g_error_has_name (error, "org.freedesktop.PolicyKit.Error.NotAuthorized")) {
+                        gchar **tokens;
+
+                        tokens = g_strsplit (error->message, " ", 2);
+                        g_error_free (error);
+                        if (g_strv_length (tokens) == 2)
+                                do_auth_async (tokens[0], tokens[1], data);
+                        else
+                                g_warning ("helper return string malformed");
+                        g_strfreev (tokens);
+                }
+                else {
+                        if (data->callback)
+                                data->callback (data->data, error);
+                        else
+                                g_error_free (error);
+                }
+        }
+}
+
+static void
+set_key_async (GConfPKCallbackData *data)
+{
+        DBusGConnection *bus;
+        DBusGProxy      *proxy;
+        gchar           *keys[2] = { data->key, NULL };
+
+        bus = get_system_bus ();
+        if (bus == NULL)
+                return;
+
+        proxy = dbus_g_proxy_new_for_name (bus,
+                                           "org.gnome.GConf.Defaults",
+                                           "/",
+                                           "org.gnome.GConf.Defaults");
+
+        dbus_g_proxy_begin_call_with_timeout (proxy,
+                                              data->call,
+                                              set_key_notify,
+                                              _gconf_pk_data_ref (data),
+                                              _gconf_pk_data_unref,
+                                              INT_MAX,
+                                              /* parameters: */
+                                              G_TYPE_STRV, keys,
+                                              G_TYPE_STRV, NULL,
+                                              G_TYPE_INVALID,
+                                              /* return values: */
+                                              G_TYPE_INVALID);
+}
+
+void
+gconf_pk_set_default_async (const gchar    *key,
+                            guint           transient_parent_xid,
+                            GFunc           callback,
+                            gpointer        d,
+                            GDestroyNotify  notify)
+{
+        GConfPKCallbackData *data;
+
+        if (key == NULL)
+                return;
+
+        data = g_slice_new0 (GConfPKCallbackData);
+        data->ref_count = 1;
+        data->call = "SetSystem";
+        data->key = g_strdup (key);
+        data->transient_parent_xid = transient_parent_xid;
+        data->callback = callback;
+        data->data = d;
+        data->notify = notify;
+
+        set_key_async (data);
+        _gconf_pk_data_unref (data);
+}
+
+void
+gconf_pk_set_mandatory_async (const gchar    *key,
+                              guint           transient_parent_xid,
+                              GFunc           callback,
+                              gpointer        d,
+                              GDestroyNotify  notify)
+{
+        GConfPKCallbackData *data;
+
+        if (key == NULL)
+                return;
+
+        data = g_slice_new0 (GConfPKCallbackData);
+        data->ref_count = 1;
+        data->call = "SetMandatory";
+        data->key = g_strdup (key);
+        data->transient_parent_xid = transient_parent_xid;
+        data->callback = callback;
+        data->data = d;
+        data->notify = notify;
+
+        set_key_async (data);
+        _gconf_pk_data_unref (data);
+}
Index: gconf-policykit.h
===================================================================
--- gconf-policykit.h	(révision 0)
+++ gconf-policykit.h	(révision 0)
@@ -0,0 +1,46 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Vincent Untz <vuntz@gnome.org>
+ *
+ * Based on set-timezone.h from gnome-panel which was GPLv2+ with this
+ * copyright:
+ *    Copyright (C) 2007 David Zeuthen <david@fubar.dk>
+ *
+ * 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_POLICYKIT_H__
+#define  __GCONF_POLICYKIT_H__
+
+#include <glib.h>
+
+gint     gconf_pk_can_set_default    (void);
+
+gint     gconf_pk_can_set_mandatory  (void);
+
+void     gconf_pk_set_default_async  (const gchar    *key,
+                                      guint           transient_parent_xid,
+                                      GFunc           callback,
+                                      gpointer        data,
+                                      GDestroyNotify  notify);
+
+void     gconf_pk_set_mandatory_async (const gchar    *key,
+                                       guint           transient_parent_xid,
+                                       GFunc           callback,
+                                       gpointer        data,
+                                       GDestroyNotify  notify);
+
+#endif /* __GCONF_POLICYKIT_H__ */
Index: Makefile.am
===================================================================
--- Makefile.am	(révision 1433)
+++ Makefile.am	(copie de travail)
@@ -33,6 +33,8 @@ gconf_editor_SOURCES = \
 	gconf-util.h			\
 	gedit-output-window.c		\
 	gedit-output-window.h		\
+	gconf-policykit.c		\
+	gconf-policykit.h		\
 	gconf-search.h                  \
 	gconf-search.c                  \
 	gconf-search-dialog.h           \
