You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

669 lines
23 KiB

From 2dad276ed4db5ee510689f41cd96180415ac4745 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 20 Dec 2013 15:32:04 -0500
Subject: [PATCH 13/19] 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 | 43 +++++++++++++++++++++++++++++---
gnome-session/gsm-session-save.h | 7 +++---
gnome-session/main.c | 11 +++++++-
5 files changed, 73 insertions(+), 10 deletions(-)
diff --git a/gnome-session/gsm-manager.c b/gnome-session/gsm-manager.c
index 31dc67db..325c6c46 100644
--- a/gnome-session/gsm-manager.c
+++ b/gnome-session/gsm-manager.c
@@ -1260,61 +1260,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->apps, 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;
@@ -1528,60 +1528,77 @@ debug_app_summary (GsmManager *manager)
g_debug ("GsmManager: App startup summary");
for (phase = GSM_MANAGER_PHASE_EARLY_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_EARLY_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;
gsm_exported_manager_set_session_name (manager->priv->skeleton, session_name);
}
void
_gsm_manager_set_renderer (GsmManager *manager,
const char *renderer)
{
gsm_exported_manager_set_renderer (manager->priv->skeleton, renderer);
}
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);
}
@@ -1946,61 +1963,61 @@ on_xsmp_client_register_confirmed (GsmXSMPClient *client,
}
}
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, manager->priv->apps, &error);
+ gsm_session_save (manager->priv->clients, manager->priv->apps, 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 a8de58de..fcf36019 100644
--- a/gnome-session/gsm-manager.h
+++ b/gnome-session/gsm-manager.h
@@ -88,51 +88,52 @@ typedef enum
GSM_MANAGER_ERROR_INVALID_OPTION,
GSM_MANAGER_ERROR_LOCKED_DOWN,
GSM_MANAGER_NUM_ERRORS
} GsmManagerError;
#define GSM_MANAGER_ERROR gsm_manager_error_quark ()
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);
void _gsm_manager_set_renderer (GsmManager *manager,
const char *renderer);
gboolean gsm_manager_save_session (GsmManager *manager,
DBusGMethodInvocation *context);
gboolean gsm_manager_logout (GsmManager *manager,
guint logout_mode,
GError **error);
gboolean gsm_manager_set_phase (GsmManager *manager,
GsmManagerPhase phase);
G_END_DECLS
#endif /* __GSM_MANAGER_H */
diff --git a/gnome-session/gsm-session-save.c b/gnome-session/gsm-session-save.c
index 7cbc72fe..22706953 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, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
+#include <string.h>
+
#include <glib.h>
#include <glib/gstdio.h>
#include <gio/gio.h>
#include "gsm-app.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;
GsmStore *app_store;
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
_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 g_strcmp0 (app_id_a, app_id_b) == 0;
}
static gboolean
save_one_client (char *id,
GObject *object,
SessionSaveData *data)
{
GsmClient *client;
GKeyFile *keyfile;
GsmApp *app = NULL;
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;
@@ -124,114 +156,116 @@ 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,
- GsmStore *app_store,
- GError **error)
+gsm_session_save (GsmStore *client_store,
+ GsmStore *app_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.app_store = app_store;
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);
@@ -313,31 +347,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 f55c9c16..b32673c4 100644
--- a/gnome-session/gsm-session-save.h
+++ b/gnome-session/gsm-session-save.h
@@ -1,34 +1,35 @@
/* 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, see <http://www.gnu.org/licenses/>.
*/
#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,
- GsmStore *app_store,
- GError **error);
+void gsm_session_save (GsmStore *client_store,
+ GsmStore *app_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 b1ac3850..cee385d9 100644
--- a/gnome-session/main.c
+++ b/gnome-session/main.c
@@ -119,61 +119,70 @@ sigusr2_cb (gpointer data)
static gboolean
sigusr1_cb (gpointer data)
{
gdm_log_toggle_debug ();
return TRUE;
}
static void
on_name_acquired (GDBusConnection *connection,
const char *name,
gpointer data)
{
gsm_manager_start (manager);
}
static void
create_manager (void)
{
GsmStore *client_store;
client_store = gsm_store_new ();
manager = gsm_manager_new (client_store, failsafe);
g_object_unref (client_store);
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 (session_name)) {
- session_name = _gsm_manager_get_default_session (manager);
+ char *saved_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 = g_steal_pointer (&saved_session_name);
+
+ g_free (saved_session_name);
}
if (!gsm_session_fill (manager, session_name)) {
gsm_fail_whale_dialog_we_failed (FALSE, TRUE, NULL);
}
_gsm_manager_set_renderer (manager, gl_renderer);
}
static void
on_bus_acquired (GDBusConnection *connection,
const char *name,
gpointer data)
{
create_manager ();
}
static guint
acquire_name (void)
{
return g_bus_own_name (G_BUS_TYPE_SESSION,
GSM_DBUS_NAME,
G_BUS_NAME_OWNER_FLAGS_NONE,
on_bus_acquired,
on_name_acquired,
on_name_lost,
NULL, NULL);
}
static gboolean
--
2.17.0