Blob Blame History Raw
From 1a767008113013cdefbb5b5de0bbfb77cd30b679 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 20 Dec 2013 10:48:03 -0500
Subject: [PATCH 01/14] session-properties: show it in the menus again

It provides functionality for adjusting the session which
customers rely on, so make it show up in the menus again.
---
 data/session-properties.desktop.in.in | 1 -
 1 file changed, 1 deletion(-)

diff --git a/data/session-properties.desktop.in.in b/data/session-properties.desktop.in.in
index 3dc7b03..1a506d9 100644
--- a/data/session-properties.desktop.in.in
+++ b/data/session-properties.desktop.in.in
@@ -1,15 +1,14 @@
 [Desktop Entry]
 _Name=Startup Applications
 _Comment=Choose what applications to start when you log in
 Exec=gnome-session-properties
 Icon=session-properties
 Terminal=false
 Type=Application
 StartupNotify=true
 Categories=GTK;GNOME;Settings;X-GNOME-PersonalSettings;
 OnlyShowIn=GNOME;Unity;
-NoDisplay=true
 X-GNOME-Bugzilla-Bugzilla=GNOME
 X-GNOME-Bugzilla-Product=gnome-session
 X-GNOME-Bugzilla-Component=gnome-session-properties
 X-GNOME-Bugzilla-Version=@VERSION@
-- 
1.8.3.1


From 68083665c3e7cb7d1915062820074f9b7fb42160 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 20 Dec 2013 15:07:35 -0500
Subject: [PATCH 02/14] session-properties: get out of Other

Put it in the menus next to Settings and Software
---
 data/session-properties.desktop.in.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/data/session-properties.desktop.in.in b/data/session-properties.desktop.in.in
index 1a506d9..e615d5c 100644
--- a/data/session-properties.desktop.in.in
+++ b/data/session-properties.desktop.in.in
@@ -1,14 +1,14 @@
 [Desktop Entry]
 _Name=Startup Applications
 _Comment=Choose what applications to start when you log in
 Exec=gnome-session-properties
 Icon=session-properties
 Terminal=false
 Type=Application
 StartupNotify=true
-Categories=GTK;GNOME;Settings;X-GNOME-PersonalSettings;
+Categories=GNOME;GTK;System;
 OnlyShowIn=GNOME;Unity;
 X-GNOME-Bugzilla-Bugzilla=GNOME
 X-GNOME-Bugzilla-Product=gnome-session
 X-GNOME-Bugzilla-Component=gnome-session-properties
 X-GNOME-Bugzilla-Version=@VERSION@
-- 
1.8.3.1


From 80e68ffa8eaa7dbff7097521e92dbc9bb18e0b82 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 20 Dec 2013 10:53:33 -0500
Subject: [PATCH 03/14] session-properties: refresh from recent glade

The ui file is rather old.  This commit just opens it up in a recent
glade and resaves it, so we have a fresh starting point to make
changes.
---
 data/session-properties.ui | 43 ++++++++++++++++++++++++++++++++++---------
 1 file changed, 34 insertions(+), 9 deletions(-)

diff --git a/data/session-properties.ui b/data/session-properties.ui
index 1f0cb9a..47a30f7 100644
--- a/data/session-properties.ui
+++ b/data/session-properties.ui
@@ -1,323 +1,348 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <interface>
-  <requires lib="gtk+" version="2.16"/>
-  <!-- interface-naming-policy toplevel-contextual -->
+  <!-- interface-requires gtk+ 3.0 -->
   <object class="GtkNotebook" id="main-notebook">
     <property name="visible">True</property>
     <property name="can_focus">True</property>
     <property name="border_width">6</property>
     <child>
       <object class="GtkVBox" id="vbox1">
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
         <property name="border_width">12</property>
-        <property name="orientation">vertical</property>
         <property name="spacing">3</property>
         <child>
           <object class="GtkLabel" id="label6">
             <property name="visible">True</property>
+            <property name="can_focus">False</property>
             <property name="xalign">0</property>
             <property name="xpad">3</property>
             <property name="ypad">3</property>
             <property name="label" translatable="yes">Additional startup _programs:</property>
             <property name="use_underline">True</property>
             <property name="mnemonic_widget">session_properties_treeview</property>
           </object>
           <packing>
             <property name="expand">False</property>
+            <property name="fill">True</property>
             <property name="position">0</property>
           </packing>
         </child>
         <child>
           <object class="GtkHBox" id="hbox1">
             <property name="visible">True</property>
+            <property name="can_focus">False</property>
             <property name="spacing">6</property>
             <child>
               <object class="GtkScrolledWindow" id="scrolledwindow1">
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="hscrollbar_policy">never</property>
-                <property name="vscrollbar_policy">automatic</property>
                 <property name="shadow_type">etched-in</property>
                 <child>
                   <object class="GtkTreeView" id="session_properties_treeview">
                     <property name="height_request">210</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
+                    <child internal-child="selection">
+                      <object class="GtkTreeSelection" id="treeview-selection1"/>
+                    </child>
                   </object>
                 </child>
               </object>
               <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
                 <property name="position">0</property>
               </packing>
             </child>
             <child>
               <object class="GtkVButtonBox" id="vbuttonbox1">
                 <property name="visible">True</property>
+                <property name="can_focus">False</property>
                 <property name="spacing">6</property>
                 <property name="layout_style">start</property>
                 <child>
                   <object class="GtkButton" id="session_properties_add_button">
                     <property name="label">gtk-add</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
                     <property name="receives_default">True</property>
                     <property name="use_stock">True</property>
                   </object>
                   <packing>
                     <property name="expand">False</property>
                     <property name="fill">False</property>
                     <property name="position">0</property>
                   </packing>
                 </child>
                 <child>
                   <object class="GtkButton" id="session_properties_delete_button">
                     <property name="label">gtk-remove</property>
                     <property name="visible">True</property>
                     <property name="sensitive">False</property>
                     <property name="can_focus">True</property>
                     <property name="receives_default">True</property>
                     <property name="use_stock">True</property>
                   </object>
                   <packing>
                     <property name="expand">False</property>
                     <property name="fill">False</property>
                     <property name="position">1</property>
                   </packing>
                 </child>
                 <child>
                   <object class="GtkButton" id="session_properties_edit_button">
                     <property name="label">gtk-edit</property>
                     <property name="visible">True</property>
                     <property name="sensitive">False</property>
                     <property name="can_focus">True</property>
                     <property name="receives_default">True</property>
                     <property name="use_stock">True</property>
                   </object>
                   <packing>
                     <property name="expand">False</property>
                     <property name="fill">False</property>
                     <property name="position">2</property>
                   </packing>
                 </child>
               </object>
               <packing>
                 <property name="expand">False</property>
                 <property name="fill">False</property>
                 <property name="position">1</property>
               </packing>
             </child>
           </object>
           <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
             <property name="position">1</property>
           </packing>
         </child>
       </object>
     </child>
     <child type="tab">
       <object class="GtkLabel" id="label4">
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
         <property name="label" translatable="yes">Startup Programs</property>
       </object>
       <packing>
         <property name="tab_fill">False</property>
       </packing>
     </child>
     <child>
       <object class="GtkVBox" id="vbox3">
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
         <property name="border_width">12</property>
-        <property name="orientation">vertical</property>
         <property name="spacing">6</property>
         <child>
           <object class="GtkCheckButton" id="session_properties_remember_toggle">
             <property name="label" translatable="yes">_Automatically remember running applications when logging out</property>
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <property name="receives_default">False</property>
             <property name="use_underline">True</property>
+            <property name="xalign">0.5</property>
             <property name="draw_indicator">True</property>
           </object>
           <packing>
             <property name="expand">False</property>
             <property name="fill">False</property>
             <property name="position">0</property>
           </packing>
         </child>
         <child>
           <object class="GtkHButtonBox" id="hbuttonbox1">
             <property name="visible">True</property>
+            <property name="can_focus">False</property>
             <child>
               <object class="GtkButton" id="session_properties_save_button">
                 <property name="can_focus">True</property>
                 <property name="receives_default">True</property>
                 <child>
                   <object class="GtkHBox" id="hbox2">
                     <property name="visible">True</property>
+                    <property name="can_focus">False</property>
                     <property name="spacing">4</property>
                     <child>
                       <object class="GtkImage" id="image1">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="stock">gtk-save</property>
                       </object>
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">False</property>
                         <property name="position">0</property>
                       </packing>
                     </child>
                     <child>
                       <object class="GtkLabel" id="label7">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="label" translatable="yes">_Remember Currently Running Applications</property>
                         <property name="use_underline">True</property>
                       </object>
                       <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
                         <property name="position">1</property>
                       </packing>
                     </child>
                   </object>
                 </child>
               </object>
               <packing>
                 <property name="expand">False</property>
                 <property name="fill">False</property>
                 <property name="position">0</property>
               </packing>
             </child>
           </object>
           <packing>
             <property name="expand">False</property>
             <property name="fill">False</property>
             <property name="position">1</property>
           </packing>
         </child>
       </object>
       <packing>
         <property name="position">1</property>
       </packing>
     </child>
     <child type="tab">
       <object class="GtkLabel" id="label5">
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
         <property name="label" translatable="yes">Options</property>
       </object>
       <packing>
         <property name="position">1</property>
         <property name="tab_fill">False</property>
       </packing>
     </child>
   </object>
   <object class="GtkTable" id="main-table">
     <property name="visible">True</property>
+    <property name="can_focus">False</property>
     <property name="border_width">6</property>
     <property name="n_rows">3</property>
     <property name="n_columns">2</property>
     <property name="column_spacing">12</property>
     <property name="row_spacing">6</property>
     <child>
       <object class="GtkHBox" id="hbox3">
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
         <property name="spacing">12</property>
         <child>
           <object class="GtkEntry" id="session_properties_command_entry">
             <property name="visible">True</property>
             <property name="can_focus">True</property>
-            <property name="invisible_char">&#x25CF;</property>
+            <property name="invisible_char">●</property>
           </object>
           <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
             <property name="position">0</property>
           </packing>
         </child>
         <child>
           <object class="GtkButton" id="session_properties_browse_button">
             <property name="label" translatable="yes">Browse…</property>
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <property name="receives_default">True</property>
           </object>
           <packing>
             <property name="expand">False</property>
             <property name="fill">False</property>
             <property name="position">1</property>
           </packing>
         </child>
       </object>
       <packing>
         <property name="left_attach">1</property>
         <property name="right_attach">2</property>
         <property name="top_attach">1</property>
         <property name="bottom_attach">2</property>
         <property name="y_options">GTK_FILL</property>
       </packing>
     </child>
     <child>
       <object class="GtkEntry" id="session_properties_comment_entry">
         <property name="visible">True</property>
         <property name="can_focus">True</property>
-        <property name="invisible_char">&#x25CF;</property>
+        <property name="invisible_char">●</property>
       </object>
       <packing>
         <property name="left_attach">1</property>
         <property name="right_attach">2</property>
         <property name="top_attach">2</property>
         <property name="bottom_attach">3</property>
         <property name="y_options">GTK_FILL</property>
       </packing>
     </child>
     <child>
       <object class="GtkEntry" id="session_properties_name_entry">
         <property name="visible">True</property>
         <property name="can_focus">True</property>
-        <property name="invisible_char">&#x25CF;</property>
+        <property name="invisible_char">●</property>
       </object>
       <packing>
         <property name="left_attach">1</property>
         <property name="right_attach">2</property>
         <property name="y_options">GTK_FILL</property>
       </packing>
     </child>
     <child>
       <object class="GtkLabel" id="label3">
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
         <property name="xalign">0</property>
         <property name="label" translatable="yes">Comm_ent:</property>
         <property name="use_underline">True</property>
         <property name="mnemonic_widget">label2</property>
       </object>
       <packing>
         <property name="top_attach">2</property>
         <property name="bottom_attach">3</property>
         <property name="x_options">GTK_FILL</property>
         <property name="y_options">GTK_FILL</property>
       </packing>
     </child>
     <child>
       <object class="GtkLabel" id="label2">
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
         <property name="xalign">0</property>
         <property name="label" translatable="yes">Co_mmand:</property>
         <property name="use_underline">True</property>
         <property name="mnemonic_widget">session_properties_command_entry</property>
       </object>
       <packing>
         <property name="top_attach">1</property>
         <property name="bottom_attach">2</property>
         <property name="x_options">GTK_FILL</property>
         <property name="y_options">GTK_FILL</property>
       </packing>
     </child>
     <child>
       <object class="GtkLabel" id="label1">
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
         <property name="xalign">0</property>
         <property name="label" translatable="yes">_Name:</property>
         <property name="use_underline">True</property>
         <property name="mnemonic_widget">session_properties_name_entry</property>
       </object>
       <packing>
         <property name="x_options">GTK_FILL</property>
         <property name="y_options">GTK_FILL</property>
       </packing>
     </child>
   </object>
 </interface>
-- 
1.8.3.1


From 94629d6620f5b46482f72e62cc2fb58c52e01268 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 20 Dec 2013 16:14:16 -0500
Subject: [PATCH 04/14] manager: Don't clear saved session if autosaving is
 disabled

Now that we support on-demand saving again, we need to make sure
we don't wipe that away at log out.
---
 gnome-session/gsm-manager.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/gnome-session/gsm-manager.c b/gnome-session/gsm-manager.c
