You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
429 lines
16 KiB
429 lines
16 KiB
From 2c8e2b38a52a09e0710953d77fe8d9072a127e72 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 ede4186a..31dc67db 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.17.0 |
|
|
|
|