From 5e8c5967d65f61a58241c6429eb79650870fa7d0 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 27 Nov 2017 15:40:54 -0500
Subject: [PATCH 1/2] save: make sure app state is written into desktop file
There are a number of important bits of app state written into
an applications desktop file that needs to be restored when
the session is saved. For instance, the phase in which the client
should get started.
That state is currently stored on the GsmApp object, which is
inaccessible, from the client save function.
This commit adds the neccesary plumbing to route the GsmApp object
associated with a client to the client save function, and also
adds code to allow the app object to augment the client keyfile at
save time.
https://bugzilla.gnome.org/show_bug.cgi?id=790913
https://bugzilla.redhat.com/show_bug.cgi?id=1529175
---
gnome-session/gsm-app.c | 9 +++++
gnome-session/gsm-app.h | 8 +++++
gnome-session/gsm-autostart-app.c | 70 +++++++++++++++++++++++++++++++++++++++
gnome-session/gsm-client.c | 3 +-
gnome-session/gsm-client.h | 3 ++
gnome-session/gsm-dbus-client.c | 1 +
gnome-session/gsm-manager.c | 4 +--
gnome-session/gsm-session-save.c | 41 +++++++++++++++++------
gnome-session/gsm-session-save.h | 1 +
gnome-session/gsm-xsmp-client.c | 9 +++++
10 files changed, 135 insertions(+), 14 deletions(-)
diff --git a/gnome-session/gsm-app.c b/gnome-session/gsm-app.c
index 845e067a..d1ef89a8 100644
--- a/gnome-session/gsm-app.c
+++ b/gnome-session/gsm-app.c
@@ -531,30 +531,39 @@ gsm_app_exited (GsmApp *app,
}
void
gsm_app_died (GsmApp *app,
int signal)
{
g_return_if_fail (GSM_IS_APP (app));
g_signal_emit (app, signals[DIED], 0, signal);
}
gboolean
gsm_app_get_registered (GsmApp *app)
{
g_return_val_if_fail (GSM_IS_APP (app), FALSE);
return app->priv->registered;
}
void
gsm_app_set_registered (GsmApp *app,
gboolean registered)
{
g_return_if_fail (GSM_IS_APP (app));
if (app->priv->registered != registered) {
app->priv->registered = registered;
g_object_notify (G_OBJECT (app), "registered");
}
}
+
+gboolean
+gsm_app_save_to_keyfile (GsmApp *app,
+ GKeyFile *keyfile,
+ GError **error)
+{
+ g_debug ("Saving app: %s", app->priv->id);
+ return GSM_APP_GET_CLASS (app)->impl_save_to_keyfile (app, keyfile, error);
+}
diff --git a/gnome-session/gsm-app.h b/gnome-session/gsm-app.h
index 14a9f94b..f38b3be4 100644
--- a/gnome-session/gsm-app.h
+++ b/gnome-session/gsm-app.h
@@ -47,80 +47,88 @@ struct _GsmApp
};
struct _GsmAppClass
{
GObjectClass parent_class;
/* signals */
void (*exited) (GsmApp *app,
guchar exit_code);
void (*died) (GsmApp *app,
int signal);
/* virtual methods */
gboolean (*impl_start) (GsmApp *app,
GError **error);
gboolean (*impl_restart) (GsmApp *app,
GError **error);
gboolean (*impl_stop) (GsmApp *app,
GError **error);
gboolean (*impl_provides) (GsmApp *app,
const char *service);
char ** (*impl_get_provides) (GsmApp *app);
gboolean (*impl_has_autostart_condition) (GsmApp *app,
const char *service);
gboolean (*impl_is_running) (GsmApp *app);
gboolean (*impl_get_autorestart) (GsmApp *app);
const char *(*impl_get_app_id) (GsmApp *app);
gboolean (*impl_is_disabled) (GsmApp *app);
gboolean (*impl_is_conditionally_disabled) (GsmApp *app);
+
+ gboolean (*impl_save_to_keyfile) (GsmApp *app,
+ GKeyFile *keyfile,
+ GError **error);
};
typedef enum
{
GSM_APP_ERROR_GENERAL = 0,
GSM_APP_ERROR_RESTART_LIMIT,
GSM_APP_ERROR_START,
GSM_APP_ERROR_STOP,
GSM_APP_NUM_ERRORS
} GsmAppError;
#define GSM_APP_ERROR gsm_app_error_quark ()
GQuark gsm_app_error_quark (void);
GType gsm_app_get_type (void) G_GNUC_CONST;
gboolean gsm_app_peek_autorestart (GsmApp *app);
const char *gsm_app_peek_id (GsmApp *app);
const char *gsm_app_peek_app_id (GsmApp *app);
const char *gsm_app_peek_startup_id (GsmApp *app);
GsmManagerPhase gsm_app_peek_phase (GsmApp *app);
gboolean gsm_app_peek_is_disabled (GsmApp *app);
gboolean gsm_app_peek_is_conditionally_disabled (GsmApp *app);
gboolean gsm_app_start (GsmApp *app,
GError **error);
gboolean gsm_app_restart (GsmApp *app,
GError **error);
gboolean gsm_app_stop (GsmApp *app,
GError **error);
gboolean gsm_app_is_running (GsmApp *app);
void gsm_app_exited (GsmApp *app,
guchar exit_code);
void gsm_app_died (GsmApp *app,
int signal);
gboolean gsm_app_provides (GsmApp *app,
const char *service);
char **gsm_app_get_provides (GsmApp *app);
gboolean gsm_app_has_autostart_condition (GsmApp *app,
const char *condition);
gboolean gsm_app_get_registered (GsmApp *app);
void gsm_app_set_registered (GsmApp *app,
gboolean registered);
+gboolean gsm_app_save_to_keyfile (GsmApp *app,
+ GKeyFile *keyfile,
+ GError **error);
+
G_END_DECLS
#endif /* __GSM_APP_H__ */
diff --git a/gnome-session/gsm-autostart-app.c b/gnome-session/gsm-autostart-app.c
index 870b1516..9eb1db5b 100644
--- a/gnome-session/gsm-autostart-app.c
+++ b/gnome-session/gsm-autostart-app.c
@@ -1400,86 +1400,156 @@ gsm_autostart_app_get_autorestart (GsmApp *app)
static const char *
gsm_autostart_app_get_app_id (GsmApp *app)
{
if (GSM_AUTOSTART_APP (app)->priv->app_info == NULL) {
return NULL;
}
return g_app_info_get_id (G_APP_INFO (GSM_AUTOSTART_APP (app)->priv->app_info));
}
static gboolean
gsm_autostart_app_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
GsmAutostartApp *app = GSM_AUTOSTART_APP (initable);
g_assert (app->priv->desktop_filename != NULL);
app->priv->app_info = g_desktop_app_info_new_from_filename (app->priv->desktop_filename);
if (app->priv->app_info == NULL) {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Could not parse desktop file %s or it references a not found TryExec binary", app->priv->desktop_id);
return FALSE;
}
load_desktop_file (app);
return TRUE;
}
+static gboolean
+gsm_autostart_app_save_to_keyfile (GsmApp *base_app,
+ GKeyFile *keyfile,
+ GError **error)
+{
+ GsmAutostartApp *app = GSM_AUTOSTART_APP (base_app);
+ char **provides = NULL;
+ char *dbus_name;
+ char *phase;
+ gboolean res;
+
+ provides = gsm_app_get_provides (base_app);
+ if (provides != NULL) {
+ g_key_file_set_string_list (keyfile,
+ G_KEY_FILE_DESKTOP_GROUP,
+ GSM_AUTOSTART_APP_PROVIDES_KEY,
+ (const char * const *)
+ provides,
+ g_strv_length (provides));
+ g_strfreev (provides);
+ }
+
+ phase = g_desktop_app_info_get_string (app->priv->app_info,
+ GSM_AUTOSTART_APP_PHASE_KEY);
+ if (phase != NULL) {
+ g_key_file_set_string (keyfile,
+ G_KEY_FILE_DESKTOP_GROUP,
+ GSM_AUTOSTART_APP_PHASE_KEY,
+ phase);
+ g_free (phase);
+ }
+
+ dbus_name = g_desktop_app_info_get_string (app->priv->app_info,
+ GSM_AUTOSTART_APP_DBUS_NAME_KEY);
+ if (dbus_name != NULL) {
+ g_key_file_set_string (keyfile,
+ G_KEY_FILE_DESKTOP_GROUP,
+ GSM_AUTOSTART_APP_DBUS_NAME_KEY,
+ dbus_name);
+ g_free (dbus_name);
+ }
+
+ res = g_desktop_app_info_has_key (app->priv->app_info,
+ GSM_AUTOSTART_APP_AUTORESTART_KEY);
+ if (res) {
+ g_key_file_set_boolean (keyfile,
+ G_KEY_FILE_DESKTOP_GROUP,
+ GSM_AUTOSTART_APP_AUTORESTART_KEY,
+ g_desktop_app_info_get_boolean (app->priv->app_info,
+ GSM_AUTOSTART_APP_AUTORESTART_KEY));
+ }
+
+ res = g_desktop_app_info_has_key (app->priv->app_info,
+ GSM_AUTOSTART_APP_AUTORESTART_KEY);
+ if (res) {
+ char *autostart_condition;
+
+ autostart_condition = g_desktop_app_info_get_string (app->priv->app_info, "AutostartCondition");
+
+ g_key_file_set_string (keyfile,
+ G_KEY_FILE_DESKTOP_GROUP,
+ "AutostartCondition",
+ autostart_condition);
+ g_free (autostart_condition);
+ }
+
+ return TRUE;
+}
+
static void
gsm_autostart_app_initable_iface_init (GInitableIface *iface)
{
iface->init = gsm_autostart_app_initable_init;
}
static void
gsm_autostart_app_class_init (GsmAutostartAppClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GsmAppClass *app_class = GSM_APP_CLASS (klass);
object_class->set_property = gsm_autostart_app_set_property;
object_class->get_property = gsm_autostart_app_get_property;
object_class->dispose = gsm_autostart_app_dispose;
app_class->impl_is_disabled = is_disabled;
app_class->impl_is_conditionally_disabled = is_conditionally_disabled;
app_class->impl_is_running = is_running;
app_class->impl_start = gsm_autostart_app_start;
app_class->impl_restart = gsm_autostart_app_restart;
app_class->impl_stop = gsm_autostart_app_stop;
app_class->impl_provides = gsm_autostart_app_provides;
app_class->impl_get_provides = gsm_autostart_app_get_provides;
app_class->impl_has_autostart_condition = gsm_autostart_app_has_autostart_condition;
app_class->impl_get_app_id = gsm_autostart_app_get_app_id;
app_class->impl_get_autorestart = gsm_autostart_app_get_autorestart;
+ app_class->impl_save_to_keyfile = gsm_autostart_app_save_to_keyfile;
g_object_class_install_property (object_class,
PROP_DESKTOP_FILENAME,
g_param_spec_string ("desktop-filename",
"Desktop filename",
"Freedesktop .desktop file",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
signals[CONDITION_CHANGED] =
g_signal_new ("condition-changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GsmAutostartAppClass, condition_changed),
NULL, NULL, NULL,
G_TYPE_NONE,
1,
G_TYPE_BOOLEAN);
g_type_class_add_private (object_class, sizeof (GsmAutostartAppPrivate));
}
GsmApp *
gsm_autostart_app_new (const char *desktop_file,
GError **error)
{
return (GsmApp*) g_initable_new (GSM_TYPE_AUTOSTART_APP, NULL, error,
"desktop-filename", desktop_file,
NULL);
}
diff --git a/gnome-session/gsm-client.c b/gnome-session/gsm-client.c
index 7b78d9e1..3f216b22 100644
--- a/gnome-session/gsm-client.c
+++ b/gnome-session/gsm-client.c
@@ -526,47 +526,48 @@ gsm_client_end_session (GsmClient *client,
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,
+ GsmApp *app,
GError **error)
{
g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
- return GSM_CLIENT_GET_CLASS (client)->impl_save (client, error);
+ return GSM_CLIENT_GET_CLASS (client)->impl_save (client, app, 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 f79896b3..19c9cd8d 100644
--- a/gnome-session/gsm-client.h
+++ b/gnome-session/gsm-client.h
@@ -6,60 +6,61 @@
* 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_CLIENT_H__
#define __GSM_CLIENT_H__
#include <glib.h>
#include <glib-object.h>
#include <sys/types.h>
G_BEGIN_DECLS
#define GSM_TYPE_CLIENT (gsm_client_get_type ())
#define GSM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSM_TYPE_CLIENT, GsmClient))
#define GSM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSM_TYPE_CLIENT, GsmClientClass))
#define GSM_IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSM_TYPE_CLIENT))
#define GSM_IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSM_TYPE_CLIENT))
#define GSM_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSM_TYPE_CLIENT, GsmClientClass))
+typedef struct _GsmApp GsmApp;
typedef struct _GsmClient GsmClient;
typedef struct _GsmClientClass GsmClientClass;
typedef struct GsmClientPrivate GsmClientPrivate;
typedef enum {
GSM_CLIENT_UNREGISTERED = 0,
GSM_CLIENT_REGISTERED,
GSM_CLIENT_FINISHED,
GSM_CLIENT_FAILED
} GsmClientStatus;
typedef enum {
GSM_CLIENT_RESTART_NEVER = 0,
GSM_CLIENT_RESTART_IF_RUNNING,
GSM_CLIENT_RESTART_ANYWAY,
GSM_CLIENT_RESTART_IMMEDIATELY
} GsmClientRestartStyle;
typedef enum {
GSM_CLIENT_END_SESSION_FLAG_FORCEFUL = 1 << 0,
GSM_CLIENT_END_SESSION_FLAG_SAVE = 1 << 1,
GSM_CLIENT_END_SESSION_FLAG_LAST = 1 << 2
} GsmClientEndSessionFlag;
struct _GsmClient
{
GObject parent;
GsmClientPrivate *priv;
};
@@ -67,91 +68,93 @@ struct _GsmClient
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,
+ GsmApp *app,
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 ()
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,
+ GsmApp *app,
GError **error);
gboolean gsm_client_stop (GsmClient *client,
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
#endif /* __GSM_CLIENT_H__ */
diff --git a/gnome-session/gsm-dbus-client.c b/gnome-session/gsm-dbus-client.c
index 050ea18f..5793f830 100644
--- a/gnome-session/gsm-dbus-client.c
+++ b/gnome-session/gsm-dbus-client.c
@@ -315,60 +315,61 @@ gsm_dbus_client_finalize (GObject *object)
if (client->priv->skeleton != NULL) {
g_dbus_interface_skeleton_unexport_from_connection (G_DBUS_INTERFACE_SKELETON (client->priv->skeleton),
client->priv->connection);
g_clear_object (&client->priv->skeleton);
}
g_clear_object (&client->priv->connection);
if (client->priv->watch_id != 0)
g_bus_unwatch_name (client->priv->watch_id);
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,
+ GsmApp *app,
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;
gsm_exported_client_private_emit_stop (dbus_client->priv->skeleton);
return TRUE;
}
static char *
dbus_client_get_app_name (GsmClient *client)
{
/* Always use app-id instead */
return NULL;
}
static GsmClientRestartStyle
dbus_client_get_restart_style_hint (GsmClient *client)
{
diff --git a/gnome-session/gsm-manager.c b/gnome-session/gsm-manager.c
index 29c3054d..e7f0d7f8 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, manager->priv->session_name, &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;
@@ -1963,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->session_name, &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-session-save.c b/gnome-session/gsm-session-save.c
index 78b64197..35ffaae0 100644
--- a/gnome-session/gsm-session-save.c
+++ b/gnome-session/gsm-session-save.c
@@ -1,234 +1,253 @@
/* -*- 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;
- keyfile = gsm_client_save (client, &local_error);
+ app_id = gsm_client_peek_app_id (client);
+ if (!IS_STRING_EMPTY (app_id)) {
+ if (g_str_has_suffix (app_id, ".desktop"))
+ filename = g_strdup (app_id);
+ else
+ filename = g_strdup_printf ("%s.desktop", app_id);
+
+ path = g_build_filename (data->dir, filename, NULL);
+
+ app = (GsmApp *)gsm_store_find (data->app_store,
+ (GsmStoreFunc)_app_has_app_id,
+ (char *)app_id);
+ }
+ keyfile = gsm_client_save (client, app, &local_error);
if (keyfile == NULL || local_error) {
goto out;
}
contents = g_key_file_to_data (keyfile, &length, &local_error);
if (local_error) {
goto out;
}
- app_id = gsm_client_peek_app_id (client);
- if (!IS_STRING_EMPTY (app_id)) {
- if (g_str_has_suffix (app_id, ".desktop"))
- filename = g_strdup (app_id);
- else
- filename = g_strdup_printf ("%s.desktop", app_id);
-
- path = g_build_filename (data->dir, filename, NULL);
- }
-
if (!path || g_file_test (path, G_FILE_TEST_EXISTS)) {
if (filename)
g_free (filename);
if (path)
g_free (path);
filename = g_strdup_printf ("%s.desktop",
gsm_client_peek_startup_id (client));
path = g_build_filename (data->dir, filename, NULL);
}
g_file_set_contents (path,
contents,
length,
&local_error);
if (local_error) {
goto out;
}
discard_exec = g_key_file_get_string (keyfile,
G_KEY_FILE_DESKTOP_GROUP,
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,
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;
+ data.app_store = app_store;
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 */
diff --git a/gnome-session/gsm-session-save.h b/gnome-session/gsm-session-save.h
index c91b5615..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,
const char *type,
GError **error);
void gsm_session_save_clear (void);
G_END_DECLS
#endif /* __GSM_SESSION_SAVE_H__ */
diff --git a/gnome-session/gsm-xsmp-client.c b/gnome-session/gsm-xsmp-client.c
index 2846d9b3..cbecd68c 100644
--- a/gnome-session/gsm-xsmp-client.c
+++ b/gnome-session/gsm-xsmp-client.c
@@ -612,118 +612,127 @@ set_desktop_file_keys_from_client (GsmClient *client,
g_free (comment);
}
static GKeyFile *
create_client_key_file (GsmClient *client,
const char *desktop_file_path,
GError **error) {
GKeyFile *keyfile;
keyfile = g_key_file_new ();
if (desktop_file_path != NULL) {
g_key_file_load_from_file (keyfile,
desktop_file_path,
G_KEY_FILE_KEEP_COMMENTS |
G_KEY_FILE_KEEP_TRANSLATIONS,
error);
} else {
set_desktop_file_keys_from_client (client, keyfile);
}
return keyfile;
}
static GsmClientRestartStyle
xsmp_get_restart_style_hint (GsmClient *client);
static GKeyFile *
xsmp_save (GsmClient *client,
+ GsmApp *app,
GError **error)
{
GsmClientRestartStyle restart_style;
GKeyFile *keyfile = NULL;
char *desktop_file_path = NULL;
char *exec_program = NULL;
char *exec_discard = NULL;
char *startup_id = NULL;
GError *local_error;
g_debug ("GsmXSMPClient: saving client with id %s",
gsm_client_peek_id (client));
local_error = NULL;
restart_style = xsmp_get_restart_style_hint (client);
if (restart_style == GSM_CLIENT_RESTART_NEVER) {
goto out;
}
exec_program = xsmp_get_restart_command (client);
if (!exec_program) {
goto out;
}
desktop_file_path = get_desktop_file_path (GSM_XSMP_CLIENT (client));
/* this can accept desktop_file_path == NULL */
keyfile = create_client_key_file (client,
desktop_file_path,
&local_error);
if (local_error) {
goto out;
}
g_object_get (client,
"startup-id", &startup_id,
NULL);
g_key_file_set_string (keyfile,
G_KEY_FILE_DESKTOP_GROUP,
GSM_AUTOSTART_APP_STARTUP_ID_KEY,
startup_id);
g_key_file_set_string (keyfile,
G_KEY_FILE_DESKTOP_GROUP,
G_KEY_FILE_DESKTOP_KEY_EXEC,
exec_program);
exec_discard = xsmp_get_discard_command (client);
if (exec_discard)
g_key_file_set_string (keyfile,
G_KEY_FILE_DESKTOP_GROUP,
GSM_AUTOSTART_APP_DISCARD_KEY,
exec_discard);
+ if (app != NULL) {
+ gsm_app_save_to_keyfile (app, keyfile, &local_error);
+
+ if (local_error) {
+ goto out;
+ }
+ }
+
out:
g_free (desktop_file_path);
g_free (exec_program);
g_free (exec_discard);
g_free (startup_id);
if (local_error != NULL) {
g_propagate_error (error, local_error);
g_key_file_free (keyfile);
return NULL;
}
return keyfile;
}
static gboolean
xsmp_stop (GsmClient *client,
GError **error)
{
GsmXSMPClient *xsmp = (GsmXSMPClient *) client;
g_debug ("GsmXSMPClient: xsmp_stop ('%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;
--
2.14.3