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

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