Commit 3e346957 authored by Vincent Untz's avatar Vincent Untz Committed by Vincent Untz

Rework deeply the code that writes the saved session to desktop files: we

2009-03-24  Vincent Untz  <vuntz@gnome.org>

	Rework deeply the code that writes the saved session to desktop files:
	we now properly discard a client when removing it; we also make sure we
	save the current session before we completely remove the previously
	saved session (to be on the safe side).
	Note that we only discard a client when the new saved session doesn't
	use the same discard command: for example, when metacity saves its
	state, it will reuse the same discard command and so we can't discard
	the old metacity client (it would discard the new client).

	* gnome-session/gsm-util.[ch]: (gsm_util_get_empty_tmp_session_dir):
	new function to get a temporary directory where to save the new
	session, while we still keep the previously saved session. It also
	makes sure the directory is empty.
	* gnome-session/gsm-session-save.[ch]: (save_one_client): update to
	make sure we remember the discard command from the client.
	(gsm_session_save): rework to first save the session in the temporary
	directory (and remember the discard commands from the saved clients),
	and then clear the old session. We finish by renaming the temporary
	directory to its final name.
	(gsm_session_clear_one_client): new, to properly clear one client from
	a saved session. We unlink the desktop file, but also run the discard
	command if it's not used by any other client from the newly saved
	session.
	(gsm_session_clear_saved_session): change to clear a saved session in a
	specified directory, and use gsm_session_clear_one_client() instead of
	just unlinking the desktop file. Also add missing g_dir_close().

