Blame SOURCES/0012-make-save-session-stall-until-it-finishes.patch

cf6cdf
From 2c8e2b38a52a09e0710953d77fe8d9072a127e72 Mon Sep 17 00:00:00 2001
cf6cdf
From: Ray Strode <rstrode@redhat.com>
cf6cdf
Date: Fri, 20 Dec 2013 11:32:52 -0500
cf6cdf
Subject: [PATCH 12/19] make save-session stall until it finishes
cf6cdf
cf6cdf
---
cf6cdf
 gnome-session/gsm-manager.c                | 58 +++++++++++++++++++---
cf6cdf
 gnome-session/gsm-manager.h                |  2 +-
cf6cdf
 gnome-session/org.gnome.SessionManager.xml |  1 +
cf6cdf
 3 files changed, 53 insertions(+), 8 deletions(-)
cf6cdf
cf6cdf
diff --git a/gnome-session/gsm-manager.c b/gnome-session/gsm-manager.c
cf6cdf
index ede4186a..31dc67db 100644
cf6cdf
--- a/gnome-session/gsm-manager.c
cf6cdf
+++ b/gnome-session/gsm-manager.c
cf6cdf
@@ -113,60 +113,61 @@ typedef enum
cf6cdf
         GSM_MANAGER_LOGOUT_REBOOT_INTERACT,
cf6cdf
         GSM_MANAGER_LOGOUT_SHUTDOWN,
cf6cdf
         GSM_MANAGER_LOGOUT_SHUTDOWN_INTERACT,
cf6cdf
 } GsmManagerLogoutType;
cf6cdf
 
cf6cdf
 struct GsmManagerPrivate
cf6cdf
 {
cf6cdf
         gboolean                failsafe;
cf6cdf
         GsmStore               *clients;
cf6cdf
         GsmStore               *inhibitors;
cf6cdf
         GsmInhibitorFlag        inhibited_actions;
cf6cdf
         GsmStore               *apps;
cf6cdf
         GsmPresence            *presence;
cf6cdf
         GsmXsmpServer          *xsmp_server;
cf6cdf
 
cf6cdf
         char                   *session_name;
cf6cdf
         gboolean                is_fallback_session : 1;
cf6cdf
 
cf6cdf
         /* Current status */
cf6cdf
         GsmManagerPhase         phase;
cf6cdf
         guint                   phase_timeout_id;
cf6cdf
         GSList                 *required_apps;
cf6cdf
         GSList                 *pending_apps;
cf6cdf
         GsmManagerLogoutMode    logout_mode;
cf6cdf
         GSList                 *query_clients;
cf6cdf
         guint                   query_timeout_id;
cf6cdf
         /* This is used for GSM_MANAGER_PHASE_END_SESSION only at the moment,
cf6cdf
          * since it uses a sublist of all running client that replied in a
cf6cdf
          * specific way */
cf6cdf
         GSList                 *next_query_clients;
cf6cdf
+        GSList                 *pending_save_invocations;
cf6cdf
         /* This is the action that will be done just before we exit */
cf6cdf
         GsmManagerLogoutType    logout_type;
cf6cdf
 
cf6cdf
         /* List of clients which were disconnected due to disabled condition
cf6cdf
          * and shouldn't be automatically restarted */
cf6cdf
         GSList                 *condition_clients;
cf6cdf
 
cf6cdf
         GSList                 *pending_end_session_tasks;
cf6cdf
         GCancellable           *end_session_cancellable;
cf6cdf
 
cf6cdf
         GSettings              *settings;
cf6cdf
         GSettings              *session_settings;
cf6cdf
         GSettings              *screensaver_settings;
cf6cdf
         GSettings              *lockdown_settings;
cf6cdf
 
cf6cdf
         GsmSystem              *system;
cf6cdf
         GDBusConnection        *connection;
cf6cdf
         GsmExportedManager     *skeleton;
cf6cdf
         gboolean                dbus_disconnected : 1;
cf6cdf
 
cf6cdf
         GsmShell               *shell;
cf6cdf
         guint                   shell_end_session_dialog_canceled_id;
cf6cdf
         guint                   shell_end_session_dialog_open_failed_id;
cf6cdf
         guint                   shell_end_session_dialog_confirmed_logout_id;
cf6cdf
         guint                   shell_end_session_dialog_confirmed_shutdown_id;
cf6cdf
         guint                   shell_end_session_dialog_confirmed_reboot_id;
cf6cdf
 };
cf6cdf
 
cf6cdf
 enum {
cf6cdf
         PROP_0,
cf6cdf
@@ -1202,91 +1203,125 @@ query_end_session_complete (GsmManager *manager)
cf6cdf
 
cf6cdf
 static gboolean
cf6cdf
 _client_request_save (GsmClient            *client,
cf6cdf
                       ClientEndSessionData *data)
cf6cdf
 {
cf6cdf
         gboolean ret;
cf6cdf
         GError  *error;
cf6cdf
 
cf6cdf
         error = NULL;
cf6cdf
         ret = gsm_client_request_save (client, data->flags, &error);
cf6cdf
         if (ret) {
cf6cdf
                 g_debug ("GsmManager: adding client to query clients: %s", gsm_client_peek_id (client));
cf6cdf
                 data->manager->priv->query_clients = g_slist_prepend (data->manager->priv->query_clients,
cf6cdf
                                                                       client);
cf6cdf
         } else if (error) {
cf6cdf
                 g_debug ("GsmManager: unable to query client: %s", error->message);
cf6cdf
                 g_error_free (error);
cf6cdf
         }
cf6cdf
 
cf6cdf
         return FALSE;
cf6cdf
 }
cf6cdf
 
cf6cdf
 static gboolean
cf6cdf
 _client_request_save_helper (const char           *id,
cf6cdf
                              GsmClient            *client,
cf6cdf
                              ClientEndSessionData *data)
cf6cdf
 {
cf6cdf
         return _client_request_save (client, data);
cf6cdf
 }
cf6cdf
 
cf6cdf
+static void
cf6cdf
+fail_pending_save_invocations (GsmManager *manager,
cf6cdf
+                               GError     *error)
cf6cdf
+{
cf6cdf
+        GSList *l;
cf6cdf
+
cf6cdf
+        for (l = manager->priv->pending_save_invocations; l != NULL; l = l->next) {
cf6cdf
+                DBusGMethodInvocation *context = l->data;
cf6cdf
+
cf6cdf
+                dbus_g_method_return_error (context, error);
cf6cdf
+        }
cf6cdf
+
cf6cdf
+        g_slist_free (manager->priv->pending_save_invocations);
cf6cdf
+        manager->priv->pending_save_invocations = NULL;
cf6cdf
+}
cf6cdf
+
cf6cdf
+static void
cf6cdf
+finish_pending_save_invocations (GsmManager *manager)
cf6cdf
+{
cf6cdf
+        GSList *l;
cf6cdf
+
cf6cdf
+        for (l = manager->priv->pending_save_invocations; l != NULL; l = l->next) {
cf6cdf
+                DBusGMethodInvocation *context = l->data;
cf6cdf
+
cf6cdf
+                dbus_g_method_return (context);
cf6cdf
+        }
cf6cdf
+
cf6cdf
+        g_slist_free (manager->priv->pending_save_invocations);
cf6cdf
+        manager->priv->pending_save_invocations = NULL;
cf6cdf
+}
cf6cdf
+
cf6cdf
 static void
cf6cdf
 query_save_session_complete (GsmManager *manager)
cf6cdf
 {
cf6cdf
         GError *error = NULL;
cf6cdf
 
cf6cdf
         if (g_slist_length (manager->priv->next_query_clients) > 0) {
cf6cdf
                 ClientEndSessionData data;
cf6cdf
 
cf6cdf
                 data.manager = manager;
cf6cdf
                 data.flags = GSM_CLIENT_END_SESSION_FLAG_LAST;
cf6cdf
 
cf6cdf
                 g_slist_foreach (manager->priv->next_query_clients,
cf6cdf
                                  (GFunc)_client_request_save,
cf6cdf
                                  &data);
cf6cdf
 
cf6cdf
                 g_slist_free (manager->priv->next_query_clients);
cf6cdf
                 manager->priv->next_query_clients = NULL;
cf6cdf
 
cf6cdf
                 return;
cf6cdf
         }
cf6cdf
 
cf6cdf
         if (manager->priv->query_timeout_id > 0) {
cf6cdf
                 g_source_remove (manager->priv->query_timeout_id);
cf6cdf
                 manager->priv->query_timeout_id = 0;
cf6cdf
         }
cf6cdf
 
cf6cdf
         gsm_session_save (manager->priv->clients, &error);
cf6cdf
 
cf6cdf
         if (error) {
cf6cdf
                 g_warning ("Error saving session: %s", error->message);
cf6cdf
+                fail_pending_save_invocations (manager, error);
cf6cdf
                 g_error_free (error);
cf6cdf
+        } else {
cf6cdf
+                finish_pending_save_invocations (manager);
cf6cdf
         }
cf6cdf
 }
cf6cdf
 
cf6cdf
 static guint32
cf6cdf
 generate_cookie (void)
cf6cdf
 {
cf6cdf
         guint32 cookie;
cf6cdf
 
cf6cdf
         cookie = (guint32)g_random_int_range (1, G_MAXINT32);
cf6cdf
 
cf6cdf
         return cookie;
cf6cdf
 }
cf6cdf
 
cf6cdf
 static guint32
cf6cdf
 _generate_unique_cookie (GsmManager *manager)
cf6cdf
 {
cf6cdf
         guint32 cookie;
cf6cdf
 
cf6cdf
         do {
cf6cdf
                 cookie = generate_cookie ();
cf6cdf
         } while (gsm_store_find (manager->priv->inhibitors, (GsmStoreFunc)_find_by_cookie, &cookie) != NULL);
cf6cdf
 
cf6cdf
         return cookie;
cf6cdf
 }
cf6cdf
 
cf6cdf
 static gboolean
cf6cdf
 _on_query_end_session_timeout (GsmManager *manager)
cf6cdf
 {
cf6cdf
         GSList *l;
cf6cdf
 
cf6cdf
@@ -2737,92 +2772,101 @@ gsm_manager_initialization_error (GsmExportedManager    *skeleton,
cf6cdf
                                   GsmManager            *manager)
cf6cdf
 {
cf6cdf
         if (manager->priv->phase != GSM_MANAGER_PHASE_INITIALIZATION) {
cf6cdf
                 g_dbus_method_invocation_return_error (invocation,
cf6cdf
                                                        GSM_MANAGER_ERROR,
cf6cdf
                                                        GSM_MANAGER_ERROR_NOT_IN_INITIALIZATION,
cf6cdf
                                                        "InitializationError interface is only available during the Initialization phase");
cf6cdf
                 return TRUE;
cf6cdf
         }
cf6cdf
 
cf6cdf
         gsm_util_init_error (fatal, "%s", message);
cf6cdf
         gsm_exported_manager_complete_initialization_error (skeleton, invocation);
cf6cdf
 
cf6cdf
         return TRUE;
cf6cdf
 }
cf6cdf
 
cf6cdf
 static void
cf6cdf
 user_logout (GsmManager           *manager,
cf6cdf
              GsmManagerLogoutMode  mode)
cf6cdf
 {
cf6cdf
         if (manager->priv->phase >= GSM_MANAGER_PHASE_QUERY_END_SESSION) {
cf6cdf
                 manager->priv->logout_mode = mode;
cf6cdf
                 end_session_or_show_shell_dialog (manager);
cf6cdf
                 return;
cf6cdf
         }
cf6cdf
 
cf6cdf
         request_logout (manager, mode);
cf6cdf
 }
cf6cdf
 
cf6cdf
 gboolean
cf6cdf
-gsm_manager_save_session (GsmManager *manager,
cf6cdf
-                          GError     **error)
cf6cdf
+gsm_manager_save_session (GsmManager            *manager,
cf6cdf
+                          DBusGMethodInvocation *context)
cf6cdf
 {
cf6cdf
         ClientEndSessionData data;
cf6cdf
+        GError *error;
cf6cdf
 
cf6cdf
         g_debug ("GsmManager: SaveSession called");
cf6cdf
 
cf6cdf
         g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
cf6cdf
 
cf6cdf
         if (manager->priv->phase != GSM_MANAGER_PHASE_RUNNING) {
cf6cdf
-                g_set_error (error,
cf6cdf
-                             GSM_MANAGER_ERROR,
cf6cdf
-                             GSM_MANAGER_ERROR_NOT_IN_RUNNING,
cf6cdf
-                             "SaveSession interface is only available during the Running phase");
cf6cdf
+                error = g_error_new (GSM_MANAGER_ERROR,
cf6cdf
+                                     GSM_MANAGER_ERROR_NOT_IN_RUNNING,
cf6cdf
+                                     "SaveSession interface is only available during the Running phase");
cf6cdf
+                dbus_g_method_return_error (context, error);
cf6cdf
+                g_error_free (error);
cf6cdf
                 return FALSE;
cf6cdf
         }
cf6cdf
 
cf6cdf
         data.manager = manager;
cf6cdf
         data.flags = 0;
cf6cdf
         gsm_store_foreach (manager->priv->clients,
cf6cdf
                            (GsmStoreFunc)_client_request_save_helper,
cf6cdf
                            &data);
cf6cdf
 
cf6cdf
         if (manager->priv->query_clients) {
cf6cdf
                 manager->priv->query_timeout_id = g_timeout_add_seconds (GSM_MANAGER_SAVE_SESSION_TIMEOUT,
cf6cdf
                                                                          (GSourceFunc)_on_query_save_session_timeout,
cf6cdf
                                                                          manager);
cf6cdf
+
cf6cdf
+                manager->priv->pending_save_invocations = g_slist_prepend (manager->priv->pending_save_invocations,
cf6cdf
+                                                                           context);
cf6cdf
+
cf6cdf
                 return TRUE;
cf6cdf
         } else {
cf6cdf
                 g_debug ("GsmManager: Nothing to save");
cf6cdf
-                return FALSE;
cf6cdf
+                dbus_g_method_return (context);
cf6cdf
+                return TRUE;
cf6cdf
         }
cf6cdf
+
cf6cdf
+        return TRUE;
cf6cdf
 }
cf6cdf
 
cf6cdf
 gboolean
cf6cdf
 gsm_manager_logout (GsmManager *manager,
cf6cdf
                     guint logout_mode,
cf6cdf
                     GError **error)
cf6cdf
 {
cf6cdf
         if (manager->priv->phase < GSM_MANAGER_PHASE_RUNNING) {
cf6cdf
                 g_set_error (error,
cf6cdf
                              GSM_MANAGER_ERROR,
cf6cdf
                              GSM_MANAGER_ERROR_NOT_IN_RUNNING,
cf6cdf
                              "Logout interface is only available after the Running phase starts");
cf6cdf
                 return FALSE;
cf6cdf
         }
cf6cdf
 
cf6cdf
         if (_log_out_is_locked_down (manager)) {
cf6cdf
                 g_set_error (error,
cf6cdf
                              GSM_MANAGER_ERROR,
cf6cdf
                              GSM_MANAGER_ERROR_LOCKED_DOWN,
cf6cdf
                              "Logout has been locked down");
cf6cdf
                 return FALSE;
cf6cdf
         }
cf6cdf
 
cf6cdf
         switch (logout_mode) {
cf6cdf
         case GSM_MANAGER_LOGOUT_MODE_NORMAL:
cf6cdf
         case GSM_MANAGER_LOGOUT_MODE_NO_CONFIRMATION:
cf6cdf
         case GSM_MANAGER_LOGOUT_MODE_FORCE:
cf6cdf
                 user_logout (manager, logout_mode);
cf6cdf
                 break;
cf6cdf
 
cf6cdf
diff --git a/gnome-session/gsm-manager.h b/gnome-session/gsm-manager.h
cf6cdf
index 4d14aa34..a8de58de 100644
cf6cdf
--- a/gnome-session/gsm-manager.h
cf6cdf
+++ b/gnome-session/gsm-manager.h
cf6cdf
@@ -97,42 +97,42 @@ GType               gsm_manager_get_type                       (void);
cf6cdf
 
cf6cdf
 GsmManager *        gsm_manager_new                            (GsmStore       *client_store,
cf6cdf
                                                                 gboolean        failsafe);
cf6cdf
 GsmManager *        gsm_manager_get                            (void);
cf6cdf
 
cf6cdf
 gboolean            gsm_manager_get_failsafe                   (GsmManager     *manager);
cf6cdf
 
cf6cdf
 gboolean            gsm_manager_add_autostart_app              (GsmManager     *manager,
cf6cdf
                                                                 const char     *path,
cf6cdf
                                                                 const char     *provides);
cf6cdf
 gboolean            gsm_manager_add_required_app               (GsmManager     *manager,
cf6cdf
                                                                 const char     *path,
cf6cdf
                                                                 const char     *provides);
cf6cdf
 gboolean            gsm_manager_add_autostart_apps_from_dir    (GsmManager     *manager,
cf6cdf
                                                                 const char     *path);
cf6cdf
 gboolean            gsm_manager_add_legacy_session_apps        (GsmManager     *manager,
cf6cdf
                                                                 const char     *path);
cf6cdf
 
cf6cdf
 void                gsm_manager_start                          (GsmManager     *manager);
cf6cdf
 
cf6cdf
 const char *        _gsm_manager_get_default_session           (GsmManager     *manager);
cf6cdf
 
cf6cdf
 void                _gsm_manager_set_active_session            (GsmManager     *manager,
cf6cdf
                                                                 const char     *session_name,
cf6cdf
                                                                 gboolean        is_fallback);
cf6cdf
 
cf6cdf
 void                _gsm_manager_set_renderer                  (GsmManager     *manager,
cf6cdf
                                                                 const char     *renderer);
cf6cdf
 
cf6cdf
 gboolean            gsm_manager_save_session                   (GsmManager     *manager,
cf6cdf
-                                                                GError        **error);
cf6cdf
+								DBusGMethodInvocation *context);
cf6cdf
 
cf6cdf
 gboolean            gsm_manager_logout                         (GsmManager     *manager,
cf6cdf
                                                                 guint           logout_mode,
cf6cdf
                                                                 GError        **error);
cf6cdf
 
cf6cdf
 gboolean            gsm_manager_set_phase                      (GsmManager     *manager,
cf6cdf
                                                                 GsmManagerPhase phase);
cf6cdf
 
cf6cdf
 G_END_DECLS
cf6cdf
 
cf6cdf
 #endif /* __GSM_MANAGER_H */
cf6cdf
diff --git a/gnome-session/org.gnome.SessionManager.xml b/gnome-session/org.gnome.SessionManager.xml
cf6cdf
index 29eb0990..ac73adc9 100644
cf6cdf
--- a/gnome-session/org.gnome.SessionManager.xml
cf6cdf
+++ b/gnome-session/org.gnome.SessionManager.xml
cf6cdf
@@ -256,60 +256,61 @@
cf6cdf
       <arg name="handled" direction="out" type="b">
cf6cdf
         <doc:doc>
cf6cdf
           <doc:summary>True if condition is handled, false otherwise</doc:summary>
cf6cdf
         </doc:doc>
cf6cdf
       </arg>
cf6cdf
       <doc:doc>
cf6cdf
         <doc:description>
cf6cdf
           <doc:para>Allows the caller to determine whether the session manager is
cf6cdf
           handling changes to the specified autostart condition.</doc:para>
cf6cdf
         </doc:description>
cf6cdf
       </doc:doc>
cf6cdf
     </method>
cf6cdf
 
cf6cdf
     <method name="Shutdown">
cf6cdf
       <doc:doc>
cf6cdf
         <doc:description>
cf6cdf
           <doc:para>Request a shutdown dialog.</doc:para>
cf6cdf
         </doc:description>
cf6cdf
       </doc:doc>
cf6cdf
     </method>
cf6cdf
 
cf6cdf
     <method name="Reboot">
cf6cdf
       <doc:doc>
cf6cdf
         <doc:description>
cf6cdf
           <doc:para>Request a reboot dialog.</doc:para>
cf6cdf
         </doc:description>
cf6cdf
       </doc:doc>
cf6cdf
     </method>
cf6cdf
 
cf6cdf
     <method name="SaveSession">
cf6cdf
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
cf6cdf
       <doc:doc>
cf6cdf
 	<doc:description>
cf6cdf
 	  <doc:para>Request to save session</doc:para>
cf6cdf
 	</doc:description>
cf6cdf
       </doc:doc>
cf6cdf
     </method>
cf6cdf
 
cf6cdf
     <method name="CanShutdown">
cf6cdf
       <arg name="is_available" direction="out" type="b">
cf6cdf
         <doc:doc>
cf6cdf
           <doc:summary>True if shutdown is available to the user, false otherwise</doc:summary>
cf6cdf
         </doc:doc>
cf6cdf
       </arg>
cf6cdf
       <doc:doc>
cf6cdf
         <doc:description>
cf6cdf
           <doc:para>Allows the caller to determine whether or not it's okay to show
cf6cdf
           a shutdown option in the UI</doc:para>
cf6cdf
         </doc:description>
cf6cdf
       </doc:doc>
cf6cdf
     </method>
cf6cdf
 
cf6cdf
     <method name="Logout">
cf6cdf
       <arg name="mode" type="u" direction="in">
cf6cdf
         <doc:doc>
cf6cdf
           <doc:summary>The type of logout that is being requested</doc:summary>
cf6cdf
         </doc:doc>
cf6cdf
       </arg>
cf6cdf
       <doc:doc>
cf6cdf
         <doc:description>
cf6cdf
           <doc:para>Request a logout dialog</doc:para>
cf6cdf
-- 
cf6cdf
2.17.0
cf6cdf