index bcd4a7e..1620bd9 100644
--- a/gnome-session/gsm-manager.c
+++ b/gnome-session/gsm-manager.c
@@ -2099,61 +2099,60 @@ on_xsmp_client_register_request (GsmXSMPClient *client,
  out:
         g_free (*id);
         *id = new_id;
 
         return handled;
 }
 
 static gboolean
 auto_save_is_enabled (GsmManager *manager)
 {
         return g_settings_get_boolean (manager->priv->settings, KEY_AUTOSAVE_ONE_SHOT)
             || g_settings_get_boolean (manager->priv->settings, KEY_AUTOSAVE);
 }
 
 static void
 maybe_save_session (GsmManager *manager)
 {
         GError *error;
 
         if (gsm_system_is_login_session (manager->priv->system))
                 return;
 
         /* We only allow session saving when session is running or when
          * logging out */
         if (manager->priv->phase != GSM_MANAGER_PHASE_RUNNING &&
             manager->priv->phase != GSM_MANAGER_PHASE_END_SESSION) {
                 return;
         }
 
         if (!auto_save_is_enabled (manager)) {
-                gsm_session_save_clear ();
                 return;
         }
 
         error = NULL;
         gsm_session_save (manager->priv->clients, &error);
 
         if (error) {
                 g_warning ("Error saving session: %s", error->message);
                 g_error_free (error);
         }
 }
 
 static void
 _handle_client_end_session_response (GsmManager *manager,
                                      GsmClient  *client,
                                      gboolean    is_ok,
                                      gboolean    do_last,
                                      gboolean    cancel,
                                      const char *reason)
 {
         /* just ignore if received outside of shutdown */
         if (manager->priv->phase < GSM_MANAGER_PHASE_QUERY_END_SESSION) {
                 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 (cancel) {
                 cancel_end_session (manager);
                 return;
-- 
1.8.3.1


From bca5ebaa433125439d4f5dad94af13b2cb4bc13f Mon Sep 17 00:00:00 2001
From: Josselin Mouette <joss@malsain.org>
Date: Mon, 21 Jun 2010 15:22:23 -0400
Subject: [PATCH 05/14] Add "Remember Currently Running Applications" button

This adds back session saving that's not at logout.
---
 capplet/gsm-properties-dialog.c            |  63 +++++++++++-
 configure.ac                               |   1 +
 data/session-properties.ui                 |  12 +++
 gnome-session/gsm-client.c                 |  10 ++
 gnome-session/gsm-client.h                 |   6 ++
 gnome-session/gsm-dbus-client.c            |  14 +++
 gnome-session/gsm-manager.c                | 150 ++++++++++++++++++++++++++++-
 gnome-session/gsm-manager.h                |   3 +
 gnome-session/gsm-xsmp-client.c            |  37 +++++++
 gnome-session/gsm-xsmp-client.h            |   3 +-
 gnome-session/org.gnome.SessionManager.xml |   8 ++
 11 files changed, 303 insertions(+), 4 deletions(-)

diff --git a/capplet/gsm-properties-dialog.c b/capplet/gsm-properties-dialog.c
index 24bf907..4cc453a 100644
--- a/capplet/gsm-properties-dialog.c
+++ b/capplet/gsm-properties-dialog.c
@@ -5,70 +5,77 @@
  * Copyright (C) 2008 Lucas Rocha.
  * Copyright (C) 2008 William Jon McCann <jmccann@redhat.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
  */
 
 #include "config.h"
 
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 
 #include "gsm-properties-dialog.h"
 #include "gsm-app-dialog.h"
 #include "gsm-util.h"
 #include "gsp-app.h"
 #include "gsp-app-manager.h"
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#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))
 
 #define GTKBUILDER_FILE "session-properties.ui"
 
 #define CAPPLET_TREEVIEW_WIDGET_NAME      "session_properties_treeview"
 #define CAPPLET_ADD_WIDGET_NAME           "session_properties_add_button"
 #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"
 
 #define SPC_SETTINGS_SCHEMA          "org.gnome.SessionManager"
 #define SPC_SETTINGS_AUTOSAVE_KEY    "auto-save-session"
 
 struct GsmPropertiesDialogPrivate
 {
         GtkBuilder        *xml;
         GtkListStore      *list_store;
         GtkTreeModel      *tree_filter;
 
         GtkTreeView       *treeview;
         GtkWidget         *add_button;
         GtkWidget         *delete_button;
         GtkWidget         *edit_button;
 
         GSettings         *settings;
 
         GspAppManager     *manager;
 };
 
 enum {
         STORE_COL_VISIBLE = 0,
         STORE_COL_ENABLED,
         STORE_COL_GICON,
         STORE_COL_DESCRIPTION,
         STORE_COL_APP,
         STORE_COL_SEARCH,
@@ -431,64 +438,118 @@ on_edit_app_clicked (GtkWidget           *widget,
                 char       *comment;
 
                 edit_dialog = gsm_app_dialog_new (gsp_app_get_name (app),
                                                   gsp_app_get_exec (app),
                                                   gsp_app_get_comment (app));
                 gtk_window_set_transient_for (GTK_WINDOW (edit_dialog),
                                               GTK_WINDOW (dialog));
 
                 if (gsm_app_dialog_run (GSM_APP_DIALOG (edit_dialog),
                                         &name, &exec, &comment)) {
                         gsp_app_update (app, name, comment, exec);
                         g_free (name);
                         g_free (exec);
                         g_free (comment);
                 }
 
                 g_object_unref (app);
         }
 }
 
 static void
 on_row_activated (GtkTreeView         *tree_view,
                   GtkTreePath         *path,
                   GtkTreeViewColumn   *column,
                   GsmPropertiesDialog *dialog)  
 {
         on_edit_app_clicked (NULL, dialog);
 }
 
 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 ("<span foreground=\"red\">%s</span>", 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
 setup_dialog (GsmPropertiesDialog *dialog)
 {
         GtkTreeView       *treeview;
         GtkWidget         *button;
         GtkTreeModel      *tree_filter;
         GtkTreeViewColumn *column;
         GtkCellRenderer   *renderer;
         GtkTreeSelection  *selection;
         GtkTargetList     *targetlist;
 
         gtk_dialog_add_buttons (GTK_DIALOG (dialog),
                                 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
                                 NULL);
 
         dialog->priv->list_store = gtk_list_store_new (NUMBER_OF_COLUMNS,
                                                        G_TYPE_BOOLEAN,
                                                        G_TYPE_BOOLEAN,
                                                        G_TYPE_ICON,
                                                        G_TYPE_STRING,
                                                        G_TYPE_OBJECT,
                                                        G_TYPE_STRING);
         tree_filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (dialog->priv->list_store),
                                                  NULL);
         g_object_unref (dialog->priv->list_store);
         dialog->priv->tree_filter = tree_filter;
 
         gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (tree_filter),
diff --git a/configure.ac b/configure.ac
index a049b01..b71c979 100644
--- a/configure.ac
+++ b/configure.ac
@@ -46,60 +46,61 @@ AC_ARG_ENABLE(session-selector, AS_HELP_STRING([--enable-session-selector],
 
 AM_CONDITIONAL(BUILD_SESSION_SELECTOR,
                [test "$enable_session_selector" = yes])
 
 if test "$enable_session_selector" = yes; then
         PKG_CHECK_MODULES(SESSION_SELECTOR, gtk+-3.0 gio-2.0)
 fi
 
 dnl ====================================================================
 dnl Dependency Checks
 dnl ====================================================================
 
 dnl Standard vertical stacks
 PKG_CHECK_MODULES(GIO, gio-2.0)
 PKG_CHECK_MODULES(GIOUNIX, gio-unix-2.0 >= $GLIB_REQUIRED)
 PKG_CHECK_MODULES(GTK3, gtk+-3.0 >= $GTK3_REQUIRED)
 
 PKG_CHECK_MODULES(GNOME_SESSION,
         glib-2.0 >= $GLIB_REQUIRED
         gio-2.0 >= $GLIB_REQUIRED
         gtk+-3.0 >= $GTK3_REQUIRED
         dbus-glib-1 >= $DBUS_GLIB_REQUIRED
         upower-glib >= $UPOWER_REQUIRED
         json-glib-1.0 >= $JSON_GLIB_REQUIRED
         gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED
 )
 
 PKG_CHECK_MODULES(SESSION_PROPERTIES,
         glib-2.0 >= $GLIB_REQUIRED
         gtk+-3.0 >= $GTK3_REQUIRED
+        dbus-glib-1 >= $DBUS_GLIB_REQUIRED
 )
 
 PKG_CHECK_MODULES(X11, x11)
 PKG_CHECK_MODULES(SM, sm)
 PKG_CHECK_MODULES(ICE, ice)
 PKG_CHECK_MODULES(XEXT, xext xau)
 
 PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1 >= $DBUS_GLIB_REQUIRED)
 
 PKG_CHECK_MODULES(EGG_SMCLIENT, gtk+-3.0)
 
 PKG_CHECK_MODULES(GL_TEST, xcomposite gl glib-2.0)
 
 dnl ====================================================================
 dnl Check for gconf
 dnl ====================================================================
 AC_ARG_ENABLE([gconf],
               AS_HELP_STRING([--enable-gconf], [Support gconf-based autostart]),
               [enable_gconf=$enableval],
               [enable_gconf=auto])
 
 PKG_CHECK_MODULES(GCONF, gconf-2.0, [have_gconf=yes], [have_gconf=no])
 
 if test x$enable_gconf = xauto ; then
         enable_gconf=$have_gconf
 elif test x$enable_gconf = xyes -a x$have_gconf = xno ; then
         AC_MSG_ERROR([GConf support explicitly required, but gconf not found])
 fi
 
 if test x$enable_gconf = xyes ; then
diff --git a/data/session-properties.ui b/data/session-properties.ui
index 47a30f7..b43759f 100644
--- a/data/session-properties.ui
+++ b/data/session-properties.ui
@@ -133,108 +133,120 @@
       </packing>
     </child>
     <child>
       <object class="GtkVBox" id="vbox3">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="border_width">12</property>
         <property name="spacing">6</property>
         <child>
           <object class="GtkCheckButton" id="session_properties_remember_toggle">
             <property name="label" translatable="yes">_Automatically remember running applications when logging out</property>
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <property name="receives_default">False</property>
             <property name="use_underline">True</property>
             <property name="xalign">0.5</property>
             <property name="draw_indicator">True</property>
           </object>
           <packing>
             <property name="expand">False</property>
             <property name="fill">False</property>
             <property name="position">0</property>
           </packing>
         </child>
         <child>
           <object class="GtkHButtonBox" id="hbuttonbox1">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <child>
               <object class="GtkButton" id="session_properties_save_button">
+                <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="receives_default">True</property>
                 <child>
                   <object class="GtkHBox" id="hbox2">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="spacing">4</property>
                     <child>
                       <object class="GtkImage" id="image1">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="stock">gtk-save</property>
                       </object>
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">False</property>
                         <property name="position">0</property>
                       </packing>
                     </child>
                     <child>
                       <object class="GtkLabel" id="label7">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="label" translatable="yes">_Remember Currently Running Applications</property>
                         <property name="use_underline">True</property>
                       </object>
                       <packing>
                         <property name="expand">True</property>
                         <property name="fill">True</property>
                         <property name="position">1</property>
                       </packing>
                     </child>
                   </object>
                 </child>
               </object>
               <packing>
                 <property name="expand">False</property>
                 <property name="fill">False</property>
                 <property name="position">0</property>
               </packing>
             </child>
           </object>
           <packing>
             <property name="expand">False</property>
             <property name="fill">False</property>
             <property name="position">1</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkLabel" id="session_properties_session_saved_label">
+            <property name="visible">True</property>
+            <property name="wrap">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
       </object>
       <packing>
         <property name="position">1</property>
       </packing>
     </child>
     <child type="tab">
       <object class="GtkLabel" id="label5">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="label" translatable="yes">Options</property>
       </object>
       <packing>
         <property name="position">1</property>
         <property name="tab_fill">False</property>
       </packing>
     </child>
   </object>
   <object class="GtkTable" id="main-table">
     <property name="visible">True</property>
     <property name="can_focus">False</property>
     <property name="border_width">6</property>
     <property name="n_rows">3</property>
     <property name="n_columns">2</property>
     <property name="column_spacing">12</property>
     <property name="row_spacing">6</property>
     <child>
       <object class="GtkHBox" id="hbox3">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="spacing">12</property>
diff --git a/gnome-session/gsm-client.c b/gnome-session/gsm-client.c
index efabde0..46b71c1 100644
--- a/gnome-session/gsm-client.c
+++ b/gnome-session/gsm-client.c
@@ -495,49 +495,59 @@ gsm_client_query_end_session (GsmClient                *client,
         g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
 
         return GSM_CLIENT_GET_CLASS (client)->impl_query_end_session (client, flags, error);
 }
 
 gboolean
 gsm_client_end_session (GsmClient                *client,
                         GsmClientEndSessionFlag   flags,
                         GError                  **error)
 {
         g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
 
         return GSM_CLIENT_GET_CLASS (client)->impl_end_session (client, flags, error);
 }
 
 gboolean
 gsm_client_stop (GsmClient *client,
                  GError   **error)
 {
         g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
 
         return GSM_CLIENT_GET_CLASS (client)->impl_stop (client, error);
 }
 
 void
 gsm_client_disconnected (GsmClient *client)
 {
         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)
 {
         g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
 
         return GSM_CLIENT_GET_CLASS (client)->impl_save (client, error);
 }
 
 void
 gsm_client_end_session_response (GsmClient  *client,
                                  gboolean    is_ok,
                                  gboolean    do_last,
                                  gboolean    cancel,
                                  const char *reason)
 {
         g_signal_emit (client, signals[END_SESSION_RESPONSE], 0,
                        is_ok, do_last, cancel, reason);
 }
diff --git a/gnome-session/gsm-client.h b/gnome-session/gsm-client.h
index aeb03c2..4a90300 100644
--- a/gnome-session/gsm-client.h
+++ b/gnome-session/gsm-client.h
@@ -65,105 +65,111 @@ struct _GsmClient
         GObject           parent;
         GsmClientPrivate *priv;
 };
 
 struct _GsmClientClass
 {
         GObjectClass parent_class;
 
         /* signals */
         void         (*disconnected)               (GsmClient  *client);
         void         (*end_session_response)       (GsmClient  *client,
                                                     gboolean    ok,
                                                     gboolean    do_last,
                                                     gboolean    cancel,
                                                     const char *reason);
 
         /* virtual methods */
         char *                (*impl_get_app_name)           (GsmClient *client);
         GsmClientRestartStyle (*impl_get_restart_style_hint) (GsmClient *client);
         guint                 (*impl_get_unix_process_id)    (GsmClient *client);
         gboolean              (*impl_query_end_session)      (GsmClient *client,
                                                               GsmClientEndSessionFlag flags,
                                                               GError   **error);
         gboolean              (*impl_end_session)            (GsmClient *client,
                                                               GsmClientEndSessionFlag flags,
                                                               GError   **error);
         gboolean              (*impl_cancel_end_session)     (GsmClient *client,
                                                               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);
 };
 
 typedef enum
 {
         GSM_CLIENT_ERROR_GENERAL = 0,
         GSM_CLIENT_ERROR_NOT_REGISTERED,
         GSM_CLIENT_NUM_ERRORS
 } GsmClientError;
 
 #define GSM_CLIENT_ERROR gsm_client_error_quark ()
 #define GSM_CLIENT_TYPE_ERROR (gsm_client_error_get_type ())
 
 GType                 gsm_client_error_get_type             (void);
 GQuark                gsm_client_error_quark                (void);
 
 GType                 gsm_client_get_type                   (void) G_GNUC_CONST;
 
 const char           *gsm_client_peek_id                    (GsmClient  *client);
 
 
 const char *          gsm_client_peek_startup_id            (GsmClient  *client);
 const char *          gsm_client_peek_app_id                (GsmClient  *client);
 guint                 gsm_client_peek_restart_style_hint    (GsmClient  *client);
 guint                 gsm_client_peek_status                (GsmClient  *client);
 
 
 char                 *gsm_client_get_app_name               (GsmClient  *client);
 void                  gsm_client_set_app_id                 (GsmClient  *client,
                                                              const char *app_id);
 void                  gsm_client_set_status                 (GsmClient  *client,
                                                              guint       status);
 
 gboolean              gsm_client_end_session                (GsmClient  *client,
                                                              guint       flags,
                                                              GError    **error);
 gboolean              gsm_client_query_end_session          (GsmClient  *client,
                                                              guint       flags,
                                                              GError    **error);
 gboolean              gsm_client_cancel_end_session         (GsmClient  *client,
                                                              GError    **error);
 
 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 */
 gboolean              gsm_client_stop                       (GsmClient  *client,
                                                              GError    **error);
 gboolean              gsm_client_get_startup_id             (GsmClient  *client,
                                                              char      **startup_id,
                                                              GError    **error);
 gboolean              gsm_client_get_app_id                 (GsmClient  *client,
                                                              char      **app_id,
                                                              GError    **error);
 gboolean              gsm_client_get_restart_style_hint     (GsmClient  *client,
                                                              guint      *hint,
                                                              GError    **error);
 gboolean              gsm_client_get_status                 (GsmClient  *client,
                                                              guint      *status,
                                                              GError    **error);
 gboolean              gsm_client_get_unix_process_id        (GsmClient  *client,
                                                              guint      *pid,
                                                              GError    **error);
 
 /* private */
 
 void                  gsm_client_end_session_response       (GsmClient  *client,
                                                              gboolean    is_ok,
                                                              gboolean    do_last,
                                                              gboolean    cancel,
                                                              const char *reason);
 
 G_END_DECLS
diff --git a/gnome-session/gsm-dbus-client.c b/gnome-session/gsm-dbus-client.c
index 3f7621a..691156c 100644
--- a/gnome-session/gsm-dbus-client.c
+++ b/gnome-session/gsm-dbus-client.c
@@ -384,60 +384,73 @@ gsm_dbus_client_set_property (GObject       *object,
 static void
 gsm_dbus_client_get_property (GObject    *object,
                               guint       prop_id,
                               GValue     *value,
                               GParamSpec *pspec)
 {
         GsmDBusClient *self;
 
         self = GSM_DBUS_CLIENT (object);
 
         switch (prop_id) {
         case PROP_BUS_NAME:
                 g_value_set_string (value, self->priv->bus_name);
                 break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
         }
 }
 
 static void
 gsm_dbus_client_finalize (GObject *object)
 {
         GsmDBusClient *client = (GsmDBusClient *) object;
 
         g_free (client->priv->bus_name);
 
         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)
 {
         g_debug ("GsmDBusClient: saving client with id %s",
                  gsm_client_peek_id (client));
 
         /* FIXME: We still don't support client saving for D-Bus
          * session clients */
 
         return NULL;
 }
 
 static gboolean
 dbus_client_stop (GsmClient *client,
                   GError   **error)
 {
         GsmDBusClient  *dbus_client = (GsmDBusClient *) client;
         DBusMessage    *message;
         gboolean        ret;
 
         ret = FALSE;
 
         /* unicast the signal to only the registered bus name */
         message = dbus_message_new_signal (gsm_client_peek_id (client),
                                            SM_DBUS_CLIENT_PRIVATE_INTERFACE,
                                            "Stop");
         if (message == NULL) {
                 goto out;
         }
@@ -636,60 +649,61 @@ dbus_client_cancel_end_session (GsmClient *client,
         return ret;
 }
 
 static void
 gsm_dbus_client_dispose (GObject *object)
 {
         GsmDBusClient *client;
 
         g_return_if_fail (object != NULL);
         g_return_if_fail (GSM_IS_DBUS_CLIENT (object));
 
         client = GSM_DBUS_CLIENT (object);
 
         dbus_connection_remove_filter (client->priv->connection, client_dbus_filter_function, client);
 
         G_OBJECT_CLASS (gsm_dbus_client_parent_class)->dispose (object);
 }
 
 static void
 gsm_dbus_client_class_init (GsmDBusClientClass *klass)
 {
         GObjectClass   *object_class = G_OBJECT_CLASS (klass);
         GsmClientClass *client_class = GSM_CLIENT_CLASS (klass);
 
         object_class->finalize             = gsm_dbus_client_finalize;
         object_class->constructor          = gsm_dbus_client_constructor;
         object_class->get_property         = gsm_dbus_client_get_property;
         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;
         client_class->impl_end_session            = dbus_client_end_session;
         client_class->impl_cancel_end_session     = dbus_client_cancel_end_session;
         client_class->impl_get_app_name           = dbus_client_get_app_name;
         client_class->impl_get_restart_style_hint = dbus_client_get_restart_style_hint;
         client_class->impl_get_unix_process_id    = dbus_client_get_unix_process_id;
 
         g_object_class_install_property (object_class,
                                          PROP_BUS_NAME,
                                          g_param_spec_string ("bus-name",
                                                               "bus-name",
                                                               "bus-name",
                                                               NULL,
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
         g_type_class_add_private (klass, sizeof (GsmDBusClientPrivate));
 }
 
 GsmClient *
 gsm_dbus_client_new (const char *startup_id,
                      const char *bus_name)
 {
         GsmDBusClient *client;
 
         client = g_object_new (GSM_TYPE_DBUS_CLIENT,
                                "startup-id", startup_id,
                                "bus-name", bus_name,
                                NULL);
diff --git a/gnome-session/gsm-manager.c b/gnome-session/gsm-manager.c
index 1620bd9..e2a493f 100644
--- a/gnome-session/gsm-manager.c
+++ b/gnome-session/gsm-manager.c
@@ -60,60 +60,61 @@
 #include "gsm-autostart-app.h"
 
 #include "gsm-util.h"
 #include "gdm.h"
 #include "gsm-logout-dialog.h"
 #include "gsm-icon-names.h"
 #include "gsm-inhibit-dialog.h"
 #include "gsm-system.h"
 #include "gsm-session-save.h"
 #include "gsm-shell-extensions.h"
 #include "gsm-fail-whale.h"
 
 #define GSM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_MANAGER, GsmManagerPrivate))
 
 /* UUIDs for log messages */
 #define GSM_MANAGER_STARTUP_SUCCEEDED_MSGID     "0ce153587afa4095832d233c17a88001"
 #define GSM_MANAGER_UNRECOVERABLE_FAILURE_MSGID "10dd2dc188b54a5e98970f56499d1f73"
 
 #define GSM_MANAGER_DBUS_PATH "/org/gnome/SessionManager"
 #define GSM_MANAGER_DBUS_NAME "org.gnome.SessionManager"
 
 /* Probably about the longest amount of time someone could reasonably
  * want to wait, at least for something happening more than once.
  * We can get deployed on very slow media though like CDROM devices,
  * often with complex stacking/compressing filesystems on top, which
  * is not a recipie for speed.   Particularly now that we throw up
  * a fail whale if required components don't show up quickly enough,
  * let's make this fairly long.
  */
 #define GSM_MANAGER_PHASE_TIMEOUT 90 /* seconds */
+#define GSM_MANAGER_SAVE_SESSION_TIMEOUT 2
 
 #define GDM_FLEXISERVER_COMMAND "gdmflexiserver"
 #define GDM_FLEXISERVER_ARGS    "--startnew Standard"
 
 #define SESSION_SCHEMA            "org.gnome.desktop.session"
 #define KEY_IDLE_DELAY            "idle-delay"
 #define KEY_SESSION_NAME          "session-name"
 
 #define GSM_MANAGER_SCHEMA        "org.gnome.SessionManager"
 #define KEY_AUTOSAVE              "auto-save-session"
 #define KEY_AUTOSAVE_ONE_SHOT     "auto-save-session-one-shot"
 #define KEY_LOGOUT_PROMPT         "logout-prompt"
 #define KEY_SHOW_FALLBACK_WARNING "show-fallback-warning"
 
 #define SCREENSAVER_SCHEMA        "org.gnome.desktop.screensaver"
 #define KEY_SLEEP_LOCK            "lock-enabled"
 
 #define LOCKDOWN_SCHEMA           "org.gnome.desktop.lockdown"
 #define KEY_DISABLE_LOG_OUT       "disable-log-out"
 #define KEY_DISABLE_USER_SWITCHING "disable-user-switching"
 
 static void app_registered (GsmApp     *app, GsmManager *manager);
 
 typedef enum
 {
         GSM_MANAGER_LOGOUT_NONE,
         GSM_MANAGER_LOGOUT_LOGOUT,
         GSM_MANAGER_LOGOUT_REBOOT,
         GSM_MANAGER_LOGOUT_REBOOT_INTERACT,
         GSM_MANAGER_LOGOUT_REBOOT_GDM,
@@ -1338,60 +1339,123 @@ end_session_or_show_shell_dialog (GsmManager *manager)
                 end_phase (manager);
                 break;
         default:
                 g_assert_not_reached ();
                 break;
         }
 
 }
 
 static void
 query_end_session_complete (GsmManager *manager)
 {
 
         g_debug ("GsmManager: query end session complete");
 
         /* Remove the timeout since this can be called from outside the timer
          * and we don't want to have it called twice */
         if (manager->priv->query_timeout_id > 0) {
                 g_source_remove (manager->priv->query_timeout_id);
                 manager->priv->query_timeout_id = 0;
         }
 
         if (gsm_shell_is_running (manager->priv->shell)) {
                 end_session_or_show_shell_dialog (manager);
         } else {
                 end_session_or_show_fallback_dialog (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
+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)
 {
         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;
 
         manager->priv->query_timeout_id = 0;
 
         g_debug ("GsmManager: query end session timed out");
@@ -1418,60 +1482,75 @@ _on_query_end_session_timeout (GsmManager *manager)
                         bus_name = NULL;
                 }
 
                 app_id = g_strdup (gsm_client_peek_app_id (l->data));
                 if (IS_STRING_EMPTY (app_id)) {
                         /* XSMP clients don't give us an app id unless we start them */
                         g_free (app_id);
                         app_id = gsm_client_get_app_name (l->data);
                 }
 
                 cookie = _generate_unique_cookie (manager);
                 inhibitor = gsm_inhibitor_new_for_client (gsm_client_peek_id (l->data),
                                                           app_id,
                                                           GSM_INHIBITOR_FLAG_LOGOUT,
                                                           _("Not responding"),
                                                           bus_name,
                                                           cookie);
                 g_free (app_id);
                 gsm_store_add (manager->priv->inhibitors, gsm_inhibitor_peek_id (inhibitor), G_OBJECT (inhibitor));
                 g_object_unref (inhibitor);
         }
 
         g_slist_free (manager->priv->query_clients);
         manager->priv->query_clients = NULL;
 
         query_end_session_complete (manager);
 
         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)
 {
         ClientEndSessionData data;
 
         data.manager = manager;
         data.flags = 0;
 
         if (manager->priv->logout_mode == GSM_MANAGER_LOGOUT_MODE_FORCE) {
                 data.flags |= GSM_CLIENT_END_SESSION_FLAG_FORCEFUL;
         }
         /* We only query if an app is ready to log out, so we don't use
          * GSM_CLIENT_END_SESSION_FLAG_SAVE here.
          */
 
         debug_clients (manager);
         g_debug ("GsmManager: sending query-end-session to clients (logout mode: %s)",
                  manager->priv->logout_mode == GSM_MANAGER_LOGOUT_MODE_NORMAL? "normal" :
                  manager->priv->logout_mode == GSM_MANAGER_LOGOUT_MODE_FORCE? "forceful":
                  "no confirmation");
         gsm_store_foreach (manager->priv->clients,
                            (GsmStoreFunc)_client_query_end_session,
                            &data);
 
         /* This phase doesn't time out unless logout is forced. Typically, this
          * separate timer is only used to show UI. */
         manager->priv->query_timeout_id = g_timeout_add_seconds (1, (GSourceFunc)_on_query_end_session_timeout, manager);
 }
 
 static void
@@ -2119,67 +2198,86 @@ maybe_save_session (GsmManager *manager)
                 return;
 
         /* We only allow session saving when session is running or when
          * logging out */
         if (manager->priv->phase != GSM_MANAGER_PHASE_RUNNING &&
             manager->priv->phase != GSM_MANAGER_PHASE_END_SESSION) {
                 return;
         }
 
         if (!auto_save_is_enabled (manager)) {
                 return;
         }
 
         error = NULL;
         gsm_session_save (manager->priv->clients, &error);
 
         if (error) {
                 g_warning ("Error saving session: %s", error->message);
                 g_error_free (error);
         }
 }
 
 static void
 _handle_client_end_session_response (GsmManager *manager,
                                      GsmClient  *client,
                                      gboolean    is_ok,
                                      gboolean    do_last,
                                      gboolean    cancel,
                                      const char *reason)
 {
-        /* 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;
         }
 
         manager->priv->query_clients = g_slist_remove (manager->priv->query_clients, client);
 
         if (! is_ok && manager->priv->logout_mode != GSM_MANAGER_LOGOUT_MODE_FORCE) {
                 guint         cookie;
                 GsmInhibitor *inhibitor;
                 char         *app_id;
                 const char   *bus_name;
 
                 /* FIXME: do we support updating the reason? */
 
                 /* Create JIT inhibit */
                 if (GSM_IS_DBUS_CLIENT (client)) {
                         bus_name = gsm_dbus_client_get_bus_name (GSM_DBUS_CLIENT (client));
                 } else {
                         bus_name = NULL;
                 }
 
                 app_id = g_strdup (gsm_client_peek_app_id (client));
                 if (IS_STRING_EMPTY (app_id)) {
                         /* XSMP clients don't give us an app id unless we start them */
                         g_free (app_id);
                         app_id = gsm_client_get_app_name (client);
                 }
 
                 cookie = _generate_unique_cookie (manager);
@@ -2240,80 +2338,93 @@ on_client_end_session_response (GsmClient  *client,
                                              client,
                                              is_ok,
                                              do_last,
                                              cancel,
                                              reason);
 }
 
 static void
 on_xsmp_client_logout_request (GsmXSMPClient *client,
                                gboolean       show_dialog,
                                GsmManager    *manager)
 {
         GError *error;
         int     logout_mode;
 
         if (show_dialog) {
                 logout_mode = GSM_MANAGER_LOGOUT_MODE_NORMAL;
         } else {
                 logout_mode = GSM_MANAGER_LOGOUT_MODE_NO_CONFIRMATION;
         }
 
         error = NULL;
         gsm_manager_logout (manager, logout_mode, &error);
         if (error != NULL) {
                 g_warning ("Unable to logout: %s", error->message);
                 g_error_free (error);
         }
 }
 
 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)
 {
         GsmClient *client;
 
         g_debug ("GsmManager: Client added: %s", id);
 
         client = (GsmClient *)gsm_store_lookup (store, id);
 
         /* a bit hacky */
         if (GSM_IS_XSMP_CLIENT (client)) {
                 g_signal_connect (client,
                                   "register-request",
                                   G_CALLBACK (on_xsmp_client_register_request),
                                   manager);
                 g_signal_connect (client,
                                   "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,
                           "end-session-response",
                           G_CALLBACK (on_client_end_session_response),
                           manager);
 
         g_signal_emit (manager, signals [CLIENT_ADDED], 0, id);
         /* FIXME: disconnect signal handler */
 }
 
 static void
 on_store_client_removed (GsmStore   *store,
                          const char *id,
                          GsmManager *manager)
 {
         g_debug ("GsmManager: Client removed: %s", id);
 
         g_signal_emit (manager, signals [CLIENT_REMOVED], 0, id);
 }
 
 static void
 gsm_manager_set_client_store (GsmManager *manager,
                               GsmStore   *store)
 {
         g_return_if_fail (GSM_IS_MANAGER (manager));
 
         if (store != NULL) {
                 g_object_ref (store);
         }
@@ -3506,60 +3617,95 @@ gsm_manager_reboot (GsmManager  *manager,
         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,
                              "Reboot interface is only available during the Running phase");
                 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;
         }
 
         shell_running = gsm_shell_is_running (manager->priv->shell);
 
         if (!shell_running)
                 show_fallback_shutdown_dialog (manager, TRUE);
         else
                 request_reboot (manager);
 
         return TRUE;
 }
 
 
 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)
 {
         g_debug ("GsmManager: CanShutdown called");
 
         g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
 
         *shutdown_available = !_log_out_is_locked_down (manager) &&
                               (gsm_system_can_stop (manager->priv->system)
                                || gsm_system_can_restart (manager->priv->system)
                                || gsm_system_can_suspend (manager->priv->system)
                                || gsm_system_can_hibernate (manager->priv->system));
 
         return TRUE;
 }
 
 gboolean
 gsm_manager_logout (GsmManager *manager,
                     guint       logout_mode,
                     GError    **error)
 {
         g_debug ("GsmManager: Logout 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,
diff --git a/gnome-session/gsm-manager.h b/gnome-session/gsm-manager.h
index f9632d7..9dbc814 100644
--- a/gnome-session/gsm-manager.h
+++ b/gnome-session/gsm-manager.h
@@ -134,60 +134,63 @@ void                _gsm_manager_set_active_session            (GsmManager     *
 
 /* exported methods */
 
 gboolean            gsm_manager_register_client                (GsmManager            *manager,
                                                                 const char            *app_id,
                                                                 const char            *client_startup_id,
                                                                 DBusGMethodInvocation *context);
 gboolean            gsm_manager_unregister_client              (GsmManager            *manager,
                                                                 const char            *session_client_id,
                                                                 DBusGMethodInvocation *context);
 
 gboolean            gsm_manager_inhibit                        (GsmManager            *manager,
                                                                 const char            *app_id,
                                                                 guint                  toplevel_xid,
                                                                 const char            *reason,
                                                                 guint                  flags,
                                                                 DBusGMethodInvocation *context);
 gboolean            gsm_manager_uninhibit                      (GsmManager            *manager,
                                                                 guint                  inhibit_cookie,
                                                                 DBusGMethodInvocation *context);
 gboolean            gsm_manager_is_inhibited                   (GsmManager            *manager,
                                                                 guint                  flags,
                                                                 gboolean              *is_inhibited,
                                                                 GError                *error);
 
 gboolean            gsm_manager_shutdown                       (GsmManager     *manager,
                                                                 GError        **error);
 gboolean            gsm_manager_reboot                         (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);
 gboolean            gsm_manager_logout                         (GsmManager     *manager,
                                                                 guint           logout_mode,
                                                                 GError        **error);
 
 gboolean            gsm_manager_setenv                         (GsmManager     *manager,
                                                                 const char     *variable,
                                                                 const char     *value,
                                                                 GError        **error);
 gboolean            gsm_manager_get_locale                     (GsmManager     *manager,
                                                                 int             category,
                                                                 const char    **value,
                                                                 GError        **error);
 gboolean            gsm_manager_initialization_error           (GsmManager     *manager,
                                                                 const char     *message,
                                                                 gboolean        fatal,
                                                                 GError        **error);
 
 gboolean            gsm_manager_get_clients                    (GsmManager     *manager,
                                                                 GPtrArray     **clients,
                                                                 GError        **error);
 gboolean            gsm_manager_get_inhibitors                 (GsmManager     *manager,
                                                                 GPtrArray     **inhibitors,
                                                                 GError        **error);
 gboolean            gsm_manager_is_autostart_condition_handled (GsmManager     *manager,
                                                                 const char     *condition,
                                                                 gboolean       *handled,
                                                                 GError        **error);
diff --git a/gnome-session/gsm-xsmp-client.c b/gnome-session/gsm-xsmp-client.c
index f84fab3..a80e79b 100644
--- a/gnome-session/gsm-xsmp-client.c
+++ b/gnome-session/gsm-xsmp-client.c
@@ -40,60 +40,61 @@
 
 #define GsmDesktopFile "_GSM_DesktopFile"
 
 #define GSM_XSMP_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_XSMP_CLIENT, GsmXSMPClientPrivate))
 
 struct GsmXSMPClientPrivate
 {
 
         SmsConn    conn;
         IceConn    ice_connection;
 
         guint      watch_id;
 
         char      *description;
         GPtrArray *props;
 
         /* SaveYourself state */
         int        current_save_yourself;
         int        next_save_yourself;
         guint      next_save_yourself_allow_interact : 1;
 };
 
 enum {
         PROP_0,
         PROP_ICE_CONNECTION
 };
 
 enum {
         REGISTER_REQUEST,
         LOGOUT_REQUEST,
+	SAVE_REQUEST,
         LAST_SIGNAL
 };
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
 G_DEFINE_TYPE (GsmXSMPClient, gsm_xsmp_client, GSM_TYPE_CLIENT)
 
 static gboolean
 client_iochannel_watch (GIOChannel    *channel,
                         GIOCondition   condition,
                         GsmXSMPClient *client)
 {
         gboolean keep_going;
 
         g_object_ref (client);
         switch (IceProcessMessages (client->priv->ice_connection, NULL, NULL)) {
         case IceProcessMessagesSuccess:
                 keep_going = TRUE;
                 break;
 
         case IceProcessMessagesIOError:
                 g_debug ("GsmXSMPClient: IceProcessMessagesIOError on '%s'", client->priv->description);
                 gsm_client_set_status (GSM_CLIENT (client), GSM_CLIENT_FAILED);
                 /* Emitting "disconnected" will eventually cause
                  * IceCloseConnection() to be called.
                  */
                 gsm_client_disconnected (GSM_CLIENT (client));
                 keep_going = FALSE;
                 break;
 
@@ -473,60 +474,84 @@ xsmp_interact (GsmClient *client)
 
         SmsInteract (xsmp->priv->conn);
 }
 
 static gboolean
 xsmp_cancel_end_session (GsmClient *client,
                          GError   **error)
 {
         GsmXSMPClient *xsmp = (GsmXSMPClient *) client;
 
         g_debug ("GsmXSMPClient: xsmp_cancel_end_session ('%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;
         }
 
         SmsShutdownCancelled (xsmp->priv->conn);
 
         /* reset the state */
         xsmp->priv->current_save_yourself = -1;
         xsmp->priv->next_save_yourself = -1;
         xsmp->priv->next_save_yourself_allow_interact = FALSE;
 
         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)
 {
         SmProp     *prop;
         char       *desktop_file_path = NULL;
         const char *program_name;
 
         /* XSMP clients using eggsmclient defines a special property
          * pointing to their respective desktop entry file */
         prop = find_property (client, GsmDesktopFile, NULL);
 
         if (prop) {
                 GFile *file = g_file_new_for_uri (prop->vals[0].value);
                 desktop_file_path = g_file_get_path (file);
                 g_object_unref (file);
                 goto out;
         }
 
         /* If we can't get desktop file from GsmDesktopFile then we
          * try to find the desktop file from its program name */
         prop = find_property (client, SmProgram, NULL);
 
         if (!prop) {
                 goto out;
         }
 
         program_name = prop->vals[0].value;
         desktop_file_path =
                 gsm_util_find_desktop_file_for_app_name (program_name,
                                                          TRUE, FALSE);
@@ -956,90 +981,102 @@ xsmp_get_unix_process_id (GsmClient *client)
         gboolean res;
 
         g_debug ("GsmXSMPClient: getting pid");
 
         prop = find_property (GSM_XSMP_CLIENT (client), SmProcessID, NULL);
 
         if (!prop || strcmp (prop->type, SmARRAY8) != 0) {
                 return 0;
         }
 
         pid = 0;
         res = _parse_value_as_uint ((char *)prop->vals[0].value, &pid);
         if (! res) {
                 pid = 0;
         }
 
         return pid;
 }
 
 static void
 gsm_xsmp_client_class_init (GsmXSMPClientClass *klass)
 {
         GObjectClass   *object_class = G_OBJECT_CLASS (klass);
         GsmClientClass *client_class = GSM_CLIENT_CLASS (klass);
 
         object_class->finalize             = gsm_xsmp_client_finalize;
         object_class->constructor          = gsm_xsmp_client_constructor;
         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;
         client_class->impl_end_session            = xsmp_end_session;
         client_class->impl_cancel_end_session     = xsmp_cancel_end_session;
         client_class->impl_get_app_name           = xsmp_get_app_name;
         client_class->impl_get_restart_style_hint = xsmp_get_restart_style_hint;
         client_class->impl_get_unix_process_id    = xsmp_get_unix_process_id;
 
         signals[REGISTER_REQUEST] =
                 g_signal_new ("register-request",
                               G_OBJECT_CLASS_TYPE (object_class),
                               G_SIGNAL_RUN_LAST,
                               G_STRUCT_OFFSET (GsmXSMPClientClass, register_request),
                               _boolean_handled_accumulator,
                               NULL,
                               NULL,
                               G_TYPE_BOOLEAN,
                               1, G_TYPE_POINTER);
         signals[LOGOUT_REQUEST] =
                 g_signal_new ("logout-request",
                               G_OBJECT_CLASS_TYPE (object_class),
                               G_SIGNAL_RUN_LAST,
                               G_STRUCT_OFFSET (GsmXSMPClientClass, logout_request),
                               NULL,
                               NULL,
                               NULL,
                               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",
                                                                "ice-connection",
                                                                "ice-connection",
                                                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
         g_type_class_add_private (klass, sizeof (GsmXSMPClientPrivate));
 }
 
 GsmClient *
 gsm_xsmp_client_new (IceConn ice_conn)
 {
         GsmXSMPClient *xsmp;
 
         xsmp = g_object_new (GSM_TYPE_XSMP_CLIENT,
                              "ice-connection", ice_conn,
                              NULL);
 
         return GSM_CLIENT (xsmp);
 }
 
 static Status
 register_client_callback (SmsConn    conn,
                           SmPointer  manager_data,
                           char      *previous_id)
 {
         GsmXSMPClient *client = manager_data;
         gboolean       handled;
         char          *id;
diff --git a/gnome-session/gsm-xsmp-client.h b/gnome-session/gsm-xsmp-client.h
index b80f933..8f9ddd9 100644
--- a/gnome-session/gsm-xsmp-client.h
+++ b/gnome-session/gsm-xsmp-client.h
@@ -27,61 +27,62 @@
 
 G_BEGIN_DECLS
 
 #define GSM_TYPE_XSMP_CLIENT            (gsm_xsmp_client_get_type ())
 #define GSM_XSMP_CLIENT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSM_TYPE_XSMP_CLIENT, GsmXSMPClient))
 #define GSM_XSMP_CLIENT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GSM_TYPE_XSMP_CLIENT, GsmXSMPClientClass))
 #define GSM_IS_XSMP_CLIENT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSM_TYPE_XSMP_CLIENT))
 #define GSM_IS_XSMP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSM_TYPE_XSMP_CLIENT))
 #define GSM_XSMP_CLIENT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GSM_TYPE_XSMP_CLIENT, GsmXSMPClientClass))
 
 typedef struct _GsmXSMPClient        GsmXSMPClient;
 typedef struct _GsmXSMPClientClass   GsmXSMPClientClass;
 
 typedef struct GsmXSMPClientPrivate  GsmXSMPClientPrivate;
 
 struct _GsmXSMPClient
 {
         GsmClient             parent;
         GsmXSMPClientPrivate *priv;
 };
 
 struct _GsmXSMPClientClass
 {
         GsmClientClass parent_class;
 
         /* signals */
         gboolean (*register_request)     (GsmXSMPClient  *client,
                                           char          **client_id);
         gboolean (*logout_request)       (GsmXSMPClient  *client,
                                           gboolean        prompt);
-
+        gboolean (*save_request)         (GsmXSMPClient  *client,
+                                          gboolean        prompt);
 
         void     (*saved_state)          (GsmXSMPClient  *client);
 
         void     (*request_phase2)       (GsmXSMPClient  *client);
 
         void     (*request_interaction)  (GsmXSMPClient  *client);
         void     (*interaction_done)     (GsmXSMPClient  *client,
                                           gboolean        cancel_shutdown);
 
         void     (*save_yourself_done)   (GsmXSMPClient  *client);
 
 };
 
 GType       gsm_xsmp_client_get_type             (void) G_GNUC_CONST;
 
 GsmClient  *gsm_xsmp_client_new                  (IceConn         ice_conn);
 
 void        gsm_xsmp_client_connect              (GsmXSMPClient  *client,
                                                   SmsConn         conn,
                                                   unsigned long  *mask_ret,
                                                   SmsCallbacks   *callbacks_ret);
 
 void        gsm_xsmp_client_save_state           (GsmXSMPClient  *client);
 void        gsm_xsmp_client_save_yourself        (GsmXSMPClient  *client,
                                                   gboolean        save_state);
 void        gsm_xsmp_client_save_yourself_phase2 (GsmXSMPClient  *client);
 void        gsm_xsmp_client_interact             (GsmXSMPClient  *client);
 void        gsm_xsmp_client_shutdown_cancelled   (GsmXSMPClient  *client);
 
 G_END_DECLS
diff --git a/gnome-session/org.gnome.SessionManager.xml b/gnome-session/org.gnome.SessionManager.xml
index eb69180..873e250 100644
--- a/gnome-session/org.gnome.SessionManager.xml
+++ b/gnome-session/org.gnome.SessionManager.xml
@@ -259,60 +259,68 @@
       </arg>
       <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">
+      <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>
           <doc:para>
             Allowed values for the mode parameter are:
             <doc:list>
               <doc:item>
                 <doc:term>0</doc:term>
                 <doc:definition>Normal.</doc:definition>
               </doc:item>
-- 
1.8.3.1


From 50ed23822cd3318518f6427f19889b944f4d4cc8 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 20 Dec 2013 11:22:07 -0500
Subject: [PATCH 06/14] Revert "Allow saved-session to be a symlink"

This reverts commit b733c2ee519b65c3c4eab0d0e93056412f995f3f.
---
 gnome-session/gsm-session-save.c | 32 ++++++++++++++++++++++++++++----
 gnome-session/gsm-util.c         |  6 ++++++
 2 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/gnome-session/gsm-session-save.c b/gnome-session/gsm-session-save.c
index aeb575f..ceea177 100644
--- a/gnome-session/gsm-session-save.c
+++ b/gnome-session/gsm-session-save.c
@@ -11,61 +11,61 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  * 02111-1307, USA.
  */
 
 #include <config.h>
 
 #include <glib.h>
 #include <glib/gstdio.h>
 #include <gio/gio.h>
 
 #include "gsm-util.h"
 #include "gsm-autostart-app.h"
 #include "gsm-client.h"
 
 #include "gsm-session-save.h"
 
 #define GSM_MANAGER_SCHEMA        "org.gnome.SessionManager"
 #define KEY_AUTOSAVE_ONE_SHOT     "auto-save-session-one-shot"
 
 
 static gboolean gsm_session_clear_saved_session (const char *directory,
                                                  GHashTable *discard_hash);
 
 typedef struct {
-        const char  *dir;
+        char        *dir;
         GHashTable  *discard_hash;
         GError     **error;
 } SessionSaveData;
 
 static gboolean
 save_one_client (char            *id,
                  GObject         *object,
                  SessionSaveData *data)
 {
         GsmClient  *client;
         GKeyFile   *keyfile;
         const char *app_id;
         char       *path = NULL;
         char       *filename = NULL;
         char       *contents = NULL;
         gsize       length = 0;
         char       *discard_exec;
         GError     *local_error;
 
         client = GSM_CLIENT (object);
 
         local_error = NULL;
 
         keyfile = gsm_client_save (client, &local_error);
 
         if (keyfile == NULL || local_error) {
                 goto out;
         }
 
         contents = g_key_file_to_data (keyfile, &length, &local_error);
@@ -114,89 +114,113 @@ save_one_client (char            *id,
         }
 
         g_debug ("GsmSessionSave: saved client %s to %s", id, filename);
 
 out:
         if (keyfile != NULL) {
                 g_key_file_free (keyfile);
         }
 
         g_free (contents);
         g_free (filename);
         g_free (path);
 
         /* in case of any error, stop saving session */
         if (local_error) {
                 g_propagate_error (data->error, local_error);
                 g_error_free (local_error);
 
                 return TRUE;
         }
 
         return FALSE;
 }
 
 void
 gsm_session_save (GsmStore  *client_store,
                   GError   **error)
 {
         GSettings       *settings;
         const char      *save_dir;
+        char            *tmp_dir;
         SessionSaveData  data;
 
         g_debug ("GsmSessionSave: Saving session");
 
         /* Clear one shot key autosave in the event its set (so that it's actually
          * one shot only)
          */
         settings = g_settings_new (GSM_MANAGER_SCHEMA);
         g_settings_set_boolean (settings, KEY_AUTOSAVE_ONE_SHOT, FALSE);
         g_object_unref (settings);
 
         save_dir = gsm_util_get_saved_session_dir ();
         if (save_dir == NULL) {
                 g_warning ("GsmSessionSave: cannot create saved session directory");
                 return;
         }
 
-        data.dir = save_dir;
+        tmp_dir = gsm_util_get_empty_tmp_session_dir ();
+        if (tmp_dir == NULL) {
+                g_warning ("GsmSessionSave: cannot create new saved session directory");
+                return;
+        }
+
+        /* save the session in a temp directory, and remember the discard
+         * commands */
+        data.dir = tmp_dir;
         data.discard_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                    g_free, NULL);
-        /* remove old saved session */
-        gsm_session_clear_saved_session (save_dir, data.discard_hash);
         data.error = error;
 
         gsm_store_foreach (client_store,
                            (GsmStoreFunc) save_one_client,
                            &data);
 
+        if (!*error) {
+                /* remove the old saved session */
+                gsm_session_clear_saved_session (save_dir, data.discard_hash);
+
+                /* rename the temp session dir */
+                if (g_file_test (save_dir, G_FILE_TEST_IS_DIR))
+                        g_rmdir (save_dir);
+                g_rename (tmp_dir, save_dir);
+        } else {
+                g_warning ("GsmSessionSave: error saving session: %s", (*error)->message);
+                /* FIXME: we should create a hash table filled with the discard
+                 * commands that are in desktop files from save_dir. */
+                gsm_session_clear_saved_session (tmp_dir, NULL);
+                g_rmdir (tmp_dir);
+        }
+
         g_hash_table_destroy (data.discard_hash);
+        g_free (tmp_dir);
 }
 
 static gboolean
 gsm_session_clear_one_client (const char *filename,
                               GHashTable *discard_hash)
 {
         gboolean  result = TRUE;
         GKeyFile *key_file = NULL;
         char     *discard_exec = NULL;
 
         g_debug ("GsmSessionSave: removing '%s' from saved session", filename);
 
         key_file = g_key_file_new ();
         if (g_key_file_load_from_file (key_file, filename,
                                        G_KEY_FILE_NONE, NULL)) {
                 char **argv;
                 int    argc;
 
                 discard_exec = g_key_file_get_string (key_file,
                                                       G_KEY_FILE_DESKTOP_GROUP,
                                                       GSM_AUTOSTART_APP_DISCARD_KEY,
                                                       NULL);
                 if (!discard_exec)
                         goto out;
 
                 if (discard_hash && g_hash_table_lookup (discard_hash, discard_exec))
                         goto out;
 
                 if (!g_shell_parse_argv (discard_exec, &argc, &argv, NULL))
                         goto out;
diff --git a/gnome-session/gsm-util.c b/gnome-session/gsm-util.c
index b4036f6..402ac69 100644
--- a/gnome-session/gsm-util.c
+++ b/gnome-session/gsm-util.c
@@ -73,63 +73,69 @@ gsm_util_find_desktop_file_for_app_name (const char *name,
                 g_debug ("GsmUtil: found in XDG dirs: '%s'", app_path);
         }
 
         /* look for gnome vendor prefix */
         if (app_path == NULL) {
                 g_free (desktop_file);
                 desktop_file = g_strdup_printf ("gnome-%s.desktop", name);
 
                 g_key_file_load_from_dirs (key_file,
                                            desktop_file,
                                            (const char **) app_dirs,
                                            &app_path,
                                            G_KEY_FILE_NONE,
                                            NULL);
                 if (app_path != NULL) {
                         g_debug ("GsmUtil: found in XDG dirs: '%s'", app_path);
                 }
         }
 
         g_free (desktop_file);
         g_key_file_free (key_file);
 
         g_strfreev (app_dirs);
 
         return app_path;
 }
 
 static gboolean
 ensure_dir_exists (const char *dir)
 {
+        if (g_file_test (dir, G_FILE_TEST_IS_DIR))
+                return TRUE;
+
         if (g_mkdir_with_parents (dir, 0755) == 0)
                 return TRUE;
 
+        if (errno == EEXIST)
+                return g_file_test (dir, G_FILE_TEST_IS_DIR);
+
         g_warning ("GsmSessionSave: Failed to create directory %s: %s", dir, strerror (errno));
 
         return FALSE;
 }
 
 gchar *
 gsm_util_get_empty_tmp_session_dir (void)
 {
         char *tmp;
         gboolean exists;
 
         tmp = g_build_filename (g_get_user_config_dir (),
                                 "gnome-session",
                                 "saved-session.new",
                                 NULL);
 
         exists = ensure_dir_exists (tmp);
 
         if (G_UNLIKELY (!exists)) {
                 g_warning ("GsmSessionSave: could not create directory for saved session: %s", tmp);
                 g_free (tmp);
                 return NULL;
         } else {
                 /* make sure it's empty */
                 GDir       *dir;
                 const char *filename;
 
                 dir = g_dir_open (tmp, 0, NULL);
                 if (dir) {
                         while ((filename = g_dir_read_name (dir))) {
-- 
1.8.3.1


From ca6ffa85dfc46ba5085ba5e81c3824214abc3ac6 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 20 Dec 2013 11:22:53 -0500
Subject: [PATCH 07/14] Allow saved-session directory to be a symlink

This gives us the option of adding a rudimentary session
chooser later.
---
 gnome-session/gsm-session-save.c | 36 ++++++++++++++++++++++++++++++------
 gnome-session/gsm-util.c         |  6 ------
 2 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/gnome-session/gsm-session-save.c b/gnome-session/gsm-session-save.c
index ceea177..2fe0bb0 100644
--- a/gnome-session/gsm-session-save.c
+++ b/gnome-session/gsm-session-save.c
@@ -150,67 +150,91 @@ gsm_session_save (GsmStore  *client_store,
          * one shot only)
          */
         settings = g_settings_new (GSM_MANAGER_SCHEMA);
         g_settings_set_boolean (settings, KEY_AUTOSAVE_ONE_SHOT, FALSE);
         g_object_unref (settings);
 
         save_dir = gsm_util_get_saved_session_dir ();
         if (save_dir == NULL) {
                 g_warning ("GsmSessionSave: cannot create saved session directory");
                 return;
         }
 
         tmp_dir = gsm_util_get_empty_tmp_session_dir ();
         if (tmp_dir == NULL) {
                 g_warning ("GsmSessionSave: cannot create new saved session directory");
                 return;
         }
 
         /* save the session in a temp directory, and remember the discard
          * commands */
         data.dir = tmp_dir;
         data.discard_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                    g_free, NULL);
         data.error = error;
 
         gsm_store_foreach (client_store,
                            (GsmStoreFunc) save_one_client,
                            &data);
 
         if (!*error) {
-                /* remove the old saved session */
-                gsm_session_clear_saved_session (save_dir, data.discard_hash);
+                char *session_dir;
 
-                /* rename the temp session dir */
-                if (g_file_test (save_dir, G_FILE_TEST_IS_DIR))
-                        g_rmdir (save_dir);
-                g_rename (tmp_dir, save_dir);
+                if (g_file_test (save_dir, G_FILE_TEST_IS_SYMLINK))
+                        session_dir = g_file_read_link (save_dir, error);
+                else
+                        session_dir = g_strdup (save_dir);
+
+                if (session_dir != NULL) {
+
+                        char *absolute_session_dir;
+
+                        if (g_path_is_absolute (session_dir)) {
+                                absolute_session_dir = g_strdup (session_dir);
+                        } else {
+                                char *parent_dir;
+
+                                parent_dir = g_path_get_dirname (save_dir);
+                                absolute_session_dir = g_build_filename (parent_dir, session_dir, NULL);
+                                g_free (parent_dir);
+                        }
+                        g_free (session_dir);
+
+                        /* remove the old saved session */
+                        gsm_session_clear_saved_session (absolute_session_dir, data.discard_hash);
+
+                        if (g_file_test (absolute_session_dir, G_FILE_TEST_IS_DIR))
+                                g_rmdir (absolute_session_dir);
+                        g_rename (tmp_dir, absolute_session_dir);
+
+                        g_free (absolute_session_dir);
+                }
         } else {
                 g_warning ("GsmSessionSave: error saving session: %s", (*error)->message);
                 /* FIXME: we should create a hash table filled with the discard
                  * commands that are in desktop files from save_dir. */
                 gsm_session_clear_saved_session (tmp_dir, NULL);
                 g_rmdir (tmp_dir);
         }
 
         g_hash_table_destroy (data.discard_hash);
         g_free (tmp_dir);
 }
 
 static gboolean
 gsm_session_clear_one_client (const char *filename,
                               GHashTable *discard_hash)
 {
         gboolean  result = TRUE;
         GKeyFile *key_file = NULL;
         char     *discard_exec = NULL;
 
         g_debug ("GsmSessionSave: removing '%s' from saved session", filename);
 
         key_file = g_key_file_new ();
         if (g_key_file_load_from_file (key_file, filename,
                                        G_KEY_FILE_NONE, NULL)) {
                 char **argv;
                 int    argc;
 
                 discard_exec = g_key_file_get_string (key_file,
                                                       G_KEY_FILE_DESKTOP_GROUP,
diff --git a/gnome-session/gsm-util.c b/gnome-session/gsm-util.c
index 402ac69..b4036f6 100644
--- a/gnome-session/gsm-util.c
+++ b/gnome-session/gsm-util.c
@@ -73,69 +73,63 @@ gsm_util_find_desktop_file_for_app_name (const char *name,
                 g_debug ("GsmUtil: found in XDG dirs: '%s'", app_path);
         }
 
         /* look for gnome vendor prefix */
         if (app_path == NULL) {
                 g_free (desktop_file);
                 desktop_file = g_strdup_printf ("gnome-%s.desktop", name);
 
                 g_key_file_load_from_dirs (key_file,
                                            desktop_file,
                                            (const char **) app_dirs,
                                            &app_path,
                                            G_KEY_FILE_NONE,
                                            NULL);
                 if (app_path != NULL) {
                         g_debug ("GsmUtil: found in XDG dirs: '%s'", app_path);
                 }
         }
 
         g_free (desktop_file);
         g_key_file_free (key_file);
 
         g_strfreev (app_dirs);
 
         return app_path;
 }
 
 static gboolean
 ensure_dir_exists (const char *dir)
 {
-        if (g_file_test (dir, G_FILE_TEST_IS_DIR))
-                return TRUE;
-
         if (g_mkdir_with_parents (dir, 0755) == 0)
                 return TRUE;
 
-        if (errno == EEXIST)
-                return g_file_test (dir, G_FILE_TEST_IS_DIR);
-
         g_warning ("GsmSessionSave: Failed to create directory %s: %s", dir, strerror (errno));
 
         return FALSE;
 }
 
 gchar *
 gsm_util_get_empty_tmp_session_dir (void)
 {
         char *tmp;
         gboolean exists;
 
         tmp = g_build_filename (g_get_user_config_dir (),
                                 "gnome-session",
                                 "saved-session.new",
                                 NULL);
 
         exists = ensure_dir_exists (tmp);
 
         if (G_UNLIKELY (!exists)) {
                 g_warning ("GsmSessionSave: could not create directory for saved session: %s", tmp);
                 g_free (tmp);
                 return NULL;
         } else {
                 /* make sure it's empty */
                 GDir       *dir;
                 const char *filename;
 
                 dir = g_dir_open (tmp, 0, NULL);
                 if (dir) {
                         while ((filename = g_dir_read_name (dir))) {
-- 
1.8.3.1


From ce646ac4da600b46dfc5a0605ec0c85f0a3a4f35 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 20 Dec 2013 11:28:53 -0500
Subject: [PATCH 08/14] Tie session selector to properties dialog

---
 capplet/gsm-properties-dialog.c |  30 +++++-
 configure.ac                    |   3 +-
 data/session-selector.ui        |   2 +-
 tools/Makefile.am               |   1 +
 tools/gnome-session-selector.c  | 211 ++++++++++++++++++++++++++++++++--------
 5 files changed, 200 insertions(+), 47 deletions(-)

diff --git a/capplet/gsm-properties-dialog.c b/capplet/gsm-properties-dialog.c
index 4cc453a..cabe96a 100644
--- a/capplet/gsm-properties-dialog.c
+++ b/capplet/gsm-properties-dialog.c
@@ -471,88 +471,114 @@ session_saved_message (GsmPropertiesDialog *dialog,
 {
         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 ("<span foreground=\"red\">%s</span>", 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)
+save_session_directly (GsmPropertiesDialog *dialog)
 {
         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
+save_session_from_selector (GsmPropertiesDialog *dialog,
+                            const char          *program_path)
+{
+        char *command_line = g_strdup_printf ("%s --action save", program_path);
+
+        g_spawn_command_line_sync (command_line, NULL, NULL, NULL, NULL);
+
+        g_free (command_line);
+}
+
+static void
+on_save_session_clicked (GtkWidget           *widget,
+                         GsmPropertiesDialog *dialog)
+{
+        char *program_path;
+
+        program_path = g_find_program_in_path ("gnome-session-selector");
+
+        if (program_path != NULL) {
+                save_session_from_selector (dialog, program_path);
+                g_free (program_path);
+        } else {
+                save_session_directly (dialog);
+        }
+}
+
+static void
 setup_dialog (GsmPropertiesDialog *dialog)
 {
         GtkTreeView       *treeview;
         GtkWidget         *button;
         GtkTreeModel      *tree_filter;
         GtkTreeViewColumn *column;
         GtkCellRenderer   *renderer;
         GtkTreeSelection  *selection;
         GtkTargetList     *targetlist;
 
         gtk_dialog_add_buttons (GTK_DIALOG (dialog),
                                 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
                                 NULL);
 
         dialog->priv->list_store = gtk_list_store_new (NUMBER_OF_COLUMNS,
                                                        G_TYPE_BOOLEAN,
                                                        G_TYPE_BOOLEAN,
                                                        G_TYPE_ICON,
                                                        G_TYPE_STRING,
                                                        G_TYPE_OBJECT,
                                                        G_TYPE_STRING);
         tree_filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (dialog->priv->list_store),
                                                  NULL);
         g_object_unref (dialog->priv->list_store);
         dialog->priv->tree_filter = tree_filter;
 
         gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (tree_filter),
                                                   STORE_COL_VISIBLE);
 
         treeview = GTK_TREE_VIEW (gtk_builder_get_object (dialog->priv->xml,
diff --git a/configure.ac b/configure.ac
index b71c979..a61d88e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -21,86 +21,85 @@ LT_PREREQ([2.2.6])
 LT_INIT([dlopen disable-static])
 
 GNOME_MAINTAINER_MODE_DEFINES
 GNOME_COMPILE_WARNINGS([maximum])
 
 AC_ARG_ENABLE(deprecation_flags,
               [AS_HELP_STRING([--enable-deprecation-flags],
                               [use *_DISABLE_DEPRECATED flags @<:@default=no@:>@])],,
               [enable_deprecation_flags=no])
 
 if test "x$enable_deprecation_flags" = "xyes"; then
    DISABLE_DEPRECATED_CFLAGS=$DISABLE_DEPRECATED
    AC_SUBST([DISABLE_DEPRECATED_CFLAGS])
 fi
 
 GLIB_REQUIRED=2.35.0
 GTK3_REQUIRED=2.90.7
 DBUS_GLIB_REQUIRED=0.76
 UPOWER_REQUIRED=0.9.0
 JSON_GLIB_REQUIRED=0.10
 GNOME_DESKTOP_REQUIRED=3.7.90
 
 AC_ARG_ENABLE(session-selector, AS_HELP_STRING([--enable-session-selector],
                                                [enable building a custom session selector dialog]),
                                                 enable_session_selector=$enableval,enable_session_selector=no)
 
 AM_CONDITIONAL(BUILD_SESSION_SELECTOR,
                [test "$enable_session_selector" = yes])
 
 if test "$enable_session_selector" = yes; then
-        PKG_CHECK_MODULES(SESSION_SELECTOR, gtk+-3.0 gio-2.0)
+        PKG_CHECK_MODULES(SESSION_SELECTOR, gtk+-3.0 gio-2.0 dbus-glib-1 >= $DBUS_GLIB_REQUIRED)
 fi
 
 dnl ====================================================================
 dnl Dependency Checks
 dnl ====================================================================
 
 dnl Standard vertical stacks
 PKG_CHECK_MODULES(GIO, gio-2.0)
 PKG_CHECK_MODULES(GIOUNIX, gio-unix-2.0 >= $GLIB_REQUIRED)
 PKG_CHECK_MODULES(GTK3, gtk+-3.0 >= $GTK3_REQUIRED)
 
 PKG_CHECK_MODULES(GNOME_SESSION,
         glib-2.0 >= $GLIB_REQUIRED
         gio-2.0 >= $GLIB_REQUIRED
         gtk+-3.0 >= $GTK3_REQUIRED
         dbus-glib-1 >= $DBUS_GLIB_REQUIRED
         upower-glib >= $UPOWER_REQUIRED
         json-glib-1.0 >= $JSON_GLIB_REQUIRED
         gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED
 )
 
 PKG_CHECK_MODULES(SESSION_PROPERTIES,
         glib-2.0 >= $GLIB_REQUIRED
         gtk+-3.0 >= $GTK3_REQUIRED
-        dbus-glib-1 >= $DBUS_GLIB_REQUIRED
 )
 
 PKG_CHECK_MODULES(X11, x11)
 PKG_CHECK_MODULES(SM, sm)
 PKG_CHECK_MODULES(ICE, ice)
 PKG_CHECK_MODULES(XEXT, xext xau)
 
 PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1 >= $DBUS_GLIB_REQUIRED)
 
 PKG_CHECK_MODULES(EGG_SMCLIENT, gtk+-3.0)
 
 PKG_CHECK_MODULES(GL_TEST, xcomposite gl glib-2.0)
 
 dnl ====================================================================
 dnl Check for gconf
 dnl ====================================================================
 AC_ARG_ENABLE([gconf],
               AS_HELP_STRING([--enable-gconf], [Support gconf-based autostart]),
               [enable_gconf=$enableval],
               [enable_gconf=auto])
 
 PKG_CHECK_MODULES(GCONF, gconf-2.0, [have_gconf=yes], [have_gconf=no])
 
 if test x$enable_gconf = xauto ; then
         enable_gconf=$have_gconf
 elif test x$enable_gconf = xyes -a x$have_gconf = xno ; then
         AC_MSG_ERROR([GConf support explicitly required, but gconf not found])
 fi
 
 if test x$enable_gconf = xyes ; then
diff --git a/data/session-selector.ui b/data/session-selector.ui
index 1c55712..1534a74 100644
--- a/data/session-selector.ui
+++ b/data/session-selector.ui
@@ -20,61 +20,61 @@
     <child>
       <object class="GtkFrame" id="frame1">
         <property name="visible">True</property>
         <property name="label_xalign">0.5</property>
         <property name="shadow_type">out</property>
         <child>
           <object class="GtkAlignment" id="alignment3">
             <property name="visible">True</property>
             <property name="border_width">12</property>
             <child>
               <object class="GtkVBox" id="vbox3">
                 <property name="visible">True</property>
                 <property name="orientation">vertical</property>
                 <property name="spacing">6</property>
 
                 <child>
                   <object class="GtkInfoBar" id="info-bar">
                     <property name="visible">True</property>
                     <property name="message-type">other</property>
 
                     <child internal-child="content_area">
                       <object class="GtkHBox" id="info-bar-content_area">
                         <property name="visible">True</property>
                         <property name="orientation">vertical</property>
                         <property name="spacing">0</property>
                         <child>
                           <object class="GtkLabel" id="info-label">
                             <property name="visible">True</property>
                             <property name="xalign">0.0</property>
                             <property name="yalign">0.5</property>
-                            <property name="label" translatable="yes">Please select a custom session to run</property>
+                            <property name="label" translatable="yes">Please select a custom session to use</property>
                           </object>
                           <packing>
                             <property name="expand">True</property>
                             <property name="fill">True</property>
                             <property name="position">0</property>
                           </packing>
                         </child>
                       </object>
                     </child>
                   </object>
                   <packing>
                     <property name="expand">False</property>
                     <property name="fill">True</property>
                     <property name="position">0</property>
                   </packing>
                 </child>
                 <child>
                   <object class="GtkVBox" id="vbox4">
                     <property name="visible">True</property>
                     <property name="orientation">vertical</property>
                     <property name="spacing">12</property>
                     <child>
                       <object class="GtkHBox" id="hbox3">
                         <property name="visible">True</property>
                         <property name="spacing">12</property>
                         <child>
                           <object class="GtkScrolledWindow" id="scrolledwindow2">
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
                             <property name="hscrollbar_policy">never</property>
diff --git a/tools/Makefile.am b/tools/Makefile.am
index ba8a6e8..2685609 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -47,37 +47,38 @@ gnome_session_check_accelerated_helper_SOURCES = 		\
 gnome_session_check_accelerated_helper_CPPFLAGS =	\
 	-DPKGDATADIR=\""$(pkgdatadir)"\"		\
 	$(GL_TEST_CFLAGS)
 
 gnome_session_check_accelerated_helper_LDADD = 		\
 	$(GL_TEST_LIBS)				\
 	$(X11_LIBS)
 
 gnome_session_check_accelerated_SOURCES =       \
 	gnome-session-check-accelerated.c
 
 gnome_session_check_accelerated_CPPFLAGS =      \
 	-DLIBEXECDIR=\""$(libexecdir)"\"	\
 	$(AM_CPPFLAGS)			        \
 	$(GTK3_CFLAGS)
 
 gnome_session_check_accelerated_LDADD =         \
 	$(GTK3_LIBS)				\
 	$(X11_LIBS)
 
 if BUILD_SESSION_SELECTOR
 gnome_session_selector_CPPFLAGS =		\
 	$(AM_CPPFLAGS)				\
 	$(GNOME_SESSION_CFLAGS)			\
 	$(DBUS_GLIB_CFLAGS)			\
 	-DGTKBUILDER_DIR=\""$(pkgdatadir)"\"	\
 	-DLOCALE_DIR=\""$(datadir)/locale"\"	\
 	$(DISABLE_DEPRECATED_CFLAGS)
 
 gnome_session_selector_LDADD = 			\
+	$(DBUS_GLIB_CFLAGS)			\
 	$(SESSION_SELECTOR_LIBS)
 
 gnome_session_selector_SOURCES = 		\
 	gnome-session-selector.c
 endif
 
 -include $(top_srcdir)/git.mk
diff --git a/tools/gnome-session-selector.c b/tools/gnome-session-selector.c
index dad88b4..54541d3 100644
--- a/tools/gnome-session-selector.c
+++ b/tools/gnome-session-selector.c
@@ -8,126 +8,133 @@
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
  * Written by: Matthias Clasen <mclasen@redhat.com>
  */
 
 #include "config.h"
 
 #include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
 #include <glib.h>
 #include <gtk/gtk.h>
 #include <gio/gio.h>
 
 #include <glib/gi18n.h>
 #include <glib/gstdio.h>
 
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#define GSM_SERVICE_DBUS   "org.gnome.SessionManager"
+#define GSM_PATH_DBUS      "/org/gnome/SessionManager"
+#define GSM_INTERFACE_DBUS "org.gnome.SessionManager"
+
 #define GSM_MANAGER_SCHEMA        "org.gnome.SessionManager"
 #define KEY_AUTOSAVE_ONE_SHOT     "auto-save-session-one-shot"
 
 static GtkBuilder *builder;
 static GtkWidget *session_list;
 static GtkListStore *store;
 static GtkTreeModelSort *sort_model;
+static char *info_text;
 
 static void select_session (const char *name);
+static gboolean make_session_current (const char *name);
 
 static char *
 get_session_path (const char *name)
 {
         return g_build_filename (g_get_user_config_dir (), "gnome-session", name, NULL);
 }
 
 static char *
 find_new_session_name (void)
 {
         char *name;
         char *path;
         int i;
 
         for (i = 1; i < 20; i++) {
                 name = g_strdup_printf (_("Session %d"), i);
                 path = get_session_path (name);
                 if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
                         g_free (path);
                         return name;
                 }
                 g_free (path);
                 g_free (name);
         }
 
         return NULL;
 }
 
 static gboolean
 is_valid_session_name (const char *name)
 {
         GtkTreeIter iter;
         char *n;
-        const char *info_text;
         char *warning_text;
         gboolean user_tried_dot;
         gboolean user_tried_slash;
         GtkWidget *info_bar;
         GtkWidget *label;
 
         if (name[0] == 0) {
                 return FALSE;
         }
 
         if (name[0] == '.') {
             user_tried_dot = TRUE;
         } else {
             user_tried_dot = FALSE;
         }
 
         if (strchr (name, '/') != NULL) {
             user_tried_slash = TRUE;
         } else {
             user_tried_slash = FALSE;
         }
 
-        info_text = _("Please select a custom session to run");
         warning_text = NULL;
         if (user_tried_dot && user_tried_slash) {
             warning_text = g_strdup_printf ("%s\n<small><b>Note:</b> <i>%s</i></small>",
                                             info_text,
                                             _("Session names are not allowed to start with ‘.’ or contain ‘/’ characters"));
         } else if (user_tried_dot) {
             warning_text = g_strdup_printf ("%s\n<small><b>Note:</b> <i>%s</i></small>",
                                             info_text,
                                             _("Session names are not allowed to start with ‘.’"));
         } else if (user_tried_slash) {
             warning_text = g_strdup_printf ("%s\n<small><b>Note:</b> <i>%s</i></small>",
                                             info_text,
                                             _("Session names are not allowed to contain ‘/’ characters"));
         }
 
         gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
         do {
                 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, 0, &n, -1);
                 if (strcmp (n, name) == 0) {
                         char *message;
                         message = g_strdup_printf (_("A session named ‘%s’ already exists"), name);
                         warning_text = g_strdup_printf ("%s\n<small><b>Note:</b> <i>%s</i></small>", info_text, message);
                         g_free (message);
                         g_free (n);
                         break;
                 }
                 g_free (n);
         } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
 
         info_bar = (GtkWidget *) gtk_builder_get_object (builder, "info-bar");
@@ -183,517 +190,637 @@ populate_session_list (GtkWidget *session_list)
         default_name = NULL;
         if (readlink (saved_session, last_session, PATH_MAX - 1) > 0) {
                 default_name = g_path_get_basename (last_session);
         }
 
         while ((name = g_dir_read_name (dir)) != NULL) {
                 if (strcmp (name, "saved-session") == 0)
                         continue;
 
                 gtk_list_store_insert_with_values (store, &iter, 100, 0, name, -1);
 
                 if (g_strcmp0 (default_name, name) == 0) {
                         GtkTreeSelection *selection;
                         GtkTreeIter child_iter;
 
                         gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &child_iter, &iter);
                         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (session_list));
                         gtk_tree_selection_select_iter (selection, &child_iter);
                 }
         }
 
         g_free (default_name);
         g_dir_close (dir);
 
  out:
         g_free (saved_session);
         g_free (path);
 }
 
 static char *
+get_last_session (void)
+{
+        char *saved_session;
+        char last_session[PATH_MAX] = "";
+        char *name = NULL;
+
+        saved_session = get_session_path ("saved-session");
+
+        if (readlink (saved_session, last_session, PATH_MAX - 1) > 0) {
+                name = g_path_get_basename (last_session);
+        }
+
+        g_free (saved_session);
+
+        return name;
+}
+
+static char *
 get_selected_session (void)
 {
         GtkTreeSelection *selection;
         GtkTreeModel *model;
         GtkTreeIter iter;
         gchar *name;
 
         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (session_list));
         if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
                 gtk_tree_model_get (model, &iter, 0, &name, -1);
                 return name;
         }
 
         return NULL;
 }
 
 static void
 remove_session (const char *name)
 {
         char *path1, *path2;
         char *n, *path;
         const char *d;
         GDir *dir;
         GError *error;
 
         path1 = get_session_path ("saved-session");
         path2 = get_session_path (name);
 
         error = NULL;
         n = g_file_read_link (path1, &error);
         if (n == NULL) {
                 g_warning ("Failed to read link: %s", error->message);
                 g_error_free (error);
         }
         else if (strcmp (n, name) == 0) {
                 unlink (path1);
         }
         g_free (n);
 
         dir = g_dir_open (path2, 0, NULL);
         while ((d = g_dir_read_name (dir)) != NULL) {
                 path = g_build_filename (path2, d, NULL);
                 unlink (path);
                 g_free (path);
         }
         g_dir_close (dir);
 
         remove (path2);
 
         g_free (path1);
         g_free (path2);
 }
 
+static gboolean
+make_session_current (const char *name)
+{
+        char *path1;
+        gboolean ret = TRUE;
+
+        path1 = g_build_filename (g_get_user_config_dir (), "gnome-session", "saved-session", NULL);
+
+        unlink (path1);
+        if (symlink (name, path1) < 0) {
+                g_warning ("Failed to make session '%s' current", name);
+                ret = FALSE;
+        }
+
+        g_free (path1);
+
+        return ret;
+}
+
 static void
 on_remove_session_clicked (GtkButton *button,
                            gpointer   data)
 {
         GtkTreeSelection *selection;
         GtkTreeModel *model;
         GtkTreeIter iter;
         char *name;
 
         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (session_list));
         if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
                 GtkTreeIter child_iter;
                 gtk_tree_model_get (model, &iter, 0, &name, -1);
                 remove_session (name);
                 g_free (name);
 
                 gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (model), &child_iter, &iter);
                 gtk_list_store_remove (GTK_LIST_STORE (store), &child_iter);
 
                 if (!gtk_tree_selection_get_selected (selection, NULL, NULL)) {
                         gtk_tree_model_get_iter_first (model, &iter);
                         gtk_tree_model_get (model, &iter, 0, &name, -1);
                         select_session (name);
+                        make_session_current (name);
                         g_free (name);
                 }
         }
 }
 
 static void
 begin_rename (void)
 {
         GtkTreePath *path;
         GtkTreeViewColumn *column;
         GList *cells;
 
         gtk_widget_grab_focus (session_list);
 
         gtk_tree_view_get_cursor (GTK_TREE_VIEW (session_list),
                                   &path, &column);
 
         cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
 
         if (cells != NULL) {
             GtkCellRenderer *cell;
 
             cell = (GtkCellRenderer *) cells->data;
             g_list_free (cells);
 
             g_object_set (cell, "editable", TRUE, NULL);
             gtk_tree_view_set_cursor_on_cell (GTK_TREE_VIEW (session_list), path,
                                               column, cell, TRUE);
         }
         gtk_tree_path_free (path);
 }
 
 static void
 on_rename_session_clicked (GtkButton *button,
                            gpointer   data)
 {
     begin_rename ();
 }
 
 static void
 on_continue_clicked (GtkButton *button,
                      gpointer    data)
 {
         char *name;
 
         name = get_selected_session ();
         g_free (name);
 
         gtk_main_quit ();
 }
 
 static void
 create_session (const char *name)
 {
         char *path;
         GtkTreeIter iter;
 
         path = get_session_path (name);
 
-        if (mkdir (path, 0755) < 0) {
+        if (g_mkdir_with_parents (path, 0755) < 0) {
                 g_warning ("Failed to create directory %s", path);
         }
         else {
                 char *marker;
 
                 gtk_list_store_insert_with_values (store, &iter, 100, 0, name, -1);
 
                 marker = g_build_filename (path, ".new-session", NULL);
                 creat (marker, 0600);
                 g_free (marker);
         }
 
         g_free (path);
 }
 
 static gboolean
 rename_session (const char *old_name,
                 const char *new_name)
 {
         char *old_path, *new_path;
         int result;
 
         if (g_strcmp0 (old_name, new_name) == 0) {
                 return TRUE;
         }
 
         if (!is_valid_session_name (new_name)) {
                return FALSE;
         }
 
         old_path = get_session_path (old_name);
         new_path = get_session_path (new_name);
 
         result = g_rename (old_path, new_path);
 
         if (result < 0) {
                 g_warning ("Failed to rename session from '%s' to '%s': %m", old_name, new_name);
+        } else {
+                char *last_session;
+                last_session = get_last_session ();
+                if (g_strcmp0 (old_name, last_session) == 0) {
+                        make_session_current (new_name);
+                }
+                g_free (last_session);
         }
 
         g_free (old_path);
         g_free (new_path);
-
         return result == 0;
 }
 
 static gboolean
-make_session_current (const char *name)
-{
-        char *path1;
-        gboolean ret = TRUE;
-
-        path1 = g_build_filename (g_get_user_config_dir (), "gnome-session", "saved-session", NULL);
-
-        unlink (path1);
-        if (symlink (name, path1) < 0) {
-                g_warning ("Failed to make session '%s' current", name);
-                ret = FALSE;
-        }
-
-        g_free (path1);
-
-        return ret;
-}
-
-static gboolean
 create_and_select_session (const char *name)
 {
         gchar *path;
 
         if (name[0] == 0 || name[0] == '.' || strchr (name, '/')) {
                 g_warning ("Invalid session name");
                 return FALSE;
         }
 
         path = g_build_filename (g_get_user_config_dir (), "gnome-session", name, NULL);
         if (!g_file_test (path, G_FILE_TEST_IS_DIR)) {
-                if (mkdir (path, 0755) < 0) {
+                if (g_mkdir_with_parents (path, 0755) < 0) {
                         g_warning ("Failed to create directory %s", path);
                         g_free (path);
                         return FALSE;
                 }
         }
 
         g_free (path);
 
         return make_session_current (name);
 }
 
 static void
 select_session (const char *name)
 {
         GtkTreeIter iter;
         char *n;
 
-        make_session_current (name);
-
         /* now select it in the list */
         gtk_tree_model_get_iter_first (GTK_TREE_MODEL (sort_model), &iter);
         do {
                 gtk_tree_model_get (GTK_TREE_MODEL (sort_model), &iter, 0, &n, -1);
                 if (strcmp (n, name) == 0) {
                         GtkTreePath *path;
 
                         path = gtk_tree_model_get_path (GTK_TREE_MODEL (sort_model), &iter);
                         gtk_tree_view_set_cursor (GTK_TREE_VIEW (session_list), path, NULL, FALSE);
                         gtk_tree_path_free (path);
                         g_free (n);
                         break;
                 }
                 g_free (n);
         } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (sort_model), &iter));
 }
 
 static void
-on_new_session_clicked (GtkButton *button,
-                        gpointer   data)
+create_session_and_begin_rename (void)
 {
         gchar *name;
 
         name = find_new_session_name ();
         create_session (name);
         select_session (name);
 
         begin_rename ();
 }
 
 static void
+on_new_session_clicked (GtkButton *button,
+                        gpointer   data)
+{
+	create_session_and_begin_rename ();
+}
+
+static void
 on_selection_changed (GtkTreeSelection *selection,
                       gpointer          data)
 {
         char *name;
 
         name = get_selected_session ();
 
         if (name == NULL) {
                 return;
         }
 
-        make_session_current (name);
-
         g_free (name);
 }
 
 static void
 update_remove_button (void)
 {
         GtkWidget *button;
 
         button = (GtkWidget *)gtk_builder_get_object (builder, "remove-session");
         if (gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL) > 1) {
                 gtk_widget_set_sensitive (button, TRUE);
         } else {
                 gtk_widget_set_sensitive (button, FALSE);
         }
 }
 
 static void
 on_row_edited (GtkCellRendererText *cell,
                const char          *path_string,
                const char          *new_name,
                gpointer             data)
 {
         GtkTreePath *path;
         GtkTreeIter  sort_iter, items_iter;
         char        *old_name;
         gboolean     was_renamed;
 
         path = gtk_tree_path_new_from_string (path_string);
         gtk_tree_model_get_iter (GTK_TREE_MODEL (sort_model), &sort_iter, path);
 
         gtk_tree_model_get (GTK_TREE_MODEL (sort_model), &sort_iter, 0, &old_name, -1);
 
         was_renamed = rename_session (old_name, new_name);
 
         if (was_renamed) {
                 gtk_tree_model_sort_convert_iter_to_child_iter (sort_model, &items_iter, &sort_iter);
 
                 gtk_list_store_set (store, &items_iter, 0, g_strdup (new_name), -1);
                 g_free (old_name);
-                make_session_current (new_name);
         } else {
                 begin_rename ();
         }
 
         gtk_tree_path_free (path);
 
         g_object_set (cell, "editable", FALSE, NULL);
 }
 
 static void
 on_row_deleted (GtkTreeModel *model,
                 GtkTreePath  *path,
                 gpointer      data)
 {
         update_remove_button ();
 }
 
 static void
 on_row_inserted (GtkTreeModel *model,
                  GtkTreePath  *path,
                  GtkTreeIter  *iter,
                  gpointer      data)
 {
         update_remove_button ();
 }
 
 static void
 on_row_activated (GtkTreeView       *tree_view,
                   GtkTreePath       *path,
                   GtkTreeViewColumn *column,
                   gpointer           data)
 {
-        char *name;
-
-        name = get_selected_session ();
-        g_free (name);
-
         gtk_main_quit ();
 }
 
 static void
 auto_save_next_session (void)
 {
         GSettings *settings;
 
         settings = g_settings_new (GSM_MANAGER_SCHEMA);
         g_settings_set_boolean (settings, KEY_AUTOSAVE_ONE_SHOT, TRUE);
         g_object_unref (settings);
 }
 
 static void
 auto_save_next_session_if_needed (void)
 {
         char *marker;
 
         marker = g_build_filename (g_get_user_config_dir (),
                                    "gnome-session", "saved-session",
                                    ".new-session", NULL);
 
         if (g_file_test (marker, G_FILE_TEST_EXISTS)) {
                 auto_save_next_session ();
                 unlink (marker);
         }
         g_free (marker);
 }
 
+static void
+save_session (void)
+{
+        DBusGConnection *conn;
+        DBusGProxy *proxy;
+        GError *error;
+
+        conn = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
+        if (conn == NULL) {
+                g_warning ("Could not connect to the session bus");
+                return;
+        }
+
+        proxy = dbus_g_proxy_new_for_name (conn, GSM_SERVICE_DBUS, GSM_PATH_DBUS, GSM_INTERFACE_DBUS);
+        if (proxy == NULL) {
+                g_warning ("Could not connect to the session manager");
+                return;
+        }
+
+        error = NULL;
+        if (!dbus_g_proxy_call (proxy, "SaveSession", &error, G_TYPE_INVALID, G_TYPE_INVALID)) {
+                g_warning ("Failed to save session: %s", error->message);
+                g_error_free (error);
+                return;
+        }
+
+        g_object_unref (proxy);
+}
+
 static int
 compare_sessions (GtkTreeModel *model,
                   GtkTreeIter  *a,
                   GtkTreeIter  *b,
                   gpointer      data)
 {
     char *name_a, *name_b;
     int result;
 
     gtk_tree_model_get (model, a, 0, &name_a, -1);
     gtk_tree_model_get (model, b, 0, &name_b, -1);
 
     result = g_utf8_collate (name_a, name_b);
 
     g_free (name_a);
     g_free (name_b);
 
     return result;
 }
 
 static void
 on_map (GtkWidget *widget,
         gpointer   data)
 {
         gdk_window_focus (gtk_widget_get_window (widget), GDK_CURRENT_TIME);
 }
 
 int
 main (int argc, char *argv[])
 {
         GtkWidget *window;
         GtkWidget *widget;
+        GtkWidget *label;
         GtkCellRenderer *cell;
         GtkTreeViewColumn *column;
         GtkTreeSelection *selection;
         GError *error;
+        char *selected_session;
+
+        static char *action = NULL;
+        static char **remaining_args = NULL;
+        static GOptionEntry entries[] = {
+                {"action", '\0', 0, G_OPTION_ARG_STRING, &action, N_("What to do with session selection (save|load|print)"), NULL},
+{ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &remaining_args, N_("[session-name]"), NULL}
+        };
+
+        if (action == NULL) {
+            if (getenv ("SESSION_MANAGER") != NULL)
+                action = "print";
+            else
+                action = "load";
+        }
 
-        if (getenv ("SESSION_MANAGER") != NULL)
+        if (getenv ("SESSION_MANAGER") != NULL && strcmp (action, "load") == 0) {
+            g_warning ("Cannot load new session when session currently loaded");
             return 1;
+        }
+
+        if (getenv ("SESSION_MANAGER") == NULL && strcmp (action, "save") == 0) {
+            g_warning ("Can only save session when session loaded");
+            return 1;
+        }
+
+        if (strcmp (action, "load") != 0 && strcmp (action, "save") != 0 && strcmp (action, "print") != 0) {
+            g_warning ("'%s' is not a supported action.  Supported actions are load, save, and print.\n", action);
+            return 1;
+        }
 
-        gtk_init (&argc, &argv);
-        if (argc > 1) {
-                g_print ("create and select session\n");
-                if (!create_and_select_session (argv[1]))
+        error = NULL;
+        gtk_init_with_args (&argc, &argv,
+                            NULL, entries, GETTEXT_PACKAGE, &error);
+
+        if (remaining_args != NULL) {
+                if (g_strv_length (remaining_args) > 1) {
+                        g_warning ("gnome-session-selector takes at most one session argument");
+                        return 1;
+                }
+
+                if (!create_and_select_session (remaining_args[0]))
                         return 1;
                 else
                         return 0;
         }
 
         builder = gtk_builder_new ();
         gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE);
 
         error = NULL;
         if (!gtk_builder_add_from_file (builder, GTKBUILDER_DIR "/" "session-selector.ui",  &error)) {
                 g_warning ("Could not load file 'session-selector.ui': %s", error->message);
                 exit (1);
         }
 
         window = (GtkWidget *) gtk_builder_get_object (builder, "main-window");
 
         store = (GtkListStore *) gtk_builder_get_object (builder, "session-store");
         sort_model = (GtkTreeModelSort *) gtk_builder_get_object (builder, "sort-model");
 
         gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sort_model),
                                          0, compare_sessions, NULL, NULL);
         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
                                               0, GTK_SORT_ASCENDING);
         g_signal_connect (store, "row-deleted", G_CALLBACK (on_row_deleted), NULL);
         g_signal_connect (store, "row-inserted", G_CALLBACK (on_row_inserted), NULL);
         session_list = (GtkWidget *) gtk_builder_get_object (builder, "session-list");
 
         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (session_list));
         gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
 
         populate_session_list (session_list);
 
         cell = gtk_cell_renderer_text_new ();
         g_signal_connect (cell, "edited", G_CALLBACK (on_row_edited), NULL);
 
         column = gtk_tree_view_column_new_with_attributes ("", cell, "text", 0, NULL);
         gtk_tree_view_append_column (GTK_TREE_VIEW (session_list), GTK_TREE_VIEW_COLUMN (column));
 
         g_signal_connect (session_list, "row-activated", G_CALLBACK (on_row_activated), NULL);
 
         g_signal_connect (selection, "changed",
                           G_CALLBACK (on_selection_changed), NULL);
 
         widget = (GtkWidget *) gtk_builder_get_object (builder, "new-session");
         g_signal_connect (widget, "clicked", G_CALLBACK (on_new_session_clicked), NULL);
         widget = (GtkWidget *) gtk_builder_get_object (builder, "remove-session");
         g_signal_connect (widget, "clicked", G_CALLBACK (on_remove_session_clicked), NULL);
         widget = (GtkWidget *) gtk_builder_get_object (builder, "rename-session");
         g_signal_connect (widget, "clicked", G_CALLBACK (on_rename_session_clicked), NULL);
         widget = (GtkWidget *) gtk_builder_get_object (builder, "continue-button");
         g_signal_connect (widget, "clicked", G_CALLBACK (on_continue_clicked), NULL);
 
         g_signal_connect (window, "map", G_CALLBACK (on_map), NULL);
         gtk_widget_show (window);
 
+        if (g_strcmp0 (action, "load") == 0) {
+            info_text = _("Please select a custom session to run");
+        } else if (g_strcmp0 (action, "print") == 0) {
+            info_text = _("Please select a session to use");
+        } else if (g_strcmp0 (action, "save") == 0) {
+            info_text = _("Please select a session to save to");
+        }
+
+        label = (GtkWidget*) gtk_builder_get_object (builder, "info-label");
+        gtk_label_set_markup (GTK_LABEL (label), info_text);
+
+        selected_session = get_selected_session ();
+
+        if (selected_session == NULL) {
+		create_session_and_begin_rename ();
+	} else {
+		g_free (selected_session);
+        }
+
         gtk_main ();
 
-        auto_save_next_session_if_needed ();
+        selected_session = get_selected_session ();
+
+        if (g_strcmp0 (action, "load") == 0) {
+                make_session_current (selected_session);
+                auto_save_next_session_if_needed ();
+        } else if (g_strcmp0 (action, "save") == 0) {
+                char *last_session;
+
+                last_session = get_last_session ();
+                make_session_current (selected_session);
+                save_session ();
+                if (last_session != NULL)
+                    make_session_current (last_session);
+        } else if (g_strcmp0 (action, "print") == 0) {
+                g_print ("%s\n", selected_session);
+        }
+        g_free (selected_session);
 
         return 0;
 }
-- 
1.8.3.1


From da7acee836dc0c06079811f445d9054cf9f7ab73 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 20 Dec 2013 11:32:52 -0500
Subject: [PATCH 09/14] 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 e2a493f..30b31f9 100644
--- a/gnome-session/gsm-manager.c
+++ b/gnome-session/gsm-manager.c
@@ -121,60 +121,61 @@ typedef enum
         GSM_MANAGER_LOGOUT_SHUTDOWN,
         GSM_MANAGER_LOGOUT_SHUTDOWN_INTERACT,
         GSM_MANAGER_LOGOUT_SHUTDOWN_GDM
 } 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;
 
         GtkWidget              *inhibit_dialog;
 
         /* List of clients which were disconnected due to disabled condition
          * and shouldn't be automatically restarted */
         GSList                 *condition_clients;
 
         GSettings              *settings;
         GSettings              *session_settings;
         GSettings              *screensaver_settings;
         GSettings              *lockdown_settings;
 
         GsmSystem              *system;
         DBusGProxy             *bus_proxy;
         DBusGConnection        *connection;
         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,
         PROP_CLIENT_STORE,
@@ -1369,90 +1370,124 @@ 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;
 
@@ -3617,92 +3652,101 @@ gsm_manager_reboot (GsmManager  *manager,
         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,
                              "Reboot interface is only available during the Running phase");
                 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;
         }
 
         shell_running = gsm_shell_is_running (manager->priv->shell);
 
         if (!shell_running)
                 show_fallback_shutdown_dialog (manager, TRUE);
         else
                 request_reboot (manager);
 
         return TRUE;
 }
 
 
 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_can_shutdown (GsmManager *manager,
                           gboolean   *shutdown_available,
                           GError    **error)
 {
         g_debug ("GsmManager: CanShutdown called");
 
         g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
 
         *shutdown_available = !_log_out_is_locked_down (manager) &&
                               (gsm_system_can_stop (manager->priv->system)
                                || gsm_system_can_restart (manager->priv->system)
                                || gsm_system_can_suspend (manager->priv->system)
                                || gsm_system_can_hibernate (manager->priv->system));
 
         return TRUE;
 }
 
 gboolean
 gsm_manager_logout (GsmManager *manager,
                     guint       logout_mode,
                     GError    **error)
 {
         g_debug ("GsmManager: Logout called");
 
         g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
 
         if (manager->priv->phase != GSM_MANAGER_PHASE_RUNNING) {
diff --git a/gnome-session/gsm-manager.h b/gnome-session/gsm-manager.h
index 9dbc814..ca29b65 100644
--- a/gnome-session/gsm-manager.h
+++ b/gnome-session/gsm-manager.h
@@ -135,61 +135,61 @@ void                _gsm_manager_set_active_session            (GsmManager     *
 /* exported methods */
 
 gboolean            gsm_manager_register_client                (GsmManager            *manager,
                                                                 const char            *app_id,
                                                                 const char            *client_startup_id,
                                                                 DBusGMethodInvocation *context);
 gboolean            gsm_manager_unregister_client              (GsmManager            *manager,
                                                                 const char            *session_client_id,
                                                                 DBusGMethodInvocation *context);
 
 gboolean            gsm_manager_inhibit                        (GsmManager            *manager,
                                                                 const char            *app_id,
                                                                 guint                  toplevel_xid,
                                                                 const char            *reason,
                                                                 guint                  flags,
                                                                 DBusGMethodInvocation *context);
 gboolean            gsm_manager_uninhibit                      (GsmManager            *manager,
                                                                 guint                  inhibit_cookie,
                                                                 DBusGMethodInvocation *context);
 gboolean            gsm_manager_is_inhibited                   (GsmManager            *manager,
                                                                 guint                  flags,
                                                                 gboolean              *is_inhibited,
                                                                 GError                *error);
 
 gboolean            gsm_manager_shutdown                       (GsmManager     *manager,
                                                                 GError        **error);
 gboolean            gsm_manager_reboot                         (GsmManager     *manager,
                                                                 GError        **error);
 
 gboolean            gsm_manager_save_session                   (GsmManager     *manager,
-                                                                GError        **error);
+								DBusGMethodInvocation *context);
 
 gboolean            gsm_manager_can_shutdown                   (GsmManager     *manager,
                                                                 gboolean       *shutdown_available,
                                                                 GError        **error);
 gboolean            gsm_manager_logout                         (GsmManager     *manager,
                                                                 guint           logout_mode,
                                                                 GError        **error);
 
 gboolean            gsm_manager_setenv                         (GsmManager     *manager,
                                                                 const char     *variable,
                                                                 const char     *value,
                                                                 GError        **error);
 gboolean            gsm_manager_get_locale                     (GsmManager     *manager,
                                                                 int             category,
                                                                 const char    **value,
                                                                 GError        **error);
 gboolean            gsm_manager_initialization_error           (GsmManager     *manager,
                                                                 const char     *message,
                                                                 gboolean        fatal,
                                                                 GError        **error);
 
 gboolean            gsm_manager_get_clients                    (GsmManager     *manager,
                                                                 GPtrArray     **clients,
                                                                 GError        **error);
 gboolean            gsm_manager_get_inhibitors                 (GsmManager     *manager,
                                                                 GPtrArray     **inhibitors,
                                                                 GError        **error);
 gboolean            gsm_manager_is_autostart_condition_handled (GsmManager     *manager,
                                                                 const char     *condition,
                                                                 gboolean       *handled,
diff --git a/gnome-session/org.gnome.SessionManager.xml b/gnome-session/org.gnome.SessionManager.xml
index 873e250..d9fb216 100644
--- a/gnome-session/org.gnome.SessionManager.xml
+++ b/gnome-session/org.gnome.SessionManager.xml
@@ -260,60 +260,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>
-- 
1.8.3.1


From e41b19c1d28b672f0c9d166d52b4e7028b92c451 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 20 Dec 2013 15:32:04 -0500
Subject: [PATCH 10/14] manager: save session type in session dir

If a user saved their session when in classic mode, make sure we
record that information so subsequent calls to gnome-session will
restore classic mode.
---
 gnome-session/gsm-manager.c      | 21 ++++++++++++++++++--
 gnome-session/gsm-manager.h      |  1 +
 gnome-session/gsm-session-save.c | 41 +++++++++++++++++++++++++++++++++++++---
 gnome-session/gsm-session-save.h |  5 +++--
 gnome-session/main.c             | 14 +++++++++++---
 5 files changed, 72 insertions(+), 10 deletions(-)

diff --git a/gnome-session/gsm-manager.c b/gnome-session/gsm-manager.c
index 30b31f9..f6ccb62 100644
--- a/gnome-session/gsm-manager.c
+++ b/gnome-session/gsm-manager.c
@@ -1426,61 +1426,61 @@ finish_pending_save_invocations (GsmManager *manager)
         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);
+        gsm_session_save (manager->priv->clients, manager->priv->session_name, &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;
@@ -1687,60 +1687,77 @@ debug_app_summary (GsmManager *manager)
 
         g_debug ("GsmManager: App startup summary");
         for (phase = GSM_MANAGER_PHASE_INITIALIZATION; phase < GSM_MANAGER_PHASE_RUNNING; phase++) {
                 g_debug ("GsmManager: Phase %s", phase_num_to_name (phase));
                 gsm_store_foreach (manager->priv->apps,
                                    (GsmStoreFunc)_debug_app_for_phase,
                                    GUINT_TO_POINTER (phase));
         }
 }
 
 void
 gsm_manager_start (GsmManager *manager)
 {
         g_debug ("GsmManager: GSM starting to manage");
 
         g_return_if_fail (GSM_IS_MANAGER (manager));
 
         gsm_xsmp_server_start (manager->priv->xsmp_server);
         gsm_manager_set_phase (manager, GSM_MANAGER_PHASE_INITIALIZATION);
         debug_app_summary (manager);
         start_phase (manager);
 }
 
 const char *
 _gsm_manager_get_default_session (GsmManager     *manager)
 {
         return g_settings_get_string (manager->priv->session_settings,
                                       KEY_SESSION_NAME);
 }
 
+char *
+_gsm_manager_get_saved_session (GsmManager     *manager)
+{
+        char *file;
+        char *type;
+        gboolean loaded;
+
+        file = g_build_filename (gsm_util_get_saved_session_dir (), "type", NULL);
+        loaded = g_file_get_contents (file, &type, NULL, NULL);
+        g_free (file);
+
+        if (!loaded)
+                return NULL;
+
+        return type;
+}
+
 void
 _gsm_manager_set_active_session (GsmManager     *manager,
                                  const char     *session_name,
                                  gboolean        is_fallback)
 {
         g_free (manager->priv->session_name);
         manager->priv->session_name = g_strdup (session_name);
         manager->priv->is_fallback_session = is_fallback;
 }
 
 static gboolean
 _app_has_app_id (const char   *id,
                  GsmApp       *app,
                  const char   *app_id_a)
 {
         const char *app_id_b;
 
         app_id_b = gsm_app_peek_app_id (app);
         return (app_id_b != NULL && strcmp (app_id_a, app_id_b) == 0);
 }
 
 static GsmApp *
 find_app_for_app_id (GsmManager *manager,
                      const char *app_id)
 {
         GsmApp *app;
         app = (GsmApp *)gsm_store_find (manager->priv->apps,
                                         (GsmStoreFunc)_app_has_app_id,
                                         (char *)app_id);
         return app;
@@ -2217,61 +2234,61 @@ on_xsmp_client_register_request (GsmXSMPClient *client,
         return handled;
 }
 
 static gboolean
 auto_save_is_enabled (GsmManager *manager)
 {
         return g_settings_get_boolean (manager->priv->settings, KEY_AUTOSAVE_ONE_SHOT)
             || g_settings_get_boolean (manager->priv->settings, KEY_AUTOSAVE);
 }
 
 static void
 maybe_save_session (GsmManager *manager)
 {
         GError *error;
 
         if (gsm_system_is_login_session (manager->priv->system))
                 return;
 
         /* We only allow session saving when session is running or when
          * logging out */
         if (manager->priv->phase != GSM_MANAGER_PHASE_RUNNING &&
             manager->priv->phase != GSM_MANAGER_PHASE_END_SESSION) {
                 return;
         }
 
         if (!auto_save_is_enabled (manager)) {
                 return;
         }
 
         error = NULL;
-        gsm_session_save (manager->priv->clients, &error);
+        gsm_session_save (manager->priv->clients, manager->priv->session_name, &error);
 
         if (error) {
                 g_warning ("Error saving session: %s", error->message);
                 g_error_free (error);
         }
 }
 
 static void
 _handle_client_end_session_response (GsmManager *manager,
                                      GsmClient  *client,
                                      gboolean    is_ok,
                                      gboolean    do_last,
                                      gboolean    cancel,
                                      const char *reason)
 {
         /* 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);
 
diff --git a/gnome-session/gsm-manager.h b/gnome-session/gsm-manager.h
index ca29b65..6f94f92 100644
--- a/gnome-session/gsm-manager.h
+++ b/gnome-session/gsm-manager.h
@@ -100,60 +100,61 @@ typedef enum
 } GsmManagerError;
 
 #define GSM_MANAGER_ERROR gsm_manager_error_quark ()
 
 GType               gsm_manager_error_get_type                 (void);
 #define GSM_MANAGER_TYPE_ERROR (gsm_manager_error_get_type ())
 
 GQuark              gsm_manager_error_quark                    (void);
 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);
+char *              _gsm_manager_get_saved_session             (GsmManager     *manager);
 
 void                _gsm_manager_set_active_session            (GsmManager     *manager,
                                                                 const char     *session_name,
                                                                 gboolean        is_fallback);
 
 /* exported methods */
 
 gboolean            gsm_manager_register_client                (GsmManager            *manager,
                                                                 const char            *app_id,
                                                                 const char            *client_startup_id,
                                                                 DBusGMethodInvocation *context);
 gboolean            gsm_manager_unregister_client              (GsmManager            *manager,
                                                                 const char            *session_client_id,
                                                                 DBusGMethodInvocation *context);
 
 gboolean            gsm_manager_inhibit                        (GsmManager            *manager,
                                                                 const char            *app_id,
                                                                 guint                  toplevel_xid,
                                                                 const char            *reason,
                                                                 guint                  flags,
                                                                 DBusGMethodInvocation *context);
 gboolean            gsm_manager_uninhibit                      (GsmManager            *manager,
                                                                 guint                  inhibit_cookie,
                                                                 DBusGMethodInvocation *context);
 gboolean            gsm_manager_is_inhibited                   (GsmManager            *manager,
                                                                 guint                  flags,
                                                                 gboolean              *is_inhibited,
                                                                 GError                *error);
 
 gboolean            gsm_manager_shutdown                       (GsmManager     *manager,
diff --git a/gnome-session/gsm-session-save.c b/gnome-session/gsm-session-save.c
index 2fe0bb0..07956b7 100644
--- a/gnome-session/gsm-session-save.c
+++ b/gnome-session/gsm-session-save.c
@@ -1,75 +1,107 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
  * gsm-session-save.c
  * Copyright (C) 2008 Lucas Rocha.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  * 02111-1307, USA.
  */
 
 #include <config.h>
 
+#include <string.h>
+
 #include <glib.h>
 #include <glib/gstdio.h>
 #include <gio/gio.h>
 
 #include "gsm-util.h"
 #include "gsm-autostart-app.h"
 #include "gsm-client.h"
 
 #include "gsm-session-save.h"
 
 #define GSM_MANAGER_SCHEMA        "org.gnome.SessionManager"
 #define KEY_AUTOSAVE_ONE_SHOT     "auto-save-session-one-shot"
 
 
 static gboolean gsm_session_clear_saved_session (const char *directory,
                                                  GHashTable *discard_hash);
 
 typedef struct {
         char        *dir;
         GHashTable  *discard_hash;
         GError     **error;
 } SessionSaveData;
 
+static void
+clear_session_type (const char *save_dir)
+{
+        char *file;
+
+        file = g_build_filename (save_dir, "type", NULL);
+
+        g_unlink (file);
+
+        g_free (file);
+}
+
+static void
+set_session_type (const char *save_dir,
+                  const char *type)
+{
+        char *file;
+        GError *error;
+
+        file = g_build_filename (save_dir, "type", NULL);
+
+        error = NULL;
+        g_file_set_contents (file, type, strlen (type), &error);
+        if (error != NULL)
+                g_warning ("couldn't save session type to %s: %s",
+                           type, error->message);
+
+        g_free (file);
+}
+
 static gboolean
 save_one_client (char            *id,
                  GObject         *object,
                  SessionSaveData *data)
 {
         GsmClient  *client;
         GKeyFile   *keyfile;
         const char *app_id;
         char       *path = NULL;
         char       *filename = NULL;
         char       *contents = NULL;
         gsize       length = 0;
         char       *discard_exec;
         GError     *local_error;
 
         client = GSM_CLIENT (object);
 
         local_error = NULL;
 
         keyfile = gsm_client_save (client, &local_error);
 
         if (keyfile == NULL || local_error) {
                 goto out;
         }
 
         contents = g_key_file_to_data (keyfile, &length, &local_error);
 
         if (local_error) {
                 goto out;
         }
@@ -109,112 +141,114 @@ save_one_client (char            *id,
                                               GSM_AUTOSTART_APP_DISCARD_KEY,
                                               NULL);
         if (discard_exec) {
                 g_hash_table_insert (data->discard_hash,
                                      discard_exec, discard_exec);
         }
 
         g_debug ("GsmSessionSave: saved client %s to %s", id, filename);
 
 out:
         if (keyfile != NULL) {
                 g_key_file_free (keyfile);
         }
 
         g_free (contents);
         g_free (filename);
         g_free (path);
 
         /* in case of any error, stop saving session */
         if (local_error) {
                 g_propagate_error (data->error, local_error);
                 g_error_free (local_error);
 
                 return TRUE;
         }
 
         return FALSE;
 }
 
 void
-gsm_session_save (GsmStore  *client_store,
-                  GError   **error)
+gsm_session_save (GsmStore    *client_store,
+                  const char  *type,
+                  GError     **error)
 {
         GSettings       *settings;
         const char      *save_dir;
         char            *tmp_dir;
         SessionSaveData  data;
 
         g_debug ("GsmSessionSave: Saving session");
 
         /* Clear one shot key autosave in the event its set (so that it's actually
          * one shot only)
          */
         settings = g_settings_new (GSM_MANAGER_SCHEMA);
         g_settings_set_boolean (settings, KEY_AUTOSAVE_ONE_SHOT, FALSE);
         g_object_unref (settings);
 
         save_dir = gsm_util_get_saved_session_dir ();
         if (save_dir == NULL) {
                 g_warning ("GsmSessionSave: cannot create saved session directory");
                 return;
         }
 
         tmp_dir = gsm_util_get_empty_tmp_session_dir ();
         if (tmp_dir == NULL) {
                 g_warning ("GsmSessionSave: cannot create new saved session directory");
                 return;
         }
 
         /* save the session in a temp directory, and remember the discard
          * commands */
         data.dir = tmp_dir;
         data.discard_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                    g_free, NULL);
         data.error = error;
 
         gsm_store_foreach (client_store,
                            (GsmStoreFunc) save_one_client,
                            &data);
 
         if (!*error) {
                 char *session_dir;
 
                 if (g_file_test (save_dir, G_FILE_TEST_IS_SYMLINK))
                         session_dir = g_file_read_link (save_dir, error);
                 else
                         session_dir = g_strdup (save_dir);
 
                 if (session_dir != NULL) {
-
                         char *absolute_session_dir;
 
+                        set_session_type (tmp_dir, type);
+
                         if (g_path_is_absolute (session_dir)) {
                                 absolute_session_dir = g_strdup (session_dir);
                         } else {
                                 char *parent_dir;
 
                                 parent_dir = g_path_get_dirname (save_dir);
                                 absolute_session_dir = g_build_filename (parent_dir, session_dir, NULL);
                                 g_free (parent_dir);
                         }
                         g_free (session_dir);
 
                         /* remove the old saved session */
                         gsm_session_clear_saved_session (absolute_session_dir, data.discard_hash);
 
                         if (g_file_test (absolute_session_dir, G_FILE_TEST_IS_DIR))
                                 g_rmdir (absolute_session_dir);
                         g_rename (tmp_dir, absolute_session_dir);
 
                         g_free (absolute_session_dir);
                 }
         } else {
                 g_warning ("GsmSessionSave: error saving session: %s", (*error)->message);
                 /* FIXME: we should create a hash table filled with the discard
                  * commands that are in desktop files from save_dir. */
                 gsm_session_clear_saved_session (tmp_dir, NULL);
                 g_rmdir (tmp_dir);
         }
 
         g_hash_table_destroy (data.discard_hash);
         g_free (tmp_dir);
@@ -294,31 +328,32 @@ gsm_session_clear_saved_session (const char *directory,
 
         while ((filename = g_dir_read_name (dir))) {
                 char *path = g_build_filename (directory,
                                                filename, NULL);
 
                 result = gsm_session_clear_one_client (path, discard_hash)
                          && result;
 
                 g_free (path);
         }
 
         g_dir_close (dir);
 
         return result;
 }
 
 void
 gsm_session_save_clear (void)
 {
         const char *save_dir;
 
         g_debug ("GsmSessionSave: Clearing saved session");
 
         save_dir = gsm_util_get_saved_session_dir ();
         if (save_dir == NULL) {
                 g_warning ("GsmSessionSave: cannot create saved session directory");
                 return;
         }
 
 	gsm_session_clear_saved_session (save_dir, NULL);
+        clear_session_type (save_dir);
 }
diff --git a/gnome-session/gsm-session-save.h b/gnome-session/gsm-session-save.h
index 10b5005..ed7fea2 100644
--- a/gnome-session/gsm-session-save.h
+++ b/gnome-session/gsm-session-save.h
@@ -1,35 +1,36 @@
 /* gsm-session-save.h
  * Copyright (C) 2008 Lucas Rocha.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation; either version 2 of the
  * License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  * 02111-1307, USA.
  */
 
 #ifndef __GSM_SESSION_SAVE_H__
 #define __GSM_SESSION_SAVE_H__
 
 #include <glib.h>
 
 #include "gsm-store.h"
 
 G_BEGIN_DECLS
 
-void      gsm_session_save                 (GsmStore  *client_store,
-                                            GError   **error);
+void      gsm_session_save                 (GsmStore    *client_store,
+                                            const char  *type,
+                                            GError     **error);
 void      gsm_session_save_clear           (void);
 
 G_END_DECLS
 
 #endif /* __GSM_SESSION_SAVE_H__ */
diff --git a/gnome-session/main.c b/gnome-session/main.c
index dc6db5f..b72f2bc 100644
--- a/gnome-session/main.c
+++ b/gnome-session/main.c
@@ -252,60 +252,61 @@ require_dbus_session (int      argc,
         }
 
         /* Should not be reached */
         return TRUE;
 }
 
 static gboolean
 check_gl (GError **error)
 {
         int status;
         char *argv[] = { LIBEXECDIR "/gnome-session-check-accelerated", NULL };
 
         if (!g_spawn_sync (NULL, (char **) argv, NULL, 0, NULL, NULL, NULL, NULL,
                            &status, error)) {
                 return FALSE;
         }
 
         return g_spawn_check_exit_status (status, error);
 }
 
 int
 main (int argc, char **argv)
 {
         GError           *error = NULL;
         char             *display_str;
         GsmManager       *manager;
         GsmStore         *client_store;
         static char     **override_autostart_dirs = NULL;
         static char      *opt_session_name = NULL;
         const char       *session_name;
+        char             *saved_session_name = NULL;
         gboolean          gl_failed = FALSE;
         static GOptionEntry entries[] = {
                 { "autostart", 'a', 0, G_OPTION_ARG_STRING_ARRAY, &override_autostart_dirs, N_("Override standard autostart directories"), N_("AUTOSTART_DIR") },
                 { "session", 0, 0, G_OPTION_ARG_STRING, &opt_session_name, N_("Session to use"), N_("SESSION_NAME") },
                 { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, N_("Enable debugging code"), NULL },
                 { "failsafe", 'f', 0, G_OPTION_ARG_NONE, &failsafe, N_("Do not load user-specified applications"), NULL },
                 { "version", 0, 0, G_OPTION_ARG_NONE, &show_version, N_("Version of this application"), NULL },
                 /* Translators: the 'fail whale' is the black dialog we show when something goes seriously wrong */
                 { "whale", 0, 0, G_OPTION_ARG_NONE, &please_fail, N_("Show the fail whale dialog for testing"), NULL },
                 { NULL, 0, 0, 0, NULL, NULL, NULL }
         };
 
         /* Make sure that we have a session bus */
         if (!require_dbus_session (argc, argv, &error)) {
                 gsm_util_init_error (TRUE, "%s", error->message);
         }
 
         /* Check GL, if it doesn't work out then force software fallback */
         if (!check_gl (&error)) {
                 gl_failed = TRUE;
 
                 g_debug ("hardware acceleration check failed: %s",
                          error? error->message : "");
                 g_clear_error (&error);
                 if (g_getenv ("LIBGL_ALWAYS_SOFTWARE") == NULL) {
                         g_setenv ("LIBGL_ALWAYS_SOFTWARE", "1", TRUE);
                         if (!check_gl (&error)) {
                                 g_warning ("software acceleration check failed: %s",
                                            error? error->message : "");
                                 g_clear_error (&error);
@@ -382,53 +383,60 @@ main (int argc, char **argv)
         gsm_util_setenv ("XDG_MENU_PREFIX", "gnome-");
 
         client_store = gsm_store_new ();
 
         /* Talk to logind before acquiring a name, since it does synchronous
          * calls at initialization time that invoke a main loop and if we
          * already owned a name, then we would service too early during
          * that main loop.
          */
         g_object_unref (gsm_get_system ());
 
         if (!acquire_name ()) {
                 gsm_fail_whale_dialog_we_failed (TRUE, TRUE, NULL);
                 gtk_main ();
                 exit (1);
         }
 
         manager = gsm_manager_new (client_store, failsafe);
 
         g_signal_connect_object (bus_proxy,
                                  "destroy",
                                  G_CALLBACK (shutdown_cb),
                                  manager,
                                  G_CONNECT_SWAPPED);
 
         g_unix_signal_add (SIGTERM, term_or_int_signal_cb, manager);
         g_unix_signal_add (SIGINT, term_or_int_signal_cb, manager);
         g_unix_signal_add (SIGUSR1, sigusr1_cb, manager);
         g_unix_signal_add (SIGUSR2, sigusr2_cb, manager);
 
-        if (IS_STRING_EMPTY (opt_session_name))
-                session_name = _gsm_manager_get_default_session (manager);
-        else
+        if (IS_STRING_EMPTY (opt_session_name)) {
+                saved_session_name = _gsm_manager_get_saved_session (manager);
+
+                if (IS_STRING_EMPTY (saved_session_name))
+                        session_name = _gsm_manager_get_default_session (manager);
+                else
+                        session_name = saved_session_name;
+        } else {
                 session_name = opt_session_name;
+        }
 
         gsm_util_set_autostart_dirs (override_autostart_dirs);
 
         if (!gsm_session_fill (manager, session_name)) {
                 gsm_fail_whale_dialog_we_failed (FALSE, TRUE, NULL);
         }
 
         gsm_manager_start (manager);
 
         gtk_main ();
 
         g_clear_object (&manager);
         g_clear_object (&client_store);
         g_clear_object (&bus_proxy);
+        g_free (saved_session_name);
 
         gdm_log_shutdown ();
 
         return 0;
 }
-- 
1.8.3.1


From 3dc13d7502b8dc4a9fa0f168ade9aa776cf2d5e9 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 7 Jan 2014 21:16:23 -0500
Subject: [PATCH 11/14] session-selector: restore saved session mode

When using the custom session selector, we need to know
whether to use classic mode or not.

This commit makes us use whatever mode was saved with the
session.
---
 tools/gnome-session-custom-session | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/tools/gnome-session-custom-session b/tools/gnome-session-custom-session
index 07fdb0c..358aee0 100644
--- a/tools/gnome-session-custom-session
+++ b/tools/gnome-session-custom-session
@@ -1,4 +1,19 @@
 #! /bin/sh
 
 gnome-session-selector
-exec gnome-session
+
+type_file="${XDG_CONFIG_HOME:-$HOME/.config}/gnome-session/saved-session/type"
+
+session_type=""
+if [ -e "$type_file" ]; then
+        read session_type < "$type_file"
+fi
+
+session_type_argument=""
+[ -n "$session_type" ] && session_type_argument="--session=$session_type"
+
+if [ "$session_type" = "gnome-classic" ]; then
+        export GNOME_SHELL_SESSION_MODE="classic"
+fi
+
+exec gnome-session "$session_type_argument"
-- 
1.8.3.1


From 25088eb65e4bf96a2b17028ae97eb48cf3c5a4dd Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 20 Dec 2013 10:53:33 -0500
Subject: [PATCH 12/14] session-selector: refresh from recent glade

The ui file is rather old.  This commit just opens it up in a recent
glade and resaves it, so we have a fresh starting point to make
changes.
---
 data/session-selector.ui | 80 ++++++++++++++++++++++++++++++++----------------
 1 file changed, 54 insertions(+), 26 deletions(-)

diff --git a/data/session-selector.ui b/data/session-selector.ui
index 1534a74..4d1e300 100644
--- a/data/session-selector.ui
+++ b/data/session-selector.ui
@@ -1,195 +1,223 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <interface>
-  <requires lib="gtk+" version="2.16"/>
-  <!-- interface-naming-policy project-wide -->
-  <object class="GtkListStore" id="session-store">
-    <columns>
-      <!-- column-name name -->
-      <column type="gchararray"/>
-    </columns>
-  </object>
-  <object class="GtkTreeModelSort" id="sort-model">
-    <property name="model">session-store</property>
-  </object>
+  <!-- interface-requires gtk+ 3.0 -->
   <object class="GtkWindow" id="main-window">
+    <property name="can_focus">False</property>
     <property name="title" translatable="yes">Custom Session</property>
     <property name="window_position">center</property>
     <property name="default_width">500</property>
     <property name="default_height">310</property>
     <property name="decorated">False</property>
     <child>
       <object class="GtkFrame" id="frame1">
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
         <property name="label_xalign">0.5</property>
         <property name="shadow_type">out</property>
         <child>
           <object class="GtkAlignment" id="alignment3">
             <property name="visible">True</property>
+            <property name="can_focus">False</property>
             <property name="border_width">12</property>
             <child>
               <object class="GtkVBox" id="vbox3">
                 <property name="visible">True</property>
-                <property name="orientation">vertical</property>
+                <property name="can_focus">False</property>
                 <property name="spacing">6</property>
-
                 <child>
                   <object class="GtkInfoBar" id="info-bar">
                     <property name="visible">True</property>
-                    <property name="message-type">other</property>
-
+                    <property name="can_focus">False</property>
+                    <property name="message_type">other</property>
                     <child internal-child="content_area">
-                      <object class="GtkHBox" id="info-bar-content_area">
+                      <object class="GtkBox" id="info-bar-content_area">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="orientation">vertical</property>
-                        <property name="spacing">0</property>
                         <child>
                           <object class="GtkLabel" id="info-label">
                             <property name="visible">True</property>
-                            <property name="xalign">0.0</property>
-                            <property name="yalign">0.5</property>
+                            <property name="can_focus">False</property>
+                            <property name="xalign">0</property>
                             <property name="label" translatable="yes">Please select a custom session to use</property>
                           </object>
                           <packing>
-                            <property name="expand">True</property>
-                            <property name="fill">True</property>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
                             <property name="position">0</property>
                           </packing>
                         </child>
                       </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child internal-child="action_area">
+                      <object class="GtkButtonBox" id="infobar-action_area1">
+                        <property name="can_focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
                     </child>
                   </object>
                   <packing>
                     <property name="expand">False</property>
                     <property name="fill">True</property>
                     <property name="position">0</property>
                   </packing>
                 </child>
                 <child>
                   <object class="GtkVBox" id="vbox4">
                     <property name="visible">True</property>
-                    <property name="orientation">vertical</property>
+                    <property name="can_focus">False</property>
                     <property name="spacing">12</property>
                     <child>
                       <object class="GtkHBox" id="hbox3">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="spacing">12</property>
                         <child>
                           <object class="GtkScrolledWindow" id="scrolledwindow2">
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
                             <property name="hscrollbar_policy">never</property>
-                            <property name="vscrollbar_policy">automatic</property>
                             <property name="shadow_type">in</property>
                             <child>
                               <object class="GtkTreeView" id="session-list">
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
+                                <property name="model">sort-model</property>
                                 <property name="headers_visible">False</property>
                                 <property name="search_column">0</property>
-                                <property name="model">sort-model</property>
+                                <child internal-child="selection">
+                                  <object class="GtkTreeSelection" id="treeview-selection1"/>
+                                </child>
                               </object>
                             </child>
                           </object>
                           <packing>
+                            <property name="expand">True</property>
+                            <property name="fill">True</property>
                             <property name="position">0</property>
                           </packing>
                         </child>
                         <child>
                           <object class="GtkVButtonBox" id="vbuttonbox2">
                             <property name="visible">True</property>
-                            <property name="orientation">vertical</property>
+                            <property name="can_focus">False</property>
                             <property name="spacing">6</property>
                             <property name="layout_style">start</property>
                             <child>
                               <object class="GtkButton" id="new-session">
                                 <property name="label" translatable="yes">_New Session</property>
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
                                 <property name="receives_default">True</property>
                                 <property name="use_underline">True</property>
                               </object>
                               <packing>
                                 <property name="expand">False</property>
                                 <property name="fill">False</property>
                                 <property name="position">0</property>
                               </packing>
                             </child>
                             <child>
                               <object class="GtkButton" id="remove-session">
                                 <property name="label" translatable="yes">_Remove Session</property>
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
                                 <property name="receives_default">True</property>
                                 <property name="use_underline">True</property>
                               </object>
                               <packing>
                                 <property name="expand">False</property>
                                 <property name="fill">False</property>
                                 <property name="position">1</property>
                               </packing>
                             </child>
                             <child>
                               <object class="GtkButton" id="rename-session">
                                 <property name="label" translatable="yes">Rena_me Session</property>
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
                                 <property name="receives_default">True</property>
                                 <property name="use_underline">True</property>
                               </object>
                               <packing>
                                 <property name="expand">False</property>
                                 <property name="fill">False</property>
                                 <property name="position">2</property>
                               </packing>
                             </child>
                           </object>
                           <packing>
                             <property name="expand">False</property>
+                            <property name="fill">True</property>
                             <property name="position">1</property>
                           </packing>
                         </child>
                       </object>
                       <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
                         <property name="position">1</property>
                       </packing>
                     </child>
                   </object>
                   <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
                     <property name="position">1</property>
                   </packing>
                 </child>
                 <child>
                   <object class="GtkHButtonBox" id="hbuttonbox2">
                     <property name="visible">True</property>
+                    <property name="can_focus">False</property>
                     <property name="spacing">6</property>
                     <property name="layout_style">end</property>
                     <child>
                       <object class="GtkButton" id="continue-button">
                         <property name="label" translatable="yes">_Continue</property>
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
                         <property name="can_default">True</property>
                         <property name="has_default">True</property>
                         <property name="receives_default">True</property>
                         <property name="use_underline">True</property>
                       </object>
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">False</property>
                         <property name="position">0</property>
                       </packing>
                     </child>
                   </object>
                   <packing>
                     <property name="expand">False</property>
+                    <property name="fill">True</property>
                     <property name="position">2</property>
                   </packing>
                 </child>
               </object>
             </child>
           </object>
         </child>
       </object>
     </child>
   </object>
+  <object class="GtkListStore" id="session-store">
+    <columns>
+      <!-- column-name name -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkTreeModelSort" id="sort-model">
+    <property name="model">session-store</property>
+  </object>
 </interface>
-- 
1.8.3.1


From d6274d2a56ca17001d8530ec6fd00b918d196356 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 7 Jan 2014 21:02:02 -0500
Subject: [PATCH 13/14] session-selector: add toggle for classic/normal
 selection

Since we offer both classic mode and regular mode when
not using the session selector, we should also offer it
when using the session selector.
---
 data/session-selector.ui       |  39 ++++++++++++++-
 tools/gnome-session-selector.c | 105 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 142 insertions(+), 2 deletions(-)

diff --git a/data/session-selector.ui b/data/session-selector.ui
index 4d1e300..beab73a 100644
--- a/data/session-selector.ui
+++ b/data/session-selector.ui
@@ -153,71 +153,106 @@
                                 <property name="fill">False</property>
                                 <property name="position">2</property>
                               </packing>
                             </child>
                           </object>
                           <packing>
                             <property name="expand">False</property>
                             <property name="fill">True</property>
                             <property name="position">1</property>
                           </packing>
                         </child>
                       </object>
                       <packing>
                         <property name="expand">True</property>
                         <property name="fill">True</property>
                         <property name="position">1</property>
                       </packing>
                     </child>
                   </object>
                   <packing>
                     <property name="expand">True</property>
                     <property name="fill">True</property>
                     <property name="position">1</property>
                   </packing>
                 </child>
                 <child>
                   <object class="GtkHButtonBox" id="hbuttonbox2">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="spacing">6</property>
-                    <property name="layout_style">end</property>
+                    <child>
+                      <object class="GtkBox" id="box1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkLabel" id="classic-mode-label">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="label" translatable="yes">Classic Experience</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkSwitch" id="classic-mode-switch">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
                     <child>
                       <object class="GtkButton" id="continue-button">
                         <property name="label" translatable="yes">_Continue</property>
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
                         <property name="can_default">True</property>
                         <property name="has_default">True</property>
                         <property name="receives_default">True</property>
                         <property name="use_underline">True</property>
                       </object>
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">False</property>
-                        <property name="position">0</property>
+                        <property name="position">1</property>
+                        <property name="non_homogeneous">True</property>
                       </packing>
                     </child>
                   </object>
                   <packing>
                     <property name="expand">False</property>
                     <property name="fill">True</property>
                     <property name="position">2</property>
                   </packing>
                 </child>
               </object>
             </child>
           </object>
         </child>
       </object>
     </child>
   </object>
   <object class="GtkListStore" id="session-store">
     <columns>
       <!-- column-name name -->
       <column type="gchararray"/>
     </columns>
   </object>
   <object class="GtkTreeModelSort" id="sort-model">
     <property name="model">session-store</property>
   </object>
 </interface>
diff --git a/tools/gnome-session-selector.c b/tools/gnome-session-selector.c
index 54541d3..1011a52 100644
--- a/tools/gnome-session-selector.c
+++ b/tools/gnome-session-selector.c
@@ -17,60 +17,61 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
  * Written by: Matthias Clasen <mclasen@redhat.com>
  */
 
 #include "config.h"
 
 #include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
 #include <glib.h>
 #include <gtk/gtk.h>
 #include <gio/gio.h>
 
 #include <glib/gi18n.h>
 #include <glib/gstdio.h>
 
 #include <dbus/dbus-glib.h>
 #include <dbus/dbus-glib-lowlevel.h>
 
 #define GSM_SERVICE_DBUS   "org.gnome.SessionManager"
 #define GSM_PATH_DBUS      "/org/gnome/SessionManager"
 #define GSM_INTERFACE_DBUS "org.gnome.SessionManager"
 
 #define GSM_MANAGER_SCHEMA        "org.gnome.SessionManager"
 #define KEY_AUTOSAVE_ONE_SHOT     "auto-save-session-one-shot"
+#define DEFAULT_SESSION_NAME      "gnome"
 
 static GtkBuilder *builder;
 static GtkWidget *session_list;
 static GtkListStore *store;
 static GtkTreeModelSort *sort_model;
 static char *info_text;
 
 static void select_session (const char *name);
 static gboolean make_session_current (const char *name);
 
 static char *
 get_session_path (const char *name)
 {
         return g_build_filename (g_get_user_config_dir (), "gnome-session", name, NULL);
 }
 
 static char *
 find_new_session_name (void)
 {
         char *name;
         char *path;
         int i;
 
         for (i = 1; i < 20; i++) {
                 name = g_strdup_printf (_("Session %d"), i);
                 path = get_session_path (name);
                 if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
                         g_free (path);
                         return name;
                 }
@@ -126,104 +127,126 @@ is_valid_session_name (const char *name)
         gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
         do {
                 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, 0, &n, -1);
                 if (strcmp (n, name) == 0) {
                         char *message;
                         message = g_strdup_printf (_("A session named ‘%s’ already exists"), name);
                         warning_text = g_strdup_printf ("%s\n<small><b>Note:</b> <i>%s</i></small>", info_text, message);
                         g_free (message);
                         g_free (n);
                         break;
                 }
                 g_free (n);
         } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
 
         info_bar = (GtkWidget *) gtk_builder_get_object (builder, "info-bar");
         label = (GtkWidget*) gtk_builder_get_object (builder, "info-label");
 
         if (warning_text != NULL) {
             gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_WARNING);
             gtk_label_set_markup (GTK_LABEL (label), warning_text);
             g_free (warning_text);
             return FALSE;
         }
 
         gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_OTHER);
         gtk_label_set_markup (GTK_LABEL (label), info_text);
 
         return TRUE;
 }
 
+static char *
+get_session_type_from_file (const char *name)
+{
+        char *file;
+        char *type;
+        gboolean loaded;
+
+        file = g_build_filename (g_get_user_config_dir (), "gnome-session", name, "type", NULL);
+        loaded = g_file_get_contents (file, &type, NULL, NULL);
+        g_free (file);
+
+        if (!loaded)
+                return g_strdup (DEFAULT_SESSION_NAME);
+
+        return type;
+}
+
 static void
 populate_session_list (GtkWidget *session_list)
 {
         GtkTreeIter iter;
         char *path;
         const char *name;
         GDir *dir;
         GError *error;
         char *saved_session;
         char *default_session;
         char *default_name;
         char last_session[PATH_MAX] = "";
 
         saved_session = get_session_path ("saved-session");
 
         if (!g_file_test (saved_session, G_FILE_TEST_IS_SYMLINK)) {
                 default_name = find_new_session_name ();
                 default_session = get_session_path (default_name);
                 rename (saved_session, default_session);
                 if (symlink (default_name, saved_session) < 0)
                         g_warning ("Failed to convert saved-session to symlink");
                 g_free (default_name);
                 g_free (default_session);
         }
 
         path = g_build_filename (g_get_user_config_dir (), "gnome-session", NULL);
         error = NULL;
         dir = g_dir_open (path, 0, &error);
         if (dir == NULL) {
                 g_warning ("Failed to open %s: %s", path, error->message);
                 g_error_free (error);
                 goto out;
         }
 
         default_name = NULL;
         if (readlink (saved_session, last_session, PATH_MAX - 1) > 0) {
                 default_name = g_path_get_basename (last_session);
         }
 
         while ((name = g_dir_read_name (dir)) != NULL) {
+                char *session_type;
+
                 if (strcmp (name, "saved-session") == 0)
                         continue;
 
+                session_type = get_session_type_from_file (name);
+
                 gtk_list_store_insert_with_values (store, &iter, 100, 0, name, -1);
+                g_free (session_type);
 
                 if (g_strcmp0 (default_name, name) == 0) {
                         GtkTreeSelection *selection;
                         GtkTreeIter child_iter;
 
                         gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &child_iter, &iter);
                         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (session_list));
                         gtk_tree_selection_select_iter (selection, &child_iter);
                 }
         }
 
         g_free (default_name);
         g_dir_close (dir);
 
  out:
         g_free (saved_session);
         g_free (path);
 }
 
 static char *
 get_last_session (void)
 {
         char *saved_session;
         char last_session[PATH_MAX] = "";
         char *name = NULL;
 
         saved_session = get_session_path ("saved-session");
 
         if (readlink (saved_session, last_session, PATH_MAX - 1) > 0) {
                 name = g_path_get_basename (last_session);
@@ -261,60 +284,136 @@ remove_session (const char *name)
         GError *error;
 
         path1 = get_session_path ("saved-session");
         path2 = get_session_path (name);
 
         error = NULL;
         n = g_file_read_link (path1, &error);
         if (n == NULL) {
                 g_warning ("Failed to read link: %s", error->message);
                 g_error_free (error);
         }
         else if (strcmp (n, name) == 0) {
                 unlink (path1);
         }
         g_free (n);
 
         dir = g_dir_open (path2, 0, NULL);
         while ((d = g_dir_read_name (dir)) != NULL) {
                 path = g_build_filename (path2, d, NULL);
                 unlink (path);
                 g_free (path);
         }
         g_dir_close (dir);
 
         remove (path2);
 
         g_free (path1);
         g_free (path2);
 }
 
+static const char *
+get_session_type_from_switch (void)
+{
+        GtkWidget *mode_switch;
+        gboolean is_classic_mode;
+
+        mode_switch = (GtkWidget *)gtk_builder_get_object (builder, "classic-mode-switch");
+
+        is_classic_mode = gtk_switch_get_active (GTK_SWITCH (mode_switch));
+
+        if (is_classic_mode) {
+                return "gnome-classic";
+        } else {
+                return "gnome";
+        }
+}
+
+static void
+set_mode_switch_from_session_type_file (const char *name)
+{
+        GtkWidget *mode_switch;
+        gboolean is_classic_mode = FALSE;
+        char *type;
+
+        mode_switch = (GtkWidget *)gtk_builder_get_object (builder, "classic-mode-switch");
+
+        type = get_session_type_from_file (name);
+        is_classic_mode = strcmp (type, "gnome-classic") == 0;
+        g_free (type);
+
+        gtk_switch_set_active (GTK_SWITCH (mode_switch), is_classic_mode);
+}
+
+static void
+save_session_type (const char *save_dir,
+                   const char *type)
+{
+        char *file;
+        GError *error;
+
+        file = g_build_filename (save_dir, "type", NULL);
+
+        error = NULL;
+        g_file_set_contents (file, type, strlen (type), &error);
+        if (error != NULL)
+                g_warning ("couldn't save session type to %s: %s",
+                           type, error->message);
+
+        g_free (file);
+}
+
+static void
+save_session_type_from_switch (void)
+{
+        char *name, *path;
+        const char *session_type;
+
+        name = get_selected_session ();
+
+        if (name == NULL) {
+                return;
+        }
+
+        path = get_session_path (name);
+        g_free (name);
+
+        session_type = get_session_type_from_switch ();
+        save_session_type (path, session_type);
+}
+
+static void
+on_mode_switched (GtkSwitch *mode_switch)
+{
+        save_session_type_from_switch ();
+}
+
 static gboolean
 make_session_current (const char *name)
 {
         char *path1;
         gboolean ret = TRUE;
 
         path1 = g_build_filename (g_get_user_config_dir (), "gnome-session", "saved-session", NULL);
 
         unlink (path1);
         if (symlink (name, path1) < 0) {
                 g_warning ("Failed to make session '%s' current", name);
                 ret = FALSE;
         }
 
         g_free (path1);
 
         return ret;
 }
 
 static void
 on_remove_session_clicked (GtkButton *button,
                            gpointer   data)
 {
         GtkTreeSelection *selection;
         GtkTreeModel *model;
         GtkTreeIter iter;
         char *name;
 
         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (session_list));
         if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
@@ -493,60 +592,62 @@ static void
 create_session_and_begin_rename (void)
 {
         gchar *name;
 
         name = find_new_session_name ();
         create_session (name);
         select_session (name);
 
         begin_rename ();
 }
 
 static void
 on_new_session_clicked (GtkButton *button,
                         gpointer   data)
 {
 	create_session_and_begin_rename ();
 }
 
 static void
 on_selection_changed (GtkTreeSelection *selection,
                       gpointer          data)
 {
         char *name;
 
         name = get_selected_session ();
 
         if (name == NULL) {
                 return;
         }
 
+        set_mode_switch_from_session_type_file (name);
+
         g_free (name);
 }
 
 static void
 update_remove_button (void)
 {
         GtkWidget *button;
 
         button = (GtkWidget *)gtk_builder_get_object (builder, "remove-session");
         if (gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), NULL) > 1) {
                 gtk_widget_set_sensitive (button, TRUE);
         } else {
                 gtk_widget_set_sensitive (button, FALSE);
         }
 }
 
 static void
 on_row_edited (GtkCellRendererText *cell,
                const char          *path_string,
                const char          *new_name,
                gpointer             data)
 {
         GtkTreePath *path;
         GtkTreeIter  sort_iter, items_iter;
         char        *old_name;
         gboolean     was_renamed;
 
         path = gtk_tree_path_new_from_string (path_string);
         gtk_tree_model_get_iter (GTK_TREE_MODEL (sort_model), &sort_iter, path);
 
@@ -752,75 +853,79 @@ main (int argc, char *argv[])
         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
                                               0, GTK_SORT_ASCENDING);
         g_signal_connect (store, "row-deleted", G_CALLBACK (on_row_deleted), NULL);
         g_signal_connect (store, "row-inserted", G_CALLBACK (on_row_inserted), NULL);
         session_list = (GtkWidget *) gtk_builder_get_object (builder, "session-list");
 
         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (session_list));
         gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
 
         populate_session_list (session_list);
 
         cell = gtk_cell_renderer_text_new ();
         g_signal_connect (cell, "edited", G_CALLBACK (on_row_edited), NULL);
 
         column = gtk_tree_view_column_new_with_attributes ("", cell, "text", 0, NULL);
         gtk_tree_view_append_column (GTK_TREE_VIEW (session_list), GTK_TREE_VIEW_COLUMN (column));
 
         g_signal_connect (session_list, "row-activated", G_CALLBACK (on_row_activated), NULL);
 
         g_signal_connect (selection, "changed",
                           G_CALLBACK (on_selection_changed), NULL);
 
         widget = (GtkWidget *) gtk_builder_get_object (builder, "new-session");
         g_signal_connect (widget, "clicked", G_CALLBACK (on_new_session_clicked), NULL);
         widget = (GtkWidget *) gtk_builder_get_object (builder, "remove-session");
         g_signal_connect (widget, "clicked", G_CALLBACK (on_remove_session_clicked), NULL);
         widget = (GtkWidget *) gtk_builder_get_object (builder, "rename-session");
         g_signal_connect (widget, "clicked", G_CALLBACK (on_rename_session_clicked), NULL);
         widget = (GtkWidget *) gtk_builder_get_object (builder, "continue-button");
         g_signal_connect (widget, "clicked", G_CALLBACK (on_continue_clicked), NULL);
+        widget = (GtkWidget *) gtk_builder_get_object (builder, "classic-mode-switch");
+        g_signal_connect (widget, "notify::active", G_CALLBACK (on_mode_switched), NULL);
 
         g_signal_connect (window, "map", G_CALLBACK (on_map), NULL);
         gtk_widget_show (window);
 
         if (g_strcmp0 (action, "load") == 0) {
             info_text = _("Please select a custom session to run");
         } else if (g_strcmp0 (action, "print") == 0) {
             info_text = _("Please select a session to use");
         } else if (g_strcmp0 (action, "save") == 0) {
             info_text = _("Please select a session to save to");
         }
 
         label = (GtkWidget*) gtk_builder_get_object (builder, "info-label");
         gtk_label_set_markup (GTK_LABEL (label), info_text);
 
         selected_session = get_selected_session ();
 
         if (selected_session == NULL) {
 		create_session_and_begin_rename ();
 	} else {
+                set_mode_switch_from_session_type_file (selected_session);
 		g_free (selected_session);
         }
 
         gtk_main ();
 
         selected_session = get_selected_session ();
 
         if (g_strcmp0 (action, "load") == 0) {
                 make_session_current (selected_session);
                 auto_save_next_session_if_needed ();
         } else if (g_strcmp0 (action, "save") == 0) {
                 char *last_session;
 
                 last_session = get_last_session ();
                 make_session_current (selected_session);
                 save_session ();
+                save_session_type_from_switch ();
                 if (last_session != NULL)
                     make_session_current (last_session);
         } else if (g_strcmp0 (action, "print") == 0) {
                 g_print ("%s\n", selected_session);
         }
         g_free (selected_session);
 
         return 0;
 }
-- 
1.8.3.1


From acc1f8715b9e3a9153eeb0c2281cb156a8925c3c Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 8 Jan 2014 10:15:29 -0500
Subject: [PATCH 14/14] session-selector: use classic mode by default

---
 tools/gnome-session-selector.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/gnome-session-selector.c b/tools/gnome-session-selector.c
index 1011a52..e18023c 100644
--- a/tools/gnome-session-selector.c
+++ b/tools/gnome-session-selector.c
@@ -17,61 +17,61 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
  * Written by: Matthias Clasen <mclasen@redhat.com>
  */
 
 #include "config.h"
 
 #include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
 #include <glib.h>
 #include <gtk/gtk.h>
 #include <gio/gio.h>
 
 #include <glib/gi18n.h>
 #include <glib/gstdio.h>
 
 #include <dbus/dbus-glib.h>
 #include <dbus/dbus-glib-lowlevel.h>
 
 #define GSM_SERVICE_DBUS   "org.gnome.SessionManager"
 #define GSM_PATH_DBUS      "/org/gnome/SessionManager"
 #define GSM_INTERFACE_DBUS "org.gnome.SessionManager"
 
 #define GSM_MANAGER_SCHEMA        "org.gnome.SessionManager"
 #define KEY_AUTOSAVE_ONE_SHOT     "auto-save-session-one-shot"
-#define DEFAULT_SESSION_NAME      "gnome"
+#define DEFAULT_SESSION_NAME      "gnome-classic"
 
 static GtkBuilder *builder;
 static GtkWidget *session_list;
 static GtkListStore *store;
 static GtkTreeModelSort *sort_model;
 static char *info_text;
 
 static void select_session (const char *name);
 static gboolean make_session_current (const char *name);
 
 static char *
 get_session_path (const char *name)
 {
         return g_build_filename (g_get_user_config_dir (), "gnome-session", name, NULL);
 }
 
 static char *
 find_new_session_name (void)
 {
         char *name;
         char *path;
         int i;
 
         for (i = 1; i < 20; i++) {
                 name = g_strdup_printf (_("Session %d"), i);
                 path = get_session_path (name);
                 if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
                         g_free (path);
                         return name;
                 }
-- 
1.8.3.1