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.
1186 lines
44 KiB
1186 lines
44 KiB
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 |
|
|
|
|