svn path=/trunk/; revision=5355
parent 7266a73b
2009-03-24 Vincent Untz <vuntz@gnome.org>
Rework deeply the code that writes the saved session to desktop files:
we now properly discard a client when removing it; we also make sure we
save the current session before we completely remove the previously
saved session (to be on the safe side).
Note that we only discard a client when the new saved session doesn't
use the same discard command: for example, when metacity saves its
state, it will reuse the same discard command and so we can't discard
the old metacity client (it would discard the new client).
* gnome-session/gsm-util.[ch]: (gsm_util_get_empty_tmp_session_dir):
new function to get a temporary directory where to save the new
session, while we still keep the previously saved session. It also
makes sure the directory is empty.
* gnome-session/gsm-session-save.[ch]: (save_one_client): update to
make sure we remember the discard command from the client.
(gsm_session_save): rework to first save the session in the temporary
directory (and remember the discard commands from the saved clients),
and then clear the old session. We finish by renaming the temporary
directory to its final name.
(gsm_session_clear_one_client): new, to properly clear one client from
a saved session. We unlink the desktop file, but also run the discard
command if it's not used by any other client from the newly saved
session.
(gsm_session_clear_saved_session): change to clear a saved session in a
specified directory, and use gsm_session_clear_one_client() instead of
just unlinking the desktop file. Also add missing g_dir_close().
2009-03-24 Vincent Untz <vuntz@gnome.org>
* gnome-session/gsm-xsmp-client.c: (xsmp_save): just don't return a
......
......@@ -28,18 +28,27 @@
#include "gsm-session-save.h"
static gboolean gsm_session_clear_saved_session (const char *directory,
GHashTable *discard_hash);
typedef struct {
char *dir;
GHashTable *discard_hash;
GError **error;
} SessionSaveData;
static gboolean
save_one_client (char *id,
GObject *object,
GError **error)
save_one_client (char *id,
GObject *object,
SessionSaveData *data)
{
GsmClient *client;
GKeyFile *keyfile;
char *path = NULL;
char *filename = NULL;
char *contents = NULL;
const char *saved_session_dir;
gsize length = 0;
char *discard_exec;
GError *local_error;
client = GSM_CLIENT (object);
......@@ -58,16 +67,10 @@ save_one_client (char *id,
goto out;
}
saved_session_dir = gsm_util_get_saved_session_dir ();
if (saved_session_dir == NULL) {
goto out;
}
filename = g_strdup_printf ("%s.desktop",
gsm_client_peek_startup_id (client));
path = g_build_filename (saved_session_dir, filename, NULL);
path = g_build_filename (data->dir, filename, NULL);
g_file_set_contents (path,
contents,
......@@ -78,6 +81,15 @@ save_one_client (char *id,
goto out;
}
discard_exec = g_key_file_get_string (keyfile,
G_KEY_FILE_DESKTOP_GROUP,
"X-GNOME-Autostart-discard-exec",
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:
......@@ -91,7 +103,7 @@ out:
/* in case of any error, stop saving session */
if (local_error) {
g_propagate_error (error, local_error);
g_propagate_error (data->error, local_error);
g_error_free (local_error);
return TRUE;
......@@ -104,39 +116,121 @@ void
gsm_session_save (GsmStore *client_store,
GError **error)
{
gsm_session_clear_saved_session ();
const char *save_dir;
char *tmp_dir;
SessionSaveData data;
g_debug ("GsmSessionSave: Saving session");
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,
error);
&data);
if (!*error) {
/* remove the old saved session */
gsm_session_clear_saved_session (save_dir, data.discard_hash);
if (*error) {
/* 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);
gsm_session_clear_saved_session ();
/* 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,
"X-GNOME-Autostart-discard-exec",
NULL);
if (!discard_exec)
goto out;
if (g_hash_table_lookup (discard_hash, discard_exec))
goto out;
if (!g_shell_parse_argv (discard_exec, &argc, &argv, NULL))
goto out;
result = g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
NULL, NULL, NULL, NULL) && result;
g_strfreev (argv);
} else {
result = FALSE;
}
out:
if (key_file)
g_key_file_free (key_file);
if (discard_exec)
g_free (discard_exec);
result = (g_unlink (filename) == 0) && result;
return result;
}
gboolean
gsm_session_clear_saved_session ()
static gboolean
gsm_session_clear_saved_session (const char *directory,
GHashTable *discard_hash)
{
GDir *dir;
const char *saved_session_dir;
const char *filename;
gboolean result = TRUE;
GError *error;
saved_session_dir = gsm_util_get_saved_session_dir ();
g_debug ("GsmSessionSave: clearing currectly saved session at %s", saved_session_dir);
g_debug ("GsmSessionSave: clearing currectly saved session at %s",
directory);
if (saved_session_dir == NULL) {
if (directory == NULL) {
return FALSE;
}
error = NULL;
dir = g_dir_open (saved_session_dir, 0, &error);
dir = g_dir_open (directory, 0, &error);
if (error) {
g_warning ("GsmSessionSave: error loading saved session directory: %s", error->message);
g_error_free (error);
......@@ -144,15 +238,16 @@ gsm_session_clear_saved_session ()
}
while ((filename = g_dir_read_name (dir))) {
char *path = g_build_filename (saved_session_dir,
char *path = g_build_filename (directory,
filename, NULL);
g_debug ("GsmSessionSave: removing '%s' from saved session", path);
result = result && (g_unlink (path) == 0);
result = gsm_session_clear_one_client (path, discard_hash)
&& result;
g_free (path);
}
g_dir_close (dir);
return result;
}
......@@ -29,8 +29,6 @@ G_BEGIN_DECLS
void gsm_session_save (GsmStore *client_store,
GError **error);
gboolean gsm_session_clear_saved_session (void);
G_END_DECLS
#endif /* __GSM_SESSION_SAVE_H__ */
......@@ -139,6 +139,42 @@ ensure_dir_exists (const char *dir)
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))) {
char *path = g_build_filename (tmp, filename,
NULL);
g_unlink (path);
}
g_dir_close (dir);
}
}
return tmp;
}
const gchar *
gsm_util_get_saved_session_dir (void)
{
......
......@@ -27,6 +27,8 @@ G_BEGIN_DECLS
char * gsm_util_find_desktop_file_for_app_name (const char *app_name,
char **dirs);
gchar *gsm_util_get_empty_tmp_session_dir (void);
const char *gsm_util_get_saved_session_dir (void);
gchar** gsm_util_get_app_dirs (void);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment