From ade647861a671eca584d25432722ac2661854748 Mon Sep 17 00:00:00 2001
From: Josselin Mouette <joss@malsain.org>
Date: Mon, 21 Jun 2010 15:22:23 -0400
Subject: [PATCH 08/19] Add "Remember Currently Running Applications" button
This adds back session saving that's not at logout.
---
capplet/gsm-properties-dialog.c | 63 ++++++++-
capplet/meson.build | 3 +-
data/session-properties.ui | 12 ++
gnome-session/gsm-client.c | 10 ++
gnome-session/gsm-client.h | 6 +
gnome-session/gsm-dbus-client.c | 14 ++
gnome-session/gsm-manager.c | 150 ++++++++++++++++++++-
gnome-session/gsm-manager.h | 3 +
gnome-session/gsm-xsmp-client.c | 37 +++++
gnome-session/gsm-xsmp-client.h | 3 +-
gnome-session/org.gnome.SessionManager.xml | 8 ++
meson.build | 1 +
12 files changed, 305 insertions(+), 5 deletions(-)
diff --git a/capplet/gsm-properties-dialog.c b/capplet/gsm-properties-dialog.c
index 33812b8b..d2be778b 100644
--- a/capplet/gsm-properties-dialog.c
+++ b/capplet/gsm-properties-dialog.c
@@ -5,70 +5,77 @@
* Copyright (C) 2008 Lucas Rocha.
* Copyright (C) 2008 William Jon McCann <jmccann@redhat.com>
*
* 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 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/gi18n.h>
#include <gtk/gtk.h>
#include "gsm-properties-dialog.h"
#include "gsm-app-dialog.h"
#include "gsm-util.h"
#include "gsp-app.h"
#include "gsp-app-manager.h"
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#define GSM_SERVICE_DBUS "org.gnome.SessionManager"
+#define GSM_PATH_DBUS "/org/gnome/SessionManager"
+#define GSM_INTERFACE_DBUS "org.gnome.SessionManager"
#define GSM_PROPERTIES_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_PROPERTIES_DIALOG, GsmPropertiesDialogPrivate))
#define GTKBUILDER_FILE "session-properties.ui"
#define CAPPLET_TREEVIEW_WIDGET_NAME "session_properties_treeview"
#define CAPPLET_ADD_WIDGET_NAME "session_properties_add_button"
#define CAPPLET_DELETE_WIDGET_NAME "session_properties_delete_button"
#define CAPPLET_EDIT_WIDGET_NAME "session_properties_edit_button"
#define CAPPLET_SAVE_WIDGET_NAME "session_properties_save_button"
+#define CAPPLET_SESSION_SAVED_WIDGET_NAME "session_properties_session_saved_label"
#define CAPPLET_REMEMBER_WIDGET_NAME "session_properties_remember_toggle"
#define STARTUP_APP_ICON "system-run"
#define SPC_SETTINGS_SCHEMA "org.gnome.SessionManager"
#define SPC_SETTINGS_AUTOSAVE_KEY "auto-save-session"
struct GsmPropertiesDialogPrivate
{
GtkBuilder *xml;
GtkListStore *list_store;
GtkTreeModel *tree_filter;
GtkTreeView *treeview;
GtkWidget *add_button;
GtkWidget *delete_button;
GtkWidget *edit_button;
GSettings *settings;
GspAppManager *manager;
};
enum {
STORE_COL_VISIBLE = 0,
STORE_COL_ENABLED,
STORE_COL_GICON,
STORE_COL_DESCRIPTION,
STORE_COL_APP,
STORE_COL_SEARCH,
@@ -430,65 +437,119 @@ on_edit_app_clicked (GtkWidget *widget,
char *exec;
char *comment;
edit_dialog = gsm_app_dialog_new (gsp_app_get_name (app),
gsp_app_get_exec (app),
gsp_app_get_comment (app));
gtk_window_set_transient_for (GTK_WINDOW (edit_dialog),
GTK_WINDOW (dialog));
if (gsm_app_dialog_run (GSM_APP_DIALOG (edit_dialog),
&name, &exec, &comment)) {
gsp_app_update (app, name, comment, exec);
g_free (name);
g_free (exec);
g_free (comment);
}
g_object_unref (app);
}
}
static void
on_row_activated (GtkTreeView *tree_view,
GtkTreePath *path,
GtkTreeViewColumn *column,
GsmPropertiesDialog *dialog)
{
on_edit_app_clicked (NULL, dialog);
}
+static void
+session_saved_message (GsmPropertiesDialog *dialog,
+ const char *msg,
+ gboolean is_error)
+{
+ GtkLabel *label;
+ gchar *markup;
+ label = GTK_LABEL (gtk_builder_get_object (dialog->priv->xml, CAPPLET_SESSION_SAVED_WIDGET_NAME));
+ if (is_error)
+ markup = g_markup_printf_escaped ("<span foreground=\"red\">%s</span>", msg);
+ else
+ markup = g_markup_escape_text (msg, -1);
+ gtk_label_set_markup (label, markup);
+ g_free (markup);
+}
+
+static void
+session_saved_cb (DBusGProxy *proxy,
+ DBusGProxyCall *call_id,
+ void *user_data)
+{
+ gboolean res;
+ GsmPropertiesDialog *dialog = user_data;
+
+ res = dbus_g_proxy_end_call (proxy, call_id, NULL, G_TYPE_INVALID);
+ if (res)
+ session_saved_message (dialog, _("Your session has been saved."), FALSE);
+ else
+ session_saved_message (dialog, _("Failed to save session"), TRUE);
+
+ g_object_unref (proxy);
+}
+
static void
on_save_session_clicked (GtkWidget *widget,
GsmPropertiesDialog *dialog)
{
- g_debug ("Session saving is not implemented yet!");
+ DBusGConnection *conn;
+ DBusGProxy *proxy;
+ DBusGProxyCall *call;
+
+ conn = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
+ if (conn == NULL) {
+ session_saved_message (dialog, _("Could not connect to the session bus"), TRUE);
+ return;
+ }
+
+ proxy = dbus_g_proxy_new_for_name (conn, GSM_SERVICE_DBUS, GSM_PATH_DBUS, GSM_INTERFACE_DBUS);
+ if (proxy == NULL) {
+ session_saved_message (dialog, _("Could not connect to the session manager"), TRUE);
+ return;
+ }
+
+ call = dbus_g_proxy_begin_call (proxy, "SaveSession", session_saved_cb, dialog, NULL, G_TYPE_INVALID);
+ if (call == NULL) {
+ session_saved_message (dialog, _("Failed to save session"), TRUE);
+ g_object_unref (proxy);
+ return;
+ }
}
static void
setup_dialog (GsmPropertiesDialog *dialog)
{
GtkTreeView *treeview;
GtkWidget *button;
GtkTreeModel *tree_filter;
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
GtkTreeSelection *selection;
GtkTargetList *targetlist;
gtk_dialog_add_buttons (GTK_DIALOG (dialog),
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
NULL);
dialog->priv->list_store = gtk_list_store_new (NUMBER_OF_COLUMNS,
G_TYPE_BOOLEAN,
G_TYPE_BOOLEAN,
G_TYPE_ICON,
G_TYPE_STRING,
G_TYPE_OBJECT,
G_TYPE_STRING);
tree_filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (dialog->priv->list_store),
NULL);
g_object_unref (dialog->priv->list_store);
dialog->priv->tree_filter = tree_filter;
gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (tree_filter),
diff --git a/capplet/meson.build b/capplet/meson.build
index 8dad9c80..ae6cb6b9 100644
--- a/capplet/meson.build
+++ b/capplet/meson.build
@@ -1,36 +1,37 @@
install_data(
install_dir: session_bindir
)
deps = session_deps + [
glib_dep,
gtk_dep,
x11_dep,
sm_dep,
- ice_dep
+ ice_dep,
+ dbus_glib_dep
]
cflags = [
'-DLOCALE_DIR="@0@"'.format(session_localedir),
'-DGTKBUILDER_DIR="@0@"'.format(session_pkgdatadir)
]
sources = files(
'../gnome-session/gsm-util.c',
'gsm-app-dialog.c',
'gsm-properties-dialog.c',
'gsp-app.c',
'gsp-app-manager.c',
'gsp-keyfile.c',
'main.c'
)
executable(
'gnome-session-properties',
sources,
include_directories: [ top_inc, include_directories('../gnome-session') ],
dependencies: deps,
c_args: cflags,
install: true,
install_dir: session_bindir
)
diff --git a/data/session-properties.ui b/data/session-properties.ui
index 47a30f78..b43759ff 100644
--- a/data/session-properties.ui
+++ b/data/session-properties.ui
@@ -133,108 +133,120 @@
</packing>
</child>
<child>
<object class="GtkVBox" id="vbox3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">12</property>
<property name="spacing">6</property>
<child>
<object class="GtkCheckButton" id="session_properties_remember_toggle">
<property name="label" translatable="yes">_Automatically remember running applications when logging out</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="xalign">0.5</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHButtonBox" id="hbuttonbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="session_properties_save_button">
+ <property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<child>
<object class="GtkHBox" id="hbox2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">4</property>
<child>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-save</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Remember Currently Running Applications</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
+ <child>
+ <object class="GtkLabel" id="session_properties_session_saved_label">
+ <property name="visible">True</property>
+ <property name="wrap">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Options</property>
</object>
<packing>
<property name="position">1</property>
<property name="tab_fill">False</property>
</packing>
</child>
</object>
<object class="GtkTable" id="main-table">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">6</property>
<property name="n_rows">3</property>
<property name="n_columns">2</property>
<property name="column_spacing">12</property>
<property name="row_spacing">6</property>
<child>
<object class="GtkHBox" id="hbox3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">12</property>
diff --git a/gnome-session/gsm-client.c b/gnome-session/gsm-client.c
index 6828ad44..3f216b22 100644
--- a/gnome-session/gsm-client.c
+++ b/gnome-session/gsm-client.c
@@ -514,50 +514,60 @@ gsm_client_query_end_session (GsmClient *client,
g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
return GSM_CLIENT_GET_CLASS (client)->impl_query_end_session (client, flags, error);
}
gboolean
gsm_client_end_session (GsmClient *client,
GsmClientEndSessionFlag flags,
GError **error)
{
g_return_val_if_fail (GSM_IS_CLIENT (client), FALSE);
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, 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 78cb15d8..19c9cd8d 100644
--- a/gnome-session/gsm-client.h
+++ b/gnome-session/gsm-client.h
@@ -64,91 +64,97 @@ struct _GsmClient
GObject parent;
GsmClientPrivate *priv;
};
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 6e9b002b..5793f830 100644
--- a/gnome-session/gsm-dbus-client.c
+++ b/gnome-session/gsm-dbus-client.c
@@ -300,60 +300,73 @@ gsm_dbus_client_get_property (GObject *object,
case PROP_BUS_NAME:
g_value_set_string (value, self->priv->bus_name);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gsm_dbus_client_finalize (GObject *object)
{
GsmDBusClient *client = (GsmDBusClient *) object;
g_free (client->priv->bus_name);
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;
}
@@ -394,60 +407,61 @@ static gboolean
dbus_client_end_session (GsmClient *client,
GsmClientEndSessionFlag flags,
GError **error)
{
GsmDBusClient *dbus_client = (GsmDBusClient *) client;
gsm_exported_client_private_emit_end_session (dbus_client->priv->skeleton, flags);
return TRUE;
}
static gboolean
dbus_client_cancel_end_session (GsmClient *client,
GError **error)
{
GsmDBusClient *dbus_client = (GsmDBusClient *) client;
gsm_exported_client_private_emit_cancel_end_session (dbus_client->priv->skeleton);
return TRUE;
}
static void
gsm_dbus_client_class_init (GsmDBusClientClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GsmClientClass *client_class = GSM_CLIENT_CLASS (klass);
object_class->finalize = gsm_dbus_client_finalize;
object_class->constructor = gsm_dbus_client_constructor;
object_class->get_property = gsm_dbus_client_get_property;
object_class->set_property = gsm_dbus_client_set_property;
+ client_class->impl_request_save = dbus_client_request_save;
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;
client_class->impl_cancel_end_session = dbus_client_cancel_end_session;
client_class->impl_get_app_name = dbus_client_get_app_name;
client_class->impl_get_restart_style_hint = dbus_client_get_restart_style_hint;
client_class->impl_get_unix_process_id = dbus_client_get_unix_process_id;
g_object_class_install_property (object_class,
PROP_BUS_NAME,
g_param_spec_string ("bus-name",
"bus-name",
"bus-name",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_type_class_add_private (klass, sizeof (GsmDBusClientPrivate));
}
GsmClient *
gsm_dbus_client_new (const char *startup_id,
const char *bus_name)
{
GsmDBusClient *client;
client = g_object_new (GSM_TYPE_DBUS_CLIENT,
"startup-id", startup_id,
"bus-name", bus_name,
NULL);
diff --git a/gnome-session/gsm-manager.c b/gnome-session/gsm-manager.c
index 4bb81e04..ede4186a 100644
--- a/gnome-session/gsm-manager.c
+++ b/gnome-session/gsm-manager.c
@@ -54,60 +54,61 @@
#include "gsm-dbus-client.h"
#include "gsm-autostart-app.h"
#include "gsm-util.h"
#include "gsm-icon-names.h"
#include "gsm-system.h"
#include "gsm-session-save.h"
#include "gsm-shell-extensions.h"
#include "gsm-fail-whale.h"
#define GSM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_MANAGER, GsmManagerPrivate))
/* UUIDs for log messages */
#define GSM_MANAGER_STARTUP_SUCCEEDED_MSGID "0ce153587afa4095832d233c17a88001"
#define GSM_MANAGER_UNRECOVERABLE_FAILURE_MSGID "10dd2dc188b54a5e98970f56499d1f73"
#define GSM_MANAGER_DBUS_PATH "/org/gnome/SessionManager"
#define GSM_MANAGER_DBUS_NAME "org.gnome.SessionManager"
#define GSM_MANAGER_DBUS_IFACE "org.gnome.SessionManager"
/* Probably about the longest amount of time someone could reasonably
* want to wait, at least for something happening more than once.
* We can get deployed on very slow media though like CDROM devices,
* often with complex stacking/compressing filesystems on top, which
* is not a recipie for speed. Particularly now that we throw up
* a fail whale if required components don't show up quickly enough,
* let's make this fairly long.
*/
#define GSM_MANAGER_PHASE_TIMEOUT 90 /* seconds */
+#define GSM_MANAGER_SAVE_SESSION_TIMEOUT 2
#define GDM_FLEXISERVER_COMMAND "gdmflexiserver"
#define GDM_FLEXISERVER_ARGS "--startnew Standard"
#define SESSION_SCHEMA "org.gnome.desktop.session"
#define KEY_IDLE_DELAY "idle-delay"
#define KEY_SESSION_NAME "session-name"
#define GSM_MANAGER_SCHEMA "org.gnome.SessionManager"
#define KEY_AUTOSAVE "auto-save-session"
#define KEY_AUTOSAVE_ONE_SHOT "auto-save-session-one-shot"
#define KEY_LOGOUT_PROMPT "logout-prompt"
#define KEY_SHOW_FALLBACK_WARNING "show-fallback-warning"
#define SCREENSAVER_SCHEMA "org.gnome.desktop.screensaver"
#define KEY_SLEEP_LOCK "lock-enabled"
#define LOCKDOWN_SCHEMA "org.gnome.desktop.lockdown"
#define KEY_DISABLE_LOG_OUT "disable-log-out"
#define KEY_DISABLE_USER_SWITCHING "disable-user-switching"
static void app_registered (GsmApp *app, GParamSpec *spec, GsmManager *manager);
typedef enum
{
GSM_MANAGER_LOGOUT_NONE,
GSM_MANAGER_LOGOUT_LOGOUT,
GSM_MANAGER_LOGOUT_REBOOT,
GSM_MANAGER_LOGOUT_REBOOT_INTERACT,
GSM_MANAGER_LOGOUT_SHUTDOWN,
@@ -1172,60 +1173,123 @@ end_session_or_show_shell_dialog (GsmManager *manager)
end_phase (manager);
}
break;
case GSM_MANAGER_LOGOUT_MODE_FORCE:
end_phase (manager);
break;
default:
g_assert_not_reached ();
break;
}
}
static void
query_end_session_complete (GsmManager *manager)
{
g_debug ("GsmManager: query end session complete");
/* Remove the timeout since this can be called from outside the timer
* and we don't want to have it called twice */
if (manager->priv->query_timeout_id > 0) {
g_source_remove (manager->priv->query_timeout_id);
manager->priv->query_timeout_id = 0;
}
end_session_or_show_shell_dialog (manager);
}
+static gboolean
+_client_request_save (GsmClient *client,
+ ClientEndSessionData *data)
+{
+ gboolean ret;
+ GError *error;
+
+ error = NULL;
+ ret = gsm_client_request_save (client, data->flags, &error);
+ if (ret) {
+ g_debug ("GsmManager: adding client to query clients: %s", gsm_client_peek_id (client));
+ data->manager->priv->query_clients = g_slist_prepend (data->manager->priv->query_clients,
+ client);
+ } else if (error) {
+ g_debug ("GsmManager: unable to query client: %s", error->message);
+ g_error_free (error);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+_client_request_save_helper (const char *id,
+ GsmClient *client,
+ ClientEndSessionData *data)
+{
+ return _client_request_save (client, data);
+}
+
+static void
+query_save_session_complete (GsmManager *manager)
+{
+ GError *error = NULL;
+
+ if (g_slist_length (manager->priv->next_query_clients) > 0) {
+ ClientEndSessionData data;
+
+ data.manager = manager;
+ data.flags = GSM_CLIENT_END_SESSION_FLAG_LAST;
+
+ g_slist_foreach (manager->priv->next_query_clients,
+ (GFunc)_client_request_save,
+ &data);
+
+ g_slist_free (manager->priv->next_query_clients);
+ manager->priv->next_query_clients = NULL;
+
+ return;
+ }
+
+ if (manager->priv->query_timeout_id > 0) {
+ g_source_remove (manager->priv->query_timeout_id);
+ manager->priv->query_timeout_id = 0;
+ }
+
+ gsm_session_save (manager->priv->clients, &error);
+
+ if (error) {
+ g_warning ("Error saving session: %s", error->message);
+ g_error_free (error);
+ }
+}
+
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;
}
static gboolean
_on_query_end_session_timeout (GsmManager *manager)
{
GSList *l;
manager->priv->query_timeout_id = 0;
g_debug ("GsmManager: query end session timed out");
@@ -1252,60 +1316,75 @@ _on_query_end_session_timeout (GsmManager *manager)
bus_name = NULL;
}
app_id = g_strdup (gsm_client_peek_app_id (l->data));
if (IS_STRING_EMPTY (app_id)) {
/* XSMP clients don't give us an app id unless we start them */
g_free (app_id);
app_id = gsm_client_get_app_name (l->data);
}
cookie = _generate_unique_cookie (manager);
inhibitor = gsm_inhibitor_new_for_client (gsm_client_peek_id (l->data),
app_id,
GSM_INHIBITOR_FLAG_LOGOUT,
_("Not responding"),
bus_name,
cookie);
g_free (app_id);
gsm_store_add (manager->priv->inhibitors, gsm_inhibitor_peek_id (inhibitor), G_OBJECT (inhibitor));
g_object_unref (inhibitor);
}
g_slist_free (manager->priv->query_clients);
manager->priv->query_clients = NULL;
query_end_session_complete (manager);
return FALSE;
}
+static gboolean
+_on_query_save_session_timeout (GsmManager *manager)
+{
+ manager->priv->query_timeout_id = 0;
+
+ g_debug ("GsmManager: query to save session timed out");
+
+ g_slist_free (manager->priv->query_clients);
+ manager->priv->query_clients = NULL;
+
+ query_save_session_complete (manager);
+
+ return FALSE;
+}
+
static void
do_phase_query_end_session (GsmManager *manager)
{
ClientEndSessionData data;
data.manager = manager;
data.flags = 0;
if (manager->priv->logout_mode == GSM_MANAGER_LOGOUT_MODE_FORCE) {
data.flags |= GSM_CLIENT_END_SESSION_FLAG_FORCEFUL;
}
/* We only query if an app is ready to log out, so we don't use
* GSM_CLIENT_END_SESSION_FLAG_SAVE here.
*/
debug_clients (manager);
g_debug ("GsmManager: sending query-end-session to clients (logout mode: %s)",
manager->priv->logout_mode == GSM_MANAGER_LOGOUT_MODE_NORMAL? "normal" :
manager->priv->logout_mode == GSM_MANAGER_LOGOUT_MODE_FORCE? "forceful":
"no confirmation");
gsm_store_foreach (manager->priv->clients,
(GsmStoreFunc)_client_query_end_session,
&data);
/* This phase doesn't time out unless logout is forced. Typically, this
* separate timer is only used to show UI. */
manager->priv->query_timeout_id = g_timeout_add_seconds (1, (GSourceFunc)_on_query_end_session_timeout, manager);
}
static void
@@ -1848,67 +1927,86 @@ maybe_save_session (GsmManager *manager)
return;
/* We only allow session saving when session is running or when
* logging out */
if (manager->priv->phase != GSM_MANAGER_PHASE_RUNNING &&
manager->priv->phase != GSM_MANAGER_PHASE_END_SESSION) {
return;
}
if (!auto_save_is_enabled (manager)) {
return;
}
error = NULL;
gsm_session_save (manager->priv->clients, manager->priv->apps, &error);
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 received outside of shutdown */
- if (manager->priv->phase < GSM_MANAGER_PHASE_QUERY_END_SESSION) {
+ /* 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);
+
+ if (do_last) {
+ manager->priv->next_query_clients = g_slist_prepend (manager->priv->next_query_clients,
+ client);
+ }
+
+ if (manager->priv->query_clients == NULL) {
+ query_save_session_complete (manager);
+ }
+ return;
+ }
+
if (cancel) {
cancel_end_session (manager);
return;
}
manager->priv->query_clients = g_slist_remove (manager->priv->query_clients, client);
if (! is_ok && manager->priv->logout_mode != GSM_MANAGER_LOGOUT_MODE_FORCE) {
guint cookie;
GsmInhibitor *inhibitor;
char *app_id;
const char *bus_name;
/* FIXME: do we support updating the reason? */
/* Create JIT inhibit */
if (GSM_IS_DBUS_CLIENT (client)) {
bus_name = gsm_dbus_client_get_bus_name (GSM_DBUS_CLIENT (client));
} else {
bus_name = NULL;
}
app_id = g_strdup (gsm_client_peek_app_id (client));
if (IS_STRING_EMPTY (app_id)) {
/* XSMP clients don't give us an app id unless we start them */
g_free (app_id);
app_id = gsm_client_get_app_name (client);
}
cookie = _generate_unique_cookie (manager);
@@ -1968,85 +2066,98 @@ on_client_end_session_response (GsmClient *client,
_handle_client_end_session_response (manager,
client,
is_ok,
do_last,
cancel,
reason);
}
static void
on_xsmp_client_logout_request (GsmXSMPClient *client,
gboolean show_dialog,
GsmManager *manager)
{
GError *error;
int logout_mode;
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);
if (error != NULL) {
g_warning ("Unable to logout: %s", error->message);
g_error_free (error);
}
}
+static void
+on_xsmp_client_save_request (GsmXSMPClient *client,
+ gboolean show_dialog,
+ GsmManager *manager)
+{
+ g_debug ("GsmManager: save_request");
+ gsm_manager_save_session (manager, NULL);
+}
+
static void
on_store_client_added (GsmStore *store,
const char *id,
GsmManager *manager)
{
GsmClient *client;
g_debug ("GsmManager: Client added: %s", id);
client = (GsmClient *)gsm_store_lookup (store, id);
/* a bit hacky */
if (GSM_IS_XSMP_CLIENT (client)) {
g_signal_connect (client,
"register-request",
G_CALLBACK (on_xsmp_client_register_request),
manager);
g_signal_connect (client,
"register-confirmed",
G_CALLBACK (on_xsmp_client_register_confirmed),
manager);
g_signal_connect (client,
"logout-request",
G_CALLBACK (on_xsmp_client_logout_request),
manager);
+ g_signal_connect (client,
+ "save-request",
+ G_CALLBACK (on_xsmp_client_save_request),
+ manager);
}
g_signal_connect (client,
"end-session-response",
G_CALLBACK (on_client_end_session_response),
manager);
gsm_exported_manager_emit_client_added (manager->priv->skeleton, id);
/* FIXME: disconnect signal handler */
}
static void
on_store_client_removed (GsmStore *store,
const char *id,
GsmManager *manager)
{
g_debug ("GsmManager: Client removed: %s", id);
gsm_exported_manager_emit_client_removed (manager->priv->skeleton, id);
}
static void
gsm_manager_set_client_store (GsmManager *manager,
GsmStore *store)
{
g_return_if_fail (GSM_IS_MANAGER (manager));
if (store != NULL) {
g_object_ref (store);
}
@@ -2625,60 +2736,95 @@ gsm_manager_initialization_error (GsmExportedManager *skeleton,
gboolean fatal,
GsmManager *manager)
{
if (manager->priv->phase != GSM_MANAGER_PHASE_INITIALIZATION) {
g_dbus_method_invocation_return_error (invocation,
GSM_MANAGER_ERROR,
GSM_MANAGER_ERROR_NOT_IN_INITIALIZATION,
"InitializationError interface is only available during the Initialization phase");
return TRUE;
}
gsm_util_init_error (fatal, "%s", message);
gsm_exported_manager_complete_initialization_error (skeleton, invocation);
return TRUE;
}
static void
user_logout (GsmManager *manager,
GsmManagerLogoutMode mode)
{
if (manager->priv->phase >= GSM_MANAGER_PHASE_QUERY_END_SESSION) {
manager->priv->logout_mode = mode;
end_session_or_show_shell_dialog (manager);
return;
}
request_logout (manager, mode);
}
+gboolean
+gsm_manager_save_session (GsmManager *manager,
+ GError **error)
+{
+ ClientEndSessionData data;
+
+ g_debug ("GsmManager: SaveSession called");
+
+ g_return_val_if_fail (GSM_IS_MANAGER (manager), FALSE);
+
+ if (manager->priv->phase != GSM_MANAGER_PHASE_RUNNING) {
+ g_set_error (error,
+ GSM_MANAGER_ERROR,
+ GSM_MANAGER_ERROR_NOT_IN_RUNNING,
+ "SaveSession interface is only available during the Running phase");
+ return FALSE;
+ }
+
+ data.manager = manager;
+ data.flags = 0;
+ gsm_store_foreach (manager->priv->clients,
+ (GsmStoreFunc)_client_request_save_helper,
+ &data);
+
+ if (manager->priv->query_clients) {
+ manager->priv->query_timeout_id = g_timeout_add_seconds (GSM_MANAGER_SAVE_SESSION_TIMEOUT,
+ (GSourceFunc)_on_query_save_session_timeout,
+ manager);
+ return TRUE;
+ } else {
+ g_debug ("GsmManager: Nothing to save");
+ return FALSE;
+ }
+}
+
gboolean
gsm_manager_logout (GsmManager *manager,
guint logout_mode,
GError **error)
{
if (manager->priv->phase < GSM_MANAGER_PHASE_RUNNING) {
g_set_error (error,
GSM_MANAGER_ERROR,
GSM_MANAGER_ERROR_NOT_IN_RUNNING,
"Logout interface is only available after the Running phase starts");
return FALSE;
}
if (_log_out_is_locked_down (manager)) {
g_set_error (error,
GSM_MANAGER_ERROR,
GSM_MANAGER_ERROR_LOCKED_DOWN,
"Logout has been locked down");
return FALSE;
}
switch (logout_mode) {
case GSM_MANAGER_LOGOUT_MODE_NORMAL:
case GSM_MANAGER_LOGOUT_MODE_NO_CONFIRMATION:
case GSM_MANAGER_LOGOUT_MODE_FORCE:
user_logout (manager, logout_mode);
break;
default:
g_debug ("Unknown logout mode option");
diff --git a/gnome-session/gsm-manager.h b/gnome-session/gsm-manager.h
index bc440cb0..4d14aa34 100644
--- a/gnome-session/gsm-manager.h
+++ b/gnome-session/gsm-manager.h
@@ -96,40 +96,43 @@ GQuark gsm_manager_error_quark (void);
GType gsm_manager_get_type (void);
GsmManager * gsm_manager_new (GsmStore *client_store,
gboolean failsafe);
GsmManager * gsm_manager_get (void);
gboolean gsm_manager_get_failsafe (GsmManager *manager);
gboolean gsm_manager_add_autostart_app (GsmManager *manager,
const char *path,
const char *provides);
gboolean gsm_manager_add_required_app (GsmManager *manager,
const char *path,
const char *provides);
gboolean gsm_manager_add_autostart_apps_from_dir (GsmManager *manager,
const char *path);
gboolean gsm_manager_add_legacy_session_apps (GsmManager *manager,
const char *path);
void gsm_manager_start (GsmManager *manager);
const char * _gsm_manager_get_default_session (GsmManager *manager);
void _gsm_manager_set_active_session (GsmManager *manager,
const char *session_name,
gboolean is_fallback);
void _gsm_manager_set_renderer (GsmManager *manager,
const char *renderer);
+gboolean gsm_manager_save_session (GsmManager *manager,
+ GError **error);
+
gboolean gsm_manager_logout (GsmManager *manager,
guint logout_mode,
GError **error);
gboolean gsm_manager_set_phase (GsmManager *manager,
GsmManagerPhase phase);
G_END_DECLS
#endif /* __GSM_MANAGER_H */
diff --git a/gnome-session/gsm-xsmp-client.c b/gnome-session/gsm-xsmp-client.c
index 8a30926f..cbecd68c 100644
--- a/gnome-session/gsm-xsmp-client.c
+++ b/gnome-session/gsm-xsmp-client.c
@@ -39,60 +39,61 @@
#define GsmDesktopFile "_GSM_DesktopFile"
#define GSM_XSMP_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSM_TYPE_XSMP_CLIENT, GsmXSMPClientPrivate))
struct GsmXSMPClientPrivate
{
SmsConn conn;
IceConn ice_connection;
guint watch_id;
char *description;
GPtrArray *props;
/* SaveYourself state */
int current_save_yourself;
int next_save_yourself;
guint next_save_yourself_allow_interact : 1;
};
enum {
PROP_0,
PROP_ICE_CONNECTION
};
enum {
REGISTER_REQUEST,
REGISTER_CONFIRMED,
LOGOUT_REQUEST,
+ SAVE_REQUEST,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE (GsmXSMPClient, gsm_xsmp_client, GSM_TYPE_CLIENT)
static gboolean
client_iochannel_watch (GIOChannel *channel,
GIOCondition condition,
GsmXSMPClient *client)
{
gboolean keep_going;
g_object_ref (client);
switch (IceProcessMessages (client->priv->ice_connection, NULL, NULL)) {
case IceProcessMessagesSuccess:
keep_going = TRUE;
break;
case IceProcessMessagesIOError:
g_debug ("GsmXSMPClient: IceProcessMessagesIOError on '%s'", client->priv->description);
gsm_client_set_status (GSM_CLIENT (client), GSM_CLIENT_FAILED);
/* Emitting "disconnected" will eventually cause
* IceCloseConnection() to be called.
*/
gsm_client_disconnected (GSM_CLIENT (client));
keep_going = FALSE;
break;
@@ -472,60 +473,84 @@ xsmp_interact (GsmClient *client)
SmsInteract (xsmp->priv->conn);
}
static gboolean
xsmp_cancel_end_session (GsmClient *client,
GError **error)
{
GsmXSMPClient *xsmp = (GsmXSMPClient *) client;
g_debug ("GsmXSMPClient: xsmp_cancel_end_session ('%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;
}
SmsShutdownCancelled (xsmp->priv->conn);
/* reset the state */
xsmp->priv->current_save_yourself = -1;
xsmp->priv->next_save_yourself = -1;
xsmp->priv->next_save_yourself_allow_interact = FALSE;
return TRUE;
}
+static gboolean
+xsmp_request_save (GsmClient *client,
+ guint flags,
+ GError **error)
+{
+ GsmXSMPClient *xsmp = (GsmXSMPClient *) client;
+
+ g_debug ("GsmXSMPClient: xsmp_request_save ('%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;
+ }
+
+ if (flags & GSM_CLIENT_END_SESSION_FLAG_LAST)
+ xsmp_save_yourself_phase2 (client);
+ else
+ do_save_yourself (xsmp, SmSaveLocal, FALSE);
+
+ return TRUE;
+}
static char *
get_desktop_file_path (GsmXSMPClient *client)
{
SmProp *prop;
char *desktop_file_path = NULL;
const char *program_name;
/* XSMP clients using eggsmclient defines a special property
* pointing to their respective desktop entry file */
prop = find_property (client, GsmDesktopFile, NULL);
if (prop) {
GFile *file = g_file_new_for_uri (prop->vals[0].value);
desktop_file_path = g_file_get_path (file);
g_object_unref (file);
goto out;
}
/* If we can't get desktop file from GsmDesktopFile then we
* try to find the desktop file from its program name */
prop = find_property (client, SmProgram, NULL);
if (!prop) {
goto out;
}
program_name = prop->vals[0].value;
desktop_file_path =
gsm_util_find_desktop_file_for_app_name (program_name,
TRUE, FALSE);
@@ -964,100 +989,112 @@ xsmp_get_unix_process_id (GsmClient *client)
gboolean res;
g_debug ("GsmXSMPClient: getting pid");
prop = find_property (GSM_XSMP_CLIENT (client), SmProcessID, NULL);
if (!prop || strcmp (prop->type, SmARRAY8) != 0) {
return 0;
}
pid = 0;
res = _parse_value_as_uint ((char *)prop->vals[0].value, &pid);
if (! res) {
pid = 0;
}
return pid;
}
static void
gsm_xsmp_client_class_init (GsmXSMPClientClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GsmClientClass *client_class = GSM_CLIENT_CLASS (klass);
object_class->finalize = gsm_xsmp_client_finalize;
object_class->constructor = gsm_xsmp_client_constructor;
object_class->get_property = gsm_xsmp_client_get_property;
object_class->set_property = gsm_xsmp_client_set_property;
+ client_class->impl_request_save = xsmp_request_save;
client_class->impl_save = xsmp_save;
client_class->impl_stop = xsmp_stop;
client_class->impl_query_end_session = xsmp_query_end_session;
client_class->impl_end_session = xsmp_end_session;
client_class->impl_cancel_end_session = xsmp_cancel_end_session;
client_class->impl_get_app_name = xsmp_get_app_name;
client_class->impl_get_restart_style_hint = xsmp_get_restart_style_hint;
client_class->impl_get_unix_process_id = xsmp_get_unix_process_id;
signals[REGISTER_REQUEST] =
g_signal_new ("register-request",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GsmXSMPClientClass, register_request),
_boolean_handled_accumulator,
NULL,
NULL,
G_TYPE_BOOLEAN,
1, G_TYPE_POINTER);
signals[REGISTER_CONFIRMED] =
g_signal_new ("register-confirmed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GsmXSMPClientClass, register_confirmed),
NULL,
NULL,
NULL,
G_TYPE_NONE,
1, G_TYPE_POINTER);
signals[LOGOUT_REQUEST] =
g_signal_new ("logout-request",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GsmXSMPClientClass, logout_request),
NULL,
NULL,
NULL,
G_TYPE_NONE,
1, G_TYPE_BOOLEAN);
+ signals[SAVE_REQUEST] =
+ g_signal_new ("save-request",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsmXSMPClientClass, save_request),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE,
+ 1, G_TYPE_BOOLEAN);
+
g_object_class_install_property (object_class,
PROP_ICE_CONNECTION,
g_param_spec_pointer ("ice-connection",
"ice-connection",
"ice-connection",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_type_class_add_private (klass, sizeof (GsmXSMPClientPrivate));
}
GsmClient *
gsm_xsmp_client_new (IceConn ice_conn)
{
GsmXSMPClient *xsmp;
xsmp = g_object_new (GSM_TYPE_XSMP_CLIENT,
"ice-connection", ice_conn,
NULL);
return GSM_CLIENT (xsmp);
}
static Status
register_client_callback (SmsConn conn,
SmPointer manager_data,
char *previous_id)
{
GsmXSMPClient *client = manager_data;
gboolean handled;
char *id;
diff --git a/gnome-session/gsm-xsmp-client.h b/gnome-session/gsm-xsmp-client.h
index 1bb27975..6b95c51b 100644
--- a/gnome-session/gsm-xsmp-client.h
+++ b/gnome-session/gsm-xsmp-client.h
@@ -27,61 +27,62 @@ G_BEGIN_DECLS
#define GSM_TYPE_XSMP_CLIENT (gsm_xsmp_client_get_type ())
#define GSM_XSMP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSM_TYPE_XSMP_CLIENT, GsmXSMPClient))
#define GSM_XSMP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSM_TYPE_XSMP_CLIENT, GsmXSMPClientClass))
#define GSM_IS_XSMP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSM_TYPE_XSMP_CLIENT))
#define GSM_IS_XSMP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSM_TYPE_XSMP_CLIENT))
#define GSM_XSMP_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSM_TYPE_XSMP_CLIENT, GsmXSMPClientClass))
typedef struct _GsmXSMPClient GsmXSMPClient;
typedef struct _GsmXSMPClientClass GsmXSMPClientClass;
typedef struct GsmXSMPClientPrivate GsmXSMPClientPrivate;
struct _GsmXSMPClient
{
GsmClient parent;
GsmXSMPClientPrivate *priv;
};
struct _GsmXSMPClientClass
{
GsmClientClass parent_class;
/* signals */
gboolean (*register_request) (GsmXSMPClient *client,
char **client_id);
void (*register_confirmed) (GsmXSMPClient *client,
const char *client_id);
gboolean (*logout_request) (GsmXSMPClient *client,
gboolean prompt);
-
+ gboolean (*save_request) (GsmXSMPClient *client,
+ gboolean prompt);
void (*saved_state) (GsmXSMPClient *client);
void (*request_phase2) (GsmXSMPClient *client);
void (*request_interaction) (GsmXSMPClient *client);
void (*interaction_done) (GsmXSMPClient *client,
gboolean cancel_shutdown);
void (*save_yourself_done) (GsmXSMPClient *client);
};
GType gsm_xsmp_client_get_type (void) G_GNUC_CONST;
GsmClient *gsm_xsmp_client_new (IceConn ice_conn);
void gsm_xsmp_client_connect (GsmXSMPClient *client,
SmsConn conn,
unsigned long *mask_ret,
SmsCallbacks *callbacks_ret);
void gsm_xsmp_client_save_state (GsmXSMPClient *client);
void gsm_xsmp_client_save_yourself (GsmXSMPClient *client,
gboolean save_state);
void gsm_xsmp_client_save_yourself_phase2 (GsmXSMPClient *client);
void gsm_xsmp_client_interact (GsmXSMPClient *client);
void gsm_xsmp_client_shutdown_cancelled (GsmXSMPClient *client);
G_END_DECLS
diff --git a/gnome-session/org.gnome.SessionManager.xml b/gnome-session/org.gnome.SessionManager.xml
index 580ec356..29eb0990 100644
--- a/gnome-session/org.gnome.SessionManager.xml
+++ b/gnome-session/org.gnome.SessionManager.xml
@@ -255,60 +255,68 @@
</arg>
<arg name="handled" direction="out" type="b">
<doc:doc>
<doc:summary>True if condition is handled, false otherwise</doc:summary>
</doc:doc>
</arg>
<doc:doc>
<doc:description>
<doc:para>Allows the caller to determine whether the session manager is
handling changes to the specified autostart condition.</doc:para>
</doc:description>
</doc:doc>
</method>
<method name="Shutdown">
<doc:doc>
<doc:description>
<doc:para>Request a shutdown dialog.</doc:para>
</doc:description>
</doc:doc>
</method>
<method name="Reboot">
<doc:doc>
<doc:description>
<doc:para>Request a reboot dialog.</doc:para>
</doc:description>
</doc:doc>
</method>
+ <method name="SaveSession">
+ <doc:doc>
+ <doc:description>
+ <doc:para>Request to save session</doc:para>
+ </doc:description>
+ </doc:doc>
+ </method>
+
<method name="CanShutdown">
<arg name="is_available" direction="out" type="b">
<doc:doc>
<doc:summary>True if shutdown is available to the user, false otherwise</doc:summary>
</doc:doc>
</arg>
<doc:doc>
<doc:description>
<doc:para>Allows the caller to determine whether or not it's okay to show
a shutdown option in the UI</doc:para>
</doc:description>
</doc:doc>
</method>
<method name="Logout">
<arg name="mode" type="u" direction="in">
<doc:doc>
<doc:summary>The type of logout that is being requested</doc:summary>
</doc:doc>
</arg>
<doc:doc>
<doc:description>
<doc:para>Request a logout dialog</doc:para>
<doc:para>
Allowed values for the mode parameter are:
<doc:list>
<doc:item>
<doc:term>0</doc:term>
<doc:definition>Normal.</doc:definition>
</doc:item>
diff --git a/meson.build b/meson.build
index 9a16d5b1..24221bb6 100644
--- a/meson.build
+++ b/meson.build
@@ -72,60 +72,61 @@ if enable_deprecation_flags
endif
compiler_flags = []
if session_debug
test_cflags = [
'-Werror=format=2',
'-Werror=implicit-function-declaration',
'-Werror=init-self',
'-Werror=missing-include-dirs',
'-Werror=missing-prototypes',
'-Werror=pointer-arith',
'-Werror=return-type',
'-Wnested-externs',
'-Wstrict-prototypes'
]
compiler_flags += cc.get_supported_arguments(test_cflags)
endif
add_project_arguments(common_flags + compiler_flags, language: 'c')
glib_req_version = '>= 2.46.0'
gio_dep = dependency('gio-2.0', version: glib_req_version)
glib_dep = dependency('glib-2.0', version: glib_req_version)
gtk_dep = dependency('gtk+-3.0', version: '>= 3.18.0')
xtrans_dep = dependency('xtrans')
ice_dep = dependency('ice')
sm_dep = dependency('sm')
x11_dep = dependency('x11')
+dbus_glib_dep = dependency('dbus-glib-1')
session_deps = [
gio_dep,
glib_dep,
dependency('gnome-desktop-3.0', version: '>= 3.18.0'),
dependency('json-glib-1.0', version: '>= 0.10')
]
session_bin_deps = session_deps + [
xtrans_dep,
ice_dep,
sm_dep
]
# Check for session selector GTK+ UI
enable_session_selector = get_option('session_selector')
# Check for session tracking backend
session_tracking = 'null backend'
enable_systemd = get_option('systemd')
enable_systemd_journal = get_option('systemd_journal')
enable_consolekit = get_option('consolekit')
if enable_systemd or enable_consolekit
session_bin_deps += dependency('gio-unix-2.0', version: glib_req_version)
# Check for systemd
if enable_systemd
libsystemd_dep = dependency('libsystemd', version: '>= 209', required: false)
session_bin_deps += libsystemd_dep
--
2.17.0