Commit be923e75 authored by Lucas Almeida Rocha's avatar Lucas Almeida Rocha

Merge branch 'session-saving'

svn path=/trunk/; revision=5295
parent ebd09750
2009-02-23 Lucas Rocha <lucasr@gnome.org>
* gnome-session/Makefile.am, gnome-session/gsm-resumed-app.[ch]:
remove GsmResumedApp code as it's being used anymore.
2009-02-23 Lucas Rocha <lucasr@gnome.org>
* gnome-session/main.c, gnome-session/gsm-manager.c: remove code for
handling legacy session saving files as it won't be supported anymore.
2009-02-23 Lucas Rocha <lucasr@gnome.org>
Bug 552387 – gnome-session doesn't save session anymore
* gnome-session/Makefile.am: add gsm-session-save.[ch] to the build.
* gnome-session/gsm-session-save.[ch]: session saving functions.
* gnome-session/gsm-autostart-app.c (load_desktop_file): check if the
desktop file has X-GNOME-Autostart-startup-id to define startup id of
the GsmAutostartApp.
* gnome-session/gsm-client.[ch] (gsm_client_save): add gsm_client_save
virtual method which should be implemented by each type of client.
* gnome-session/gsm-dbus-client.c, gnome-session/gsm-xsmp-client.c:
add respective gsm_client_save implementations. D-Bus clients still
don't implement saving.
* gnome-session/gsm-manager.c (auto_save_is_enabled,
maybe_save_session): save session state if auto save is enable before
finalizing the session.
* gnome-session/main.c (load_standard_apps): load GsmApps from the
saved session directory.
2009-02-23 Lucas Rocha <lucasr@gnome.org>
* gnome-session/main.c, gnome-session/gsm-util.[ch]: move
find_desktop_file_for_app_name to gsm-util so that we can use it in
other places.
2009-02-23 Lucas Rocha <lucasr@gnome.org>
* gnome-session/gsm-manager.c (user_logout): use gconf client from
GsmManager instead of getting a new one.
2009-02-23 Lucas Rocha <lucasr@gnome.org>
* gnome-session/gsm-xsmp-client.c (do_save_yourself): add comments on
SmsSaveYourself parameters for clarity.
2009-02-23 Lucas Rocha <lucasr@gnome.org>
* gnome-session/gsm-manager.c (on_xsmp_client_logout_request):
improve readability of conditional code.
2009-02-23 Lucas Rocha <lucasr@gnome.org>
* gnome-session/gsm-manager.c: wrap too long lines into 80 cols.
2009-02-23 Lucas Rocha <lucasr@gnome.org>
* gnome-session/gsm-manager.c: rename forceful attribute to
forceful_logout for clarity.
2009-02-22 Lucas Rocha <lucasr@gnome.org>
* capplet/gsm-properties-dialog.c: use G_KEY_FILE_DESKTOP_* constants
......
......@@ -59,8 +59,6 @@ gnome_session_SOURCES = \
gsm-app.c \
gsm-autostart-app.h \
gsm-autostart-app.c \
gsm-resumed-app.h \
gsm-resumed-app.c \
gsm-client.c \
gsm-client.h \
gsm-xsmp-client.h \
......@@ -96,6 +94,8 @@ gnome_session_SOURCES = \
gsm-inhibitor.c \
gsm-manager.c \
gsm-manager.h \
gsm-session-save.c \
gsm-session-save.h \
gsm-xsmp-server.c \
gsm-xsmp-server.h \
$(NULL)
......
......@@ -419,7 +419,14 @@ load_desktop_file (GsmAutostartApp *app)
/* this must only be done on first load */
switch (app->priv->launch_type) {
case AUTOSTART_LAUNCH_SPAWN:
startup_id = gsm_util_generate_startup_id ();
startup_id =
egg_desktop_file_get_string (app->priv->desktop_file,
"X-GNOME-Autostart-startup-id",
NULL);
if (startup_id == NULL) {
startup_id = gsm_util_generate_startup_id ();
}
break;
case AUTOSTART_LAUNCH_ACTIVATE:
startup_id = g_strdup (dbus_name);
......
......@@ -23,6 +23,8 @@
#include <dbus/dbus-glib.h>
#include "eggdesktopfile.h"
#include "gsm-marshal.h"
#include "gsm-client.h"
#include "gsm-client-glue.h"
......@@ -506,6 +508,15 @@ gsm_client_disconnected (GsmClient *client)
g_signal_emit (client, signals[DISCONNECTED], 0);
}
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
gdm_client_end_session_response (GsmClient *client,
gboolean is_ok,
......
......@@ -22,6 +22,7 @@
#ifndef __GSM_CLIENT_H__
#define __GSM_CLIENT_H__
#include <glib.h>
#include <glib-object.h>
#include <sys/types.h>
......@@ -87,6 +88,8 @@ struct _GsmClientClass
GError **error);
gboolean (*impl_stop) (GsmClient *client,
GError **error);
GKeyFile * (*impl_save) (GsmClient *client,
GError **error);
};
typedef enum
......@@ -130,6 +133,8 @@ gboolean gsm_client_cancel_end_session (GsmClient *client,
void gsm_client_disconnected (GsmClient *client);
GKeyFile *gsm_client_save (GsmClient *client,
GError **error);
/* exported to bus */
gboolean gsm_client_stop (GsmClient *client,
GError **error);
......
......@@ -412,6 +412,19 @@ gsm_dbus_client_finalize (GObject *object)
G_OBJECT_CLASS (gsm_dbus_client_parent_class)->finalize (object);
}
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)
......@@ -651,6 +664,7 @@ gsm_dbus_client_class_init (GsmDBusClientClass *klass)
object_class->set_property = gsm_dbus_client_set_property;
object_class->dispose = gsm_dbus_client_dispose;
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;
......
......@@ -52,7 +52,6 @@
#include "gsm-dbus-client.h"
#include "gsm-autostart-app.h"
#include "gsm-resumed-app.h"
#include "gsm-util.h"
#include "gdm.h"
......@@ -60,6 +59,7 @@
#include "gsm-inhibit-dialog.h"
#include "gsm-consolekit.h"
#include "gsm-power-manager.h"
#include "gsm-session-save.h"
#define GSM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_MANAGER, GsmManagerPrivate))
......@@ -79,6 +79,9 @@
#define KEY_DESKTOP_DIR "/desktop/gnome/session"
#define KEY_IDLE_DELAY KEY_DESKTOP_DIR "/idle_delay"
#define KEY_GNOME_SESSION_DIR "/apps/gnome-session/options"
#define KEY_AUTOSAVE KEY_GNOME_SESSION_DIR "/auto_save_session"
#define IS_STRING_EMPTY(x) ((x)==NULL||(x)[0]=='\0')
struct GsmManagerPrivate
......@@ -93,7 +96,7 @@ struct GsmManagerPrivate
GsmManagerPhase phase;
guint phase_timeout_id;
GSList *pending_apps;
gboolean forceful;
gboolean forceful_logout;
GSList *query_clients;
guint query_timeout_id;
......@@ -280,7 +283,9 @@ app_condition_changed (GsmApp *app,
/* Kill client in case condition if false and make sure it won't
* be automatically restarted by adding the client to
* condition_clients */
manager->priv->condition_clients = g_slist_prepend (manager->priv->condition_clients, client);
manager->priv->condition_clients =
g_slist_prepend (manager->priv->condition_clients, client);
g_debug ("GsmManager: stopping client %s for app", gsm_client_peek_id (client));
error = NULL;
......@@ -540,7 +545,7 @@ do_phase_end_session (GsmManager *manager)
data.manager = manager;
data.flags = 0;
if (manager->priv->forceful) {
if (manager->priv->forceful_logout) {
data.flags |= GSM_CLIENT_END_SESSION_FLAG_FORCEFUL;
}
......@@ -684,7 +689,7 @@ cancel_end_session (GsmManager *manager)
NULL);
gsm_manager_set_phase (manager, GSM_MANAGER_PHASE_RUNNING);
manager->priv->forceful = FALSE;
manager->priv->forceful_logout = FALSE;
start_phase (manager);
}
......@@ -806,7 +811,7 @@ do_dialog_action (GsmManager *manager,
manager_attempt_reboot (manager);
break;
case GSM_LOGOUT_ACTION_LOGOUT:
manager->priv->forceful = TRUE;
manager->priv->forceful_logout = TRUE;
end_phase (manager);
break;
default:
......@@ -973,12 +978,12 @@ do_phase_query_end_session (GsmManager *manager)
data.manager = manager;
data.flags = 0;
if (manager->priv->forceful) {
if (manager->priv->forceful_logout) {
data.flags |= GSM_CLIENT_END_SESSION_FLAG_FORCEFUL;
}
debug_clients (manager);
g_debug ("GsmManager: sending query-end-session to clients forceful:%d", manager->priv->forceful);
g_debug ("GsmManager: sending query-end-session to clients forceful:%d", manager->priv->forceful_logout);
gsm_store_foreach (manager->priv->clients,
(GsmStoreFunc)_client_query_end_session,
&data);
......@@ -1527,6 +1532,51 @@ on_xsmp_client_register_request (GsmXSMPClient *client,
return handled;
}
static gboolean
auto_save_is_enabled(GsmManager *manager)
{
GError *error;
gboolean auto_save;
error = NULL;
auto_save = gconf_client_get_bool (manager->priv->gconf_client,
KEY_AUTOSAVE,
&error);
if (error) {
g_warning ("Error retrieving configuration key '%s': %s",
KEY_AUTOSAVE,
error->message);
g_error_free (error);
/* If we fail to query gconf key, disable auto save */
auto_save = FALSE;
}
return auto_save;
}
static void
maybe_save_session (GsmManager *manager)
{
GError *error;
/* 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;
}
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
on_client_end_session_response (GsmClient *client,
gboolean is_ok,
......@@ -1587,6 +1637,10 @@ on_client_end_session_response (GsmClient *client,
manager->priv->query_timeout_id = 0;
}
if (auto_save_is_enabled (manager)) {
maybe_save_session (manager);
}
end_phase (manager);
}
}
......@@ -1599,8 +1653,11 @@ on_xsmp_client_logout_request (GsmXSMPClient *client,
GError *error;
int logout_mode;
logout_mode = (show_dialog) ? GSM_MANAGER_LOGOUT_MODE_NORMAL :
GSM_MANAGER_LOGOUT_MODE_NO_CONFIRMATION;
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);
......@@ -2322,10 +2379,10 @@ request_hibernate (GsmManager *manager)
static void
request_logout (GsmManager *manager,
gboolean forceful)
gboolean forceful_logout)
{
g_debug ("GsmManager: requesting logout");
manager->priv->forceful = forceful;
manager->priv->forceful_logout = forceful_logout;
end_phase (manager);
}
......@@ -2440,20 +2497,19 @@ show_logout_dialog (GsmManager *manager)
static void
user_logout (GsmManager *manager,
gboolean show_confirmation,
gboolean forceful)
gboolean forceful_logout)
{
gboolean logout_prompt;
GConfClient *client;
gboolean logout_prompt;
if (manager->priv->phase >= GSM_MANAGER_PHASE_QUERY_END_SESSION) {
/* Already shutting down, nothing more to do */
return;
}
client = gconf_client_get_default ();
logout_prompt = gconf_client_get_bool (client,
"/apps/gnome-session/options/logout_prompt",
NULL);
g_object_unref (client);
logout_prompt =
gconf_client_get_bool (manager->priv->gconf_client,
"/apps/gnome-session/options/logout_prompt",
NULL);
/* Global settings overides input parameter in order to disable confirmation
* dialog accordingly. If we're shutting down, we always show the confirmation
......@@ -2463,7 +2519,7 @@ user_logout (GsmManager *manager,
if (logout_prompt) {
show_logout_dialog (manager);
} else {
request_logout (manager, forceful);
request_logout (manager, forceful_logout);
}
}
......@@ -2835,9 +2891,9 @@ gsm_manager_is_inhibited (GsmManager *manager,
return TRUE;
}
inhibitor = (GsmInhibitor *)gsm_store_find (manager->priv->inhibitors,
(GsmStoreFunc)inhibitor_has_flag,
GUINT_TO_POINTER (flags));
inhibitor = (GsmInhibitor *) gsm_store_find (manager->priv->inhibitors,
(GsmStoreFunc)inhibitor_has_flag,
GUINT_TO_POINTER (flags));
if (inhibitor == NULL) {
*is_inhibited = FALSE;
} else {
......@@ -2886,7 +2942,9 @@ gsm_manager_get_inhibitors (GsmManager *manager,
}
*inhibitors = g_ptr_array_new ();
gsm_store_foreach (manager->priv->inhibitors, (GsmStoreFunc)listify_store_ids, inhibitors);
gsm_store_foreach (manager->priv->inhibitors,
(GsmStoreFunc) listify_store_ids,
inhibitors);
return TRUE;
}
......@@ -2916,7 +2974,10 @@ gsm_manager_is_autostart_condition_handled (GsmManager *manager,
g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
app = (GsmApp *)gsm_store_find (manager->priv->apps, (GsmStoreFunc)_app_has_autostart_condition, (char *)condition);
app = (GsmApp *) gsm_store_find (manager->priv->apps,(
GsmStoreFunc) _app_has_autostart_condition,
(char *)condition);
if (app != NULL) {
*handled = TRUE;
} else {
......@@ -3030,40 +3091,3 @@ gsm_manager_add_autostart_apps_from_dir (GsmManager *manager,
return TRUE;
}
gboolean
gsm_manager_add_legacy_session_apps (GsmManager *manager,
const char *path)
{
GKeyFile *saved;
int num_clients;
int i;
g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
g_return_val_if_fail (path != NULL, FALSE);
saved = g_key_file_new ();
if (!g_key_file_load_from_file (saved, path, 0, NULL)) {
/* FIXME: error handling? */
g_key_file_free (saved);
return FALSE;
}
num_clients = g_key_file_get_integer (saved,
"Default",
"num_clients",
NULL);
for (i = 0; i < num_clients; i++) {
GsmApp *app;
app = gsm_resumed_app_new_from_legacy_session (saved, i);
if (app != NULL) {
append_app (manager, app);
g_object_unref (app);
}
}
g_key_file_free (saved);
return TRUE;
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 Novell, Inc.
* Copyright (C) 2008 Red Hat, Inc.
*
* 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.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <sys/wait.h>
#include <glib.h>
#include <X11/SM/SMlib.h>
#include "gsm-resumed-app.h"
#define GSM_RESUMED_APP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_RESUMED_APP, GsmResumedAppPrivate))
struct _GsmResumedAppPrivate
{
char *program;
char *restart_command;
char *discard_command;
gboolean discard_on_resume;
GPid pid;
guint child_watch_id;
};
G_DEFINE_TYPE (GsmResumedApp, gsm_resumed_app, GSM_TYPE_APP)
static void
gsm_resumed_app_init (GsmResumedApp *app)
{
app->priv = GSM_RESUMED_APP_GET_PRIVATE (app);
}
static void
app_exited (GPid pid,
int status,
GsmResumedApp *app)
{
g_debug ("GsmResumedApp: (pid:%d) done (%s:%d)",
(int) pid,
WIFEXITED (status) ? "status"
: WIFSIGNALED (status) ? "signal"
: "unknown",
WIFEXITED (status) ? WEXITSTATUS (status)
: WIFSIGNALED (status) ? WTERMSIG (status)
: -1);
g_spawn_close_pid (app->priv->pid);
app->priv->pid = -1;
app->priv->child_watch_id = 0;
if (WIFEXITED (status)) {
gsm_app_exited (GSM_APP (app));
} else if (WIFSIGNALED (status)) {
gsm_app_died (GSM_APP (app));
}
}
static gboolean
gsm_resumed_app_start (GsmApp *app,
GError **error)
{
const char *restart_command;
int argc;
char **argv;
gboolean success;
gboolean res;
pid_t pid;
GsmResumedApp *rapp;
rapp = GSM_RESUMED_APP (app);
restart_command = rapp->priv->restart_command;
if (restart_command == NULL) {
return FALSE;
}
res = g_shell_parse_argv (restart_command, &argc, &argv, error);
if (!res) {
return FALSE;
}
/* In theory, we should set up the environment according to
* SmEnvironment, and the current directory according to
* SmCurrentDirectory. However, ksmserver doesn't support either of
* those properties, so apps that want to be portable can't depend
* on them working anyway. Also, no one ever uses them. So we just
* ignore them.
*/
success = g_spawn_async (NULL,
argv,
NULL,
G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
NULL,
NULL,
&pid,
error);
g_strfreev (argv);
if (success) {
g_debug ("GsmResumedApp: started pid:%d",
rapp->priv->pid);
rapp->priv->child_watch_id = g_child_watch_add (rapp->priv->pid,
(GChildWatchFunc)app_exited,
app);
}
return success;
}
static gboolean
gsm_resumed_app_restart (GsmApp *app,
GError **error)
{
GError *local_error;
gboolean res;
local_error = NULL;
res = gsm_app_stop (app, &local_error);
if (! res) {
g_propagate_error (error, local_error);
return FALSE;
}
res = gsm_app_start (app, &local_error);
if (! res) {
g_propagate_error (error, local_error);
return FALSE;
}
return TRUE;
}
static const char *
gsm_resumed_app_get_app_id (GsmApp *app)
{
return GSM_RESUMED_APP (app)->priv->program;
}
static void
gsm_resumed_app_dispose (GObject *object)
{
GsmResumedAppPrivate *priv;
priv = GSM_RESUMED_APP (object)->priv;
g_free (priv->program);
priv->program = NULL;
g_free (priv->restart_command);
priv->restart_command = NULL;
g_free (priv->discard_command);
priv->discard_command = NULL;
if (priv->child_watch_id > 0) {
g_source_remove (priv->child_watch_id);
priv->child_watch_id = 0;
}
G_OBJECT_CLASS (gsm_resumed_app_parent_class)->dispose (object);
}
static void
gsm_resumed_app_class_init (GsmResumedAppClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GsmAppClass *app_class = GSM_APP_CLASS (klass);
object_class->dispose = gsm_resumed_app_dispose;
app_class->impl_get_app_id = gsm_resumed_app_get_app_id;
app_class->impl_start = gsm_resumed_app_start;
app_class->impl_restart = gsm_resumed_app_restart;
g_type_class_add_private (klass, sizeof (GsmResumedAppPrivate));
}
/**
* gsm_resumed_app_new_from_legacy_session:
* @session_file: a session file (eg, ~/.gnome2/session) from the old
* gnome-session
* @n: the number of the client in @session_file to read
*
* Creates a new #GsmApp corresponding to the indicated client in
* a legacy session file.
*
* Return value: the new #GsmApp, or %NULL if the @n'th entry in
* @session_file is not actually a saved XSMP client.
**/
GsmApp *
gsm_resumed_app_new_from_legacy_session (GKeyFile *session_file,
int n)
{
GsmResumedApp *app;
char *key;
char *id;
char *val;
key = g_strdup_printf ("%d,id", n);
id = g_key_file_get_string (session_file, "Default", key, NULL);
g_free (key);
if (!id) {
/* Not actually a saved app, just a redundantly-specified
* autostart app; ignore.
*/
return NULL;
}
app = g_object_new (GSM_TYPE_RESUMED_APP,
"startup-id", id,
NULL);
g_free (id);
key = g_strdup_printf ("%d," SmProgram, n);
val = g_key_file_get_string (session_file, "Default", key, NULL);
g_free (key);
if (val) {
app->priv->program = val;
}
key = g_strdup_printf ("%d," SmRestartCommand, n);
val = g_key_file_get_string (session_file, "Default", key, NULL);
g_free (key);
if (val) {
app->priv->restart_command = val;
}
/* We ignore the discard_command on apps resumed from the legacy
* session, so that the legacy session will still work if the user
* reverts back to the old gnome-session.
*/
app->priv->discard_on_resume = FALSE;
return (GsmApp *) app;
}
/* -*- 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 <glib.h>
#include <glib/gstdio.h>
#include "gsm-util.h"
#include "gsm-client.h"
#include "gsm-session-save.h"