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">●</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">●</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">●</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