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