Based on the patch in GNOME #575544 Index: gnome-session-2.28.0/gnome-session/gsm-manager.c =================================================================== --- gnome-session-2.28.0.orig/gnome-session/gsm-manager.c 2009-09-18 18:36:04.000000000 +0200 +++ gnome-session-2.28.0/gnome-session/gsm-manager.c 2009-10-24 12:43:56.861770100 +0200 @@ -68,6 +68,7 @@ #define GSM_MANAGER_DBUS_NAME "org.gnome.SessionManager" #define GSM_MANAGER_PHASE_TIMEOUT 10 /* seconds */ +#define GSM_MANAGER_SAVE_SESSION_TIMEOUT 2 #define GDM_FLEXISERVER_COMMAND "gdmflexiserver" #define GDM_FLEXISERVER_ARGS "--startnew Standard" @@ -1147,6 +1148,69 @@ query_end_session_complete (GsmManager * } +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 +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); + g_error_free (error); + } +} + static guint32 generate_cookie (void) { @@ -1221,6 +1285,21 @@ _on_query_end_session_timeout (GsmManage return FALSE; } +static gboolean +_on_query_save_session_timeout (GsmManager *manager) +{ + manager->priv->query_timeout_id = 0; + + g_debug ("GsmManager: query to save session timed out"); + + g_slist_free (manager->priv->query_clients); + manager->priv->query_clients = NULL; + + query_save_session_complete (manager); + + return FALSE; +} + static void do_phase_query_end_session (GsmManager *manager) { @@ -1857,13 +1936,32 @@ on_client_end_session_response (GsmClien const char *reason, GsmManager *manager) { - /* just ignore if received outside of shutdown */ - if (manager->priv->phase < GSM_MANAGER_PHASE_QUERY_END_SESSION) { + /* just ignore if we are not yet running */ + if (manager->priv->phase < GSM_MANAGER_PHASE_RUNNING) { return; } g_debug ("GsmManager: Response from end session request: is-ok=%d do-last=%d cancel=%d reason=%s", is_ok, do_last, cancel, reason ? reason :""); + if (manager->priv->phase == GSM_MANAGER_PHASE_RUNNING) { + /* Ignore responses when no requests were sent */ + if (manager->priv->query_clients == NULL) { + return; + } + + manager->priv->query_clients = g_slist_remove (manager->priv->query_clients, client); + + if (do_last) { + manager->priv->next_query_clients = g_slist_prepend (manager->priv->next_query_clients, + client); + } + + if (manager->priv->query_clients == NULL) { + query_save_session_complete (manager); + } + return; + } + if (cancel) { cancel_end_session (manager); return; @@ -1962,6 +2060,15 @@ on_xsmp_client_logout_request (GsmXSMPCl } static void +on_xsmp_client_save_request (GsmXSMPClient *client, + gboolean show_dialog, + GsmManager *manager) +{ + g_debug ("GsmManager: save_request"); + gsm_manager_save_session (manager, NULL); +} + +static void on_store_client_added (GsmStore *store, const char *id, GsmManager *manager) @@ -1982,6 +2089,10 @@ on_store_client_added (GsmStore *store "logout-request", G_CALLBACK (on_xsmp_client_logout_request), manager); + g_signal_connect (client, + "save-request", + G_CALLBACK (on_xsmp_client_save_request), + manager); } g_signal_connect (client, @@ -2939,6 +3050,41 @@ gsm_manager_shutdown (GsmManager *manage } gboolean +gsm_manager_save_session (GsmManager *manager, + GError **error) +{ + ClientEndSessionData data; + + 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"); + 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); + return TRUE; + } else { + g_debug ("GsmManager: Nothing to save"); + return FALSE; + } +} + +gboolean gsm_manager_can_shutdown (GsmManager *manager, gboolean *shutdown_available, GError **error) Index: gnome-session-2.28.0/gnome-session/gsm-manager.h =================================================================== --- gnome-session-2.28.0.orig/gnome-session/gsm-manager.h 2009-04-19 20:26:52.000000000 +0200 +++ gnome-session-2.28.0/gnome-session/gsm-manager.h 2009-10-24 12:43:56.861770100 +0200 @@ -152,6 +152,9 @@ gboolean gsm_manager_is_inhib gboolean gsm_manager_shutdown (GsmManager *manager, GError **error); +gboolean gsm_manager_save_session (GsmManager *manager, + GError **error); + gboolean gsm_manager_can_shutdown (GsmManager *manager, gboolean *shutdown_available, GError **error); Index: gnome-session-2.28.0/gnome-session/gsm-xsmp-client.c =================================================================== --- gnome-session-2.28.0.orig/gnome-session/gsm-xsmp-client.c 2009-07-29 02:36:08.000000000 +0200 +++ gnome-session-2.28.0/gnome-session/gsm-xsmp-client.c 2009-10-24 12:43:56.861770100 +0200 @@ -70,6 +70,7 @@ enum { enum { REGISTER_REQUEST, LOGOUT_REQUEST, + SAVE_REQUEST, LAST_SIGNAL }; @@ -523,6 +524,30 @@ xsmp_cancel_end_session (GsmClient *clie return TRUE; } +static gboolean +xsmp_request_save (GsmClient *client, + guint flags, + GError **error) +{ + GsmXSMPClient *xsmp = (GsmXSMPClient *) client; + + g_debug ("GsmXSMPClient: xsmp_request_save ('%s')", xsmp->priv->description); + + if (xsmp->priv->conn == NULL) { + g_set_error (error, + GSM_CLIENT_ERROR, + GSM_CLIENT_ERROR_NOT_REGISTERED, + "Client is not registered"); + return FALSE; + } + + if (flags & GSM_CLIENT_END_SESSION_FLAG_LAST) + xsmp_save_yourself_phase2 (client); + else + do_save_yourself (xsmp, SmSaveLocal, FALSE); + + return TRUE; +} static char * get_desktop_file_path (GsmXSMPClient *client) { @@ -993,6 +1018,7 @@ gsm_xsmp_client_class_init (GsmXSMPClien object_class->get_property = gsm_xsmp_client_get_property; object_class->set_property = gsm_xsmp_client_set_property; + client_class->impl_request_save = xsmp_request_save; client_class->impl_save = xsmp_save; client_class->impl_stop = xsmp_stop; client_class->impl_query_end_session = xsmp_query_end_session; @@ -1023,6 +1049,17 @@ gsm_xsmp_client_class_init (GsmXSMPClien G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + signals[SAVE_REQUEST] = + g_signal_new ("save-request", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GsmXSMPClientClass, save_request), + NULL, + NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, + 1, G_TYPE_BOOLEAN); + g_object_class_install_property (object_class, PROP_ICE_CONNECTION, g_param_spec_pointer ("ice-connection", Index: gnome-session-2.28.0/gnome-session/gsm-xsmp-client.h =================================================================== --- gnome-session-2.28.0.orig/gnome-session/gsm-xsmp-client.h 2009-04-19 20:26:52.000000000 +0200 +++ gnome-session-2.28.0/gnome-session/gsm-xsmp-client.h 2009-10-24 12:43:56.861770100 +0200 @@ -54,7 +54,8 @@ struct _GsmXSMPClientClass char **client_id); gboolean (*logout_request) (GsmXSMPClient *client, gboolean prompt); - + gboolean (*save_request) (GsmXSMPClient *client, + gboolean prompt); void (*saved_state) (GsmXSMPClient *client); Index: gnome-session-2.28.0/gnome-session/org.gnome.SessionManager.xml =================================================================== --- gnome-session-2.28.0.orig/gnome-session/org.gnome.SessionManager.xml 2009-04-19 20:26:52.000000000 +0200 +++ gnome-session-2.28.0/gnome-session/org.gnome.SessionManager.xml 2009-10-24 12:43:56.865763345 +0200 @@ -256,6 +256,14 @@ + + + + Request to save session + + + + Index: gnome-session-2.28.0/capplet/gsm-properties-dialog.c =================================================================== --- gnome-session-2.28.0.orig/capplet/gsm-properties-dialog.c 2009-08-25 10:03:42.000000000 +0200 +++ gnome-session-2.28.0/capplet/gsm-properties-dialog.c 2009-10-24 13:21:57.910268989 +0200 @@ -35,6 +35,12 @@ #include "gsm-util.h" #include "gsp-app.h" #include "gsp-app-manager.h" +#include +#include + +#define GSM_SERVICE_DBUS "org.gnome.SessionManager" +#define GSM_PATH_DBUS "/org/gnome/SessionManager" +#define GSM_INTERFACE_DBUS "org.gnome.SessionManager" #define GSM_PROPERTIES_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_PROPERTIES_DIALOG, GsmPropertiesDialogPrivate)) @@ -50,6 +56,7 @@ #define CAPPLET_DELETE_WIDGET_NAME "session_properties_delete_button" #define CAPPLET_EDIT_WIDGET_NAME "session_properties_edit_button" #define CAPPLET_SAVE_WIDGET_NAME "session_properties_save_button" +#define CAPPLET_SESSION_SAVED_WIDGET_NAME "session_properties_session_saved_label" #define CAPPLET_REMEMBER_WIDGET_NAME "session_properties_remember_toggle" #define STARTUP_APP_ICON "system-run" @@ -493,10 +500,64 @@ on_autosave_value_toggled (GtkToggleButt } static void +session_saved_message (GsmPropertiesDialog *dialog, + const char *msg, + gboolean is_error) +{ + GtkLabel *label; + gchar *markup; + label = GTK_LABEL (gtk_builder_get_object (dialog->priv->xml, CAPPLET_SESSION_SAVED_WIDGET_NAME)); + if (is_error) + markup = g_markup_printf_escaped ("%s", msg); + else + markup = g_markup_escape_text (msg, -1); + gtk_label_set_markup (label, markup); + g_free (markup); +} + +static void +session_saved_cb (DBusGProxy *proxy, + DBusGProxyCall *call_id, + void *user_data) +{ + gboolean res; + GsmPropertiesDialog *dialog = user_data; + + res = dbus_g_proxy_end_call (proxy, call_id, NULL, G_TYPE_INVALID); + if (res) + session_saved_message (dialog, _("Your session has been saved."), FALSE); + else + session_saved_message (dialog, _("Failed to save session"), TRUE); + + g_object_unref (proxy); +} + +static void on_save_session_clicked (GtkWidget *widget, GsmPropertiesDialog *dialog) { - g_debug ("Session saving is not implemented yet!"); + DBusGConnection *conn; + DBusGProxy *proxy; + DBusGProxyCall *call; + + conn = dbus_g_bus_get (DBUS_BUS_SESSION, NULL); + if (conn == NULL) { + session_saved_message (dialog, _("Could not connect to the session bus"), TRUE); + return; + } + + proxy = dbus_g_proxy_new_for_name (conn, GSM_SERVICE_DBUS, GSM_PATH_DBUS, GSM_INTERFACE_DBUS); + if (proxy == NULL) { + session_saved_message (dialog, _("Could not connect to the session manager"), TRUE); + return; + } + + call = dbus_g_proxy_begin_call (proxy, "SaveSession", session_saved_cb, dialog, NULL, G_TYPE_INVALID); + if (call == NULL) { + session_saved_message (dialog, _("Failed to save session"), TRUE); + g_object_unref (proxy); + return; + } } static void Index: gnome-session-2.28.0/configure.in =================================================================== --- gnome-session-2.28.0.orig/configure.in 2009-09-09 02:21:06.000000000 +0200 +++ gnome-session-2.28.0/configure.in 2009-10-24 12:46:15.021757805 +0200 @@ -59,6 +59,7 @@ PKG_CHECK_MODULES(GNOME_SESSION, PKG_CHECK_MODULES(SESSION_PROPERTIES, glib-2.0 >= $GLIB_REQUIRED gtk+-2.0 >= $GTK_REQUIRED + dbus-glib-1 >= $DBUS_GLIB_REQUIRED ) PKG_CHECK_MODULES(SPLASH, Index: gnome-session-2.28.0/gnome-session/gsm-client.h =================================================================== --- gnome-session-2.28.0.orig/gnome-session/gsm-client.h 2009-04-19 20:26:52.000000000 +0200 +++ gnome-session-2.28.0/gnome-session/gsm-client.h 2009-10-24 12:43:56.873765479 +0200 @@ -92,6 +92,9 @@ struct _GsmClientClass GError **error); gboolean (*impl_stop) (GsmClient *client, GError **error); + gboolean (*impl_request_save) (GsmClient *client, + guint flags, + GError **error); GKeyFile * (*impl_save) (GsmClient *client, GError **error); }; @@ -137,6 +140,9 @@ gboolean gsm_client_cancel_ void gsm_client_disconnected (GsmClient *client); +gboolean gsm_client_request_save (GsmClient *client, + guint flags, + GError **error); GKeyFile *gsm_client_save (GsmClient *client, GError **error); /* exported to bus */ Index: gnome-session-2.28.0/gnome-session/gsm-dbus-client.c =================================================================== --- gnome-session-2.28.0.orig/gnome-session/gsm-dbus-client.c 2009-04-19 20:26:52.000000000 +0200 +++ gnome-session-2.28.0/gnome-session/gsm-dbus-client.c 2009-10-24 12:43:56.873765479 +0200 @@ -413,6 +413,19 @@ gsm_dbus_client_finalize (GObject *objec G_OBJECT_CLASS (gsm_dbus_client_parent_class)->finalize (object); } +static gboolean +dbus_client_request_save (GsmClient *client, + guint flags, + GError **error) +{ + g_debug ("GsmDBusClient: sending save request to client with id %s", + gsm_client_peek_id (client)); + + /* FIXME: The protocol does not support this */ + + return FALSE; +} + static GKeyFile * dbus_client_save (GsmClient *client, GError **error) @@ -665,6 +678,7 @@ gsm_dbus_client_class_init (GsmDBusClien object_class->set_property = gsm_dbus_client_set_property; object_class->dispose = gsm_dbus_client_dispose; + client_class->impl_request_save = dbus_client_request_save; client_class->impl_save = dbus_client_save; client_class->impl_stop = dbus_client_stop; client_class->impl_query_end_session = dbus_client_query_end_session; Index: gnome-session-2.28.0/gnome-session/gsm-client.c =================================================================== --- gnome-session-2.28.0.orig/gnome-session/gsm-client.c 2009-04-19 20:26:52.000000000 +0200 +++ gnome-session-2.28.0/gnome-session/gsm-client.c 2009-10-24 12:43:56.877763612 +0200 @@ -510,6 +510,16 @@ gsm_client_disconnected (GsmClient *clie g_signal_emit (client, signals[DISCONNECTED], 0); } +gboolean +gsm_client_request_save (GsmClient *client, + guint flags, + GError **error) +{ + g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE); + + return GSM_CLIENT_GET_CLASS (client)->impl_request_save (client, flags, error); +} + GKeyFile * gsm_client_save (GsmClient *client, GError **error) Index: gnome-session-2.28.0/data/session-properties.ui =================================================================== --- gnome-session-2.28.0.orig/data/session-properties.ui 2009-10-24 12:55:01.946268673 +0200 +++ gnome-session-2.28.0/data/session-properties.ui 2009-10-24 12:54:11.638268279 +0200 @@ -148,6 +148,7 @@ True + True True True @@ -191,6 +192,17 @@ 1 + + + True + True + + + False + False + 2 + + 1