From 96e78f519a4d5ce2e5b708035ae1f43eb7c1bbd2 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 14 Aug 2018 14:52:41 -0400
Subject: [PATCH 2/4] session: support new accountsservice Session and
SessionType props
At the moment the user's session is stored in a property called
"XSession". This is pretty weird if the user is using wayland.
AccountService now supports a more generic property "Session" and
a related "SessionType" property to replace "XSession".
This commit switches GDM over to use the new properties.
---
daemon/gdm-session-settings.c | 61 ++++++++++++++++++++++--
daemon/gdm-session-settings.h | 3 ++
daemon/gdm-session-worker.c | 28 +++++++++++
daemon/gdm-session-worker.xml | 3 ++
daemon/gdm-session.c | 87 +++++++++++++++++++++++++----------
5 files changed, 153 insertions(+), 29 deletions(-)
diff --git a/daemon/gdm-session-settings.c b/daemon/gdm-session-settings.c
index 484a3b5b..f2b1addd 100644
--- a/daemon/gdm-session-settings.c
+++ b/daemon/gdm-session-settings.c
@@ -12,114 +12,121 @@
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* Written by: Ray Strode <rstrode@redhat.com>
*/
#include "config.h"
#include "gdm-session-settings.h"
#include <errno.h>
#include <pwd.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <glib.h>
#include <glib-object.h>
#include <glib/gi18n.h>
#include <act/act-user-manager.h>
struct _GdmSessionSettingsPrivate
{
ActUserManager *user_manager;
ActUser *user;
char *session_name;
+ char *session_type;
char *language_name;
};
static void gdm_session_settings_finalize (GObject *object);
static void gdm_session_settings_class_install_properties (GdmSessionSettingsClass *
settings_class);
static void gdm_session_settings_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gdm_session_settings_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
enum {
PROP_0 = 0,
PROP_SESSION_NAME,
+ PROP_SESSION_TYPE,
PROP_LANGUAGE_NAME,
PROP_IS_LOADED
};
G_DEFINE_TYPE_WITH_PRIVATE (GdmSessionSettings,
gdm_session_settings,
G_TYPE_OBJECT)
static void
gdm_session_settings_class_init (GdmSessionSettingsClass *settings_class)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (settings_class);
object_class->finalize = gdm_session_settings_finalize;
gdm_session_settings_class_install_properties (settings_class);
}
static void
gdm_session_settings_class_install_properties (GdmSessionSettingsClass *settings_class)
{
GObjectClass *object_class;
GParamSpec *param_spec;
object_class = G_OBJECT_CLASS (settings_class);
object_class->set_property = gdm_session_settings_set_property;
object_class->get_property = gdm_session_settings_get_property;
param_spec = g_param_spec_string ("session-name", "Session Name",
"The name of the session",
NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_SESSION_NAME, param_spec);
+ param_spec = g_param_spec_string ("session-type", "Session Type",
+ "The type of the session",
+ NULL, G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_SESSION_TYPE, param_spec);
+
param_spec = g_param_spec_string ("language-name", "Language Name",
"The name of the language",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_LANGUAGE_NAME, param_spec);
param_spec = g_param_spec_boolean ("is-loaded", NULL, NULL,
FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_IS_LOADED, param_spec);
}
static void
gdm_session_settings_init (GdmSessionSettings *settings)
{
settings->priv = G_TYPE_INSTANCE_GET_PRIVATE (settings,
GDM_TYPE_SESSION_SETTINGS,
GdmSessionSettingsPrivate);
settings->priv->user_manager = act_user_manager_get_default ();
}
static void
gdm_session_settings_finalize (GObject *object)
{
GdmSessionSettings *settings;
GObjectClass *parent_class;
settings = GDM_SESSION_SETTINGS (object);
@@ -136,172 +143,212 @@ gdm_session_settings_finalize (GObject *object)
parent_class->finalize (object);
}
}
void
gdm_session_settings_set_language_name (GdmSessionSettings *settings,
const char *language_name)
{
g_return_if_fail (GDM_IS_SESSION_SETTINGS (settings));
if (settings->priv->language_name == NULL ||
strcmp (settings->priv->language_name, language_name) != 0) {
settings->priv->language_name = g_strdup (language_name);
g_object_notify (G_OBJECT (settings), "language-name");
}
}
void
gdm_session_settings_set_session_name (GdmSessionSettings *settings,
const char *session_name)
{
g_return_if_fail (GDM_IS_SESSION_SETTINGS (settings));
if (settings->priv->session_name == NULL ||
strcmp (settings->priv->session_name, session_name) != 0) {
settings->priv->session_name = g_strdup (session_name);
g_object_notify (G_OBJECT (settings), "session-name");
}
}
+void
+gdm_session_settings_set_session_type (GdmSessionSettings *settings,
+ const char *session_type)
+{
+ g_return_if_fail (GDM_IS_SESSION_SETTINGS (settings));
+
+ if (settings->priv->session_type == NULL ||
+ g_strcmp0 (settings->priv->session_type, session_type) != 0) {
+ settings->priv->session_type = g_strdup (session_type);
+ g_object_notify (G_OBJECT (settings), "session-type");
+ }
+}
+
char *
gdm_session_settings_get_language_name (GdmSessionSettings *settings)
{
g_return_val_if_fail (GDM_IS_SESSION_SETTINGS (settings), NULL);
return g_strdup (settings->priv->language_name);
}
char *
gdm_session_settings_get_session_name (GdmSessionSettings *settings)
{
g_return_val_if_fail (GDM_IS_SESSION_SETTINGS (settings), NULL);
return g_strdup (settings->priv->session_name);
}
+char *
+gdm_session_settings_get_session_type (GdmSessionSettings *settings)
+{
+ g_return_val_if_fail (GDM_IS_SESSION_SETTINGS (settings), NULL);
+ return g_strdup (settings->priv->session_type);
+}
+
static void
gdm_session_settings_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdmSessionSettings *settings;
settings = GDM_SESSION_SETTINGS (object);
switch (prop_id) {
case PROP_LANGUAGE_NAME:
gdm_session_settings_set_language_name (settings, g_value_get_string (value));
break;
case PROP_SESSION_NAME:
gdm_session_settings_set_session_name (settings, g_value_get_string (value));
break;
+ case PROP_SESSION_TYPE:
+ gdm_session_settings_set_session_type (settings, g_value_get_string (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gdm_session_settings_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdmSessionSettings *settings;
settings = GDM_SESSION_SETTINGS (object);
switch (prop_id) {
case PROP_SESSION_NAME:
g_value_set_string (value, settings->priv->session_name);
break;
+ case PROP_SESSION_TYPE:
+ g_value_set_string (value, settings->priv->session_type);
+ break;
+
case PROP_LANGUAGE_NAME:
g_value_set_string (value, settings->priv->language_name);
break;
case PROP_IS_LOADED:
g_value_set_boolean (value, gdm_session_settings_is_loaded (settings));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
GdmSessionSettings *
gdm_session_settings_new (void)
{
GdmSessionSettings *settings;
settings = g_object_new (GDM_TYPE_SESSION_SETTINGS,
NULL);
return settings;
}
gboolean
gdm_session_settings_is_loaded (GdmSessionSettings *settings)
{
if (settings->priv->user == NULL) {
return FALSE;
}
return act_user_is_loaded (settings->priv->user);
}
static void
load_settings_from_user (GdmSessionSettings *settings)
{
const char *session_name;
+ const char *session_type;
const char *language_name;
if (!act_user_is_loaded (settings->priv->user)) {
g_warning ("GdmSessionSettings: trying to load user settings from unloaded user");
return;
}
- session_name = act_user_get_x_session (settings->priv->user);
- g_debug ("GdmSessionSettings: saved session is %s", session_name);
- if (session_name != NULL) {
+
+
+
+ session_type = act_user_get_session_type (settings->priv->user);
+ session_name = act_user_get_session (settings->priv->user);
+
+ g_debug ("GdmSessionSettings: saved session is %s (type %s)", session_name, session_type);
+
+ if (session_type != NULL && session_type[0] != '\0') {
+ gdm_session_settings_set_session_type (settings, session_type);
+ }
+
+ if (session_name != NULL && session_name[0] != '\0') {
gdm_session_settings_set_session_name (settings, session_name);
}
language_name = act_user_get_language (settings->priv->user);
g_debug ("GdmSessionSettings: saved language is %s", language_name);
- if (language_name != NULL) {
+ if (language_name != NULL && language_name[0] != '\0') {
gdm_session_settings_set_language_name (settings, language_name);
}
+out:
g_object_notify (G_OBJECT (settings), "is-loaded");
}
static void
on_user_is_loaded_changed (ActUser *user,
GParamSpec *pspec,
GdmSessionSettings *settings)
{
if (act_user_is_loaded (settings->priv->user)) {
load_settings_from_user (settings);
g_signal_handlers_disconnect_by_func (G_OBJECT (settings->priv->user),
G_CALLBACK (on_user_is_loaded_changed),
settings);
}
}
gboolean
gdm_session_settings_load (GdmSessionSettings *settings,
const char *username)
{
ActUser *old_user;
g_return_val_if_fail (settings != NULL, FALSE);
g_return_val_if_fail (username != NULL, FALSE);
g_return_val_if_fail (!gdm_session_settings_is_loaded (settings), FALSE);
if (settings->priv->user != NULL) {
old_user = settings->priv->user;
g_signal_handlers_disconnect_by_func (G_OBJECT (settings->priv->user),
@@ -322,40 +369,44 @@ gdm_session_settings_load (GdmSessionSettings *settings,
G_CALLBACK (on_user_is_loaded_changed),
settings);
return FALSE;
}
load_settings_from_user (settings);
return TRUE;
}
gboolean
gdm_session_settings_save (GdmSessionSettings *settings,
const char *username)
{
ActUser *user;
g_return_val_if_fail (GDM_IS_SESSION_SETTINGS (settings), FALSE);
g_return_val_if_fail (username != NULL, FALSE);
g_return_val_if_fail (gdm_session_settings_is_loaded (settings), FALSE);
user = act_user_manager_get_user (settings->priv->user_manager,
username);
if (!act_user_is_loaded (user)) {
g_object_unref (user);
return FALSE;
}
if (settings->priv->session_name != NULL) {
- act_user_set_x_session (user, settings->priv->session_name);
+ act_user_set_session (user, settings->priv->session_name);
+ }
+
+ if (settings->priv->session_type != NULL) {
+ act_user_set_session_type (user, settings->priv->session_type);
}
if (settings->priv->language_name != NULL) {
act_user_set_language (user, settings->priv->language_name);
}
g_object_unref (user);
return TRUE;
}
diff --git a/daemon/gdm-session-settings.h b/daemon/gdm-session-settings.h
index 20946bff..db38ffc7 100644
--- a/daemon/gdm-session-settings.h
+++ b/daemon/gdm-session-settings.h
@@ -33,37 +33,40 @@ G_BEGIN_DECLS
#define GDM_IS_SESSION_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_SESSION_SETTINGS))
#define GDM_SESSION_SETTINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GDM_TYPE_SESSION_SETTINGS, GdmSessionSettingsClass))
#define GDM_SESSION_SETTINGS_ERROR (gdm_session_settings_error_quark ())
typedef struct _GdmSessionSettings GdmSessionSettings;
typedef struct _GdmSessionSettingsClass GdmSessionSettingsClass;
typedef struct _GdmSessionSettingsPrivate GdmSessionSettingsPrivate;
struct _GdmSessionSettings
{
GObject parent;
/*< private > */
GdmSessionSettingsPrivate *priv;
};
struct _GdmSessionSettingsClass
{
GObjectClass parent_class;
};
GType gdm_session_settings_get_type (void);
GdmSessionSettings *gdm_session_settings_new (void);
gboolean gdm_session_settings_load (GdmSessionSettings *settings,
const char *username);
gboolean gdm_session_settings_save (GdmSessionSettings *settings,
const char *username);
gboolean gdm_session_settings_is_loaded (GdmSessionSettings *settings);
char *gdm_session_settings_get_language_name (GdmSessionSettings *settings);
char *gdm_session_settings_get_session_name (GdmSessionSettings *settings);
+char *gdm_session_settings_get_session_type (GdmSessionSettings *settings);
void gdm_session_settings_set_language_name (GdmSessionSettings *settings,
const char *language_name);
void gdm_session_settings_set_session_name (GdmSessionSettings *settings,
const char *session_name);
+void gdm_session_settings_set_session_type (GdmSessionSettings *settings,
+ const char *session_type);
G_END_DECLS
#endif /* GDM_SESSION_SETTINGS_H */
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 88fe36c1..c1201b70 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -2664,60 +2664,74 @@ gdm_session_worker_handle_set_language_name (GdmDBusWorker *object,
gdm_dbus_worker_complete_set_language_name (object, invocation);
return TRUE;
}
static void
on_saved_language_name_read (GdmSessionWorker *worker)
{
char *language_name;
language_name = gdm_session_settings_get_language_name (worker->priv->user_settings);
g_debug ("GdmSessionWorker: Saved language is %s", language_name);
gdm_dbus_worker_emit_saved_language_name_read (GDM_DBUS_WORKER (worker),
language_name);
g_free (language_name);
}
static void
on_saved_session_name_read (GdmSessionWorker *worker)
{
char *session_name;
session_name = gdm_session_settings_get_session_name (worker->priv->user_settings);
g_debug ("GdmSessionWorker: Saved session is %s", session_name);
gdm_dbus_worker_emit_saved_session_name_read (GDM_DBUS_WORKER (worker),
session_name);
g_free (session_name);
}
+static void
+on_saved_session_type_read (GdmSessionWorker *worker)
+{
+ char *session_type;
+
+ session_type = gdm_session_settings_get_session_type (worker->priv->user_settings);
+
+ g_debug ("GdmSessionWorker: Saved session type is %s", session_type);
+ gdm_dbus_worker_emit_saved_session_type_read (GDM_DBUS_WORKER (worker),
+ session_type);
+ g_free (session_type);
+}
+
+
static void
do_setup (GdmSessionWorker *worker)
{
GError *error;
gboolean res;
error = NULL;
res = gdm_session_worker_initialize_pam (worker,
worker->priv->service,
(const char **) worker->priv->extensions,
worker->priv->username,
worker->priv->hostname,
worker->priv->display_is_local,
worker->priv->x11_display_name,
worker->priv->x11_authority_file,
worker->priv->display_device,
worker->priv->display_seat_id,
&error);
if (res) {
g_dbus_method_invocation_return_value (worker->priv->pending_invocation, NULL);
} else {
g_dbus_method_invocation_take_error (worker->priv->pending_invocation, error);
}
worker->priv->pending_invocation = NULL;
}
static void
do_authenticate (GdmSessionWorker *worker)
{
@@ -3127,158 +3141,172 @@ gdm_session_worker_handle_initialize (GdmDBusWorker *object,
} else if (g_strcmp0 (key, "x11-authority-file") == 0) {
worker->priv->x11_authority_file = g_variant_dup_string (value, NULL);
} else if (g_strcmp0 (key, "console") == 0) {
worker->priv->display_device = g_variant_dup_string (value, NULL);
} else if (g_strcmp0 (key, "seat-id") == 0) {
worker->priv->display_seat_id = g_variant_dup_string (value, NULL);
} else if (g_strcmp0 (key, "hostname") == 0) {
worker->priv->hostname = g_variant_dup_string (value, NULL);
} else if (g_strcmp0 (key, "display-is-local") == 0) {
worker->priv->display_is_local = g_variant_get_boolean (value);
} else if (g_strcmp0 (key, "display-is-initial") == 0) {
worker->priv->display_is_initial = g_variant_get_boolean (value);
}
}
worker->priv->pending_invocation = invocation;
if (!worker->priv->is_program_session) {
worker->priv->user_settings = gdm_session_settings_new ();
g_signal_connect_swapped (worker->priv->user_settings,
"notify::language-name",
G_CALLBACK (on_saved_language_name_read),
worker);
g_signal_connect_swapped (worker->priv->user_settings,
"notify::session-name",
G_CALLBACK (on_saved_session_name_read),
worker);
+ g_signal_connect_swapped (worker->priv->user_settings,
+ "notify::session-type",
+ G_CALLBACK (on_saved_session_type_read),
+ worker);
+
if (worker->priv->username) {
wait_for_settings = !gdm_session_settings_load (worker->priv->user_settings,
worker->priv->username);
}
}
if (wait_for_settings) {
/* Load settings from accounts daemon before continuing
*/
g_signal_connect (G_OBJECT (worker->priv->user_settings),
"notify::is-loaded",
G_CALLBACK (on_settings_is_loaded_changed),
worker);
} else {
queue_state_change (worker);
}
return TRUE;
}
static gboolean
gdm_session_worker_handle_setup (GdmDBusWorker *object,
GDBusMethodInvocation *invocation,
const char *service,
const char *x11_display_name,
const char *x11_authority_file,
const char *console,
const char *seat_id,
const char *hostname,
gboolean display_is_local,
gboolean display_is_initial)
{
GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
validate_and_queue_state_change (worker, invocation, GDM_SESSION_WORKER_STATE_SETUP_COMPLETE);
worker->priv->service = g_strdup (service);
worker->priv->x11_display_name = g_strdup (x11_display_name);
worker->priv->x11_authority_file = g_strdup (x11_authority_file);
worker->priv->display_device = g_strdup (console);
worker->priv->display_seat_id = g_strdup (seat_id);
worker->priv->hostname = g_strdup (hostname);
worker->priv->display_is_local = display_is_local;
worker->priv->display_is_initial = display_is_initial;
worker->priv->username = NULL;
worker->priv->user_settings = gdm_session_settings_new ();
g_signal_connect_swapped (worker->priv->user_settings,
"notify::language-name",
G_CALLBACK (on_saved_language_name_read),
worker);
g_signal_connect_swapped (worker->priv->user_settings,
"notify::session-name",
G_CALLBACK (on_saved_session_name_read),
worker);
+ g_signal_connect_swapped (worker->priv->user_settings,
+ "notify::session-type",
+ G_CALLBACK (on_saved_session_type_read),
+ worker);
+
return TRUE;
}
static gboolean
gdm_session_worker_handle_setup_for_user (GdmDBusWorker *object,
GDBusMethodInvocation *invocation,
const char *service,
const char *username,
const char *x11_display_name,
const char *x11_authority_file,
const char *console,
const char *seat_id,
const char *hostname,
gboolean display_is_local,
gboolean display_is_initial)
{
GdmSessionWorker *worker = GDM_SESSION_WORKER (object);
if (!validate_state_change (worker, invocation, GDM_SESSION_WORKER_STATE_SETUP_COMPLETE))
return TRUE;
worker->priv->service = g_strdup (service);
worker->priv->x11_display_name = g_strdup (x11_display_name);
worker->priv->x11_authority_file = g_strdup (x11_authority_file);
worker->priv->display_device = g_strdup (console);
worker->priv->display_seat_id = g_strdup (seat_id);
worker->priv->hostname = g_strdup (hostname);
worker->priv->display_is_local = display_is_local;
worker->priv->display_is_initial = display_is_initial;
worker->priv->username = g_strdup (username);
worker->priv->user_settings = gdm_session_settings_new ();
g_signal_connect_swapped (worker->priv->user_settings,
"notify::language-name",
G_CALLBACK (on_saved_language_name_read),
worker);
g_signal_connect_swapped (worker->priv->user_settings,
"notify::session-name",
G_CALLBACK (on_saved_session_name_read),
worker);
+ g_signal_connect_swapped (worker->priv->user_settings,
+ "notify::session-type",
+ G_CALLBACK (on_saved_session_type_read),
+ worker);
/* Load settings from accounts daemon before continuing
*/
worker->priv->pending_invocation = invocation;
if (gdm_session_settings_load (worker->priv->user_settings, username)) {
queue_state_change (worker);
} else {
g_signal_connect (G_OBJECT (worker->priv->user_settings),
"notify::is-loaded",
G_CALLBACK (on_settings_is_loaded_changed),
worker);
}
return TRUE;
}
static gboolean
gdm_session_worker_handle_setup_for_program (GdmDBusWorker *object,
GDBusMethodInvocation *invocation,
const char *service,
const char *username,
const char *x11_display_name,
const char *x11_authority_file,
const char *console,
const char *seat_id,
const char *hostname,
gboolean display_is_local,
gboolean display_is_initial,
const char *log_file)
{
diff --git a/daemon/gdm-session-worker.xml b/daemon/gdm-session-worker.xml
index 4280fe09..a215779c 100644
--- a/daemon/gdm-session-worker.xml
+++ b/daemon/gdm-session-worker.xml
@@ -51,40 +51,43 @@
<method name="SetupForProgram">
<arg name="service_name" direction="in" type="s"/>
<arg name="user_name" direction="in" type="s"/>
<arg name="x11_display_name" direction="in" type="s"/>
<arg name="x11_authority_file" direction="in" type="s"/>
<arg name="display_device" direction="in" type="s"/>
<arg name="display_seat" direction="in" type="s"/>
<arg name="hostname" direction="in" type="s"/>
<arg name="display_is_local" direction="in" type="b"/>
<arg name="display_is_initial" direction="in" type="b"/>
<arg name="log_file" direction="in" type="s"/>
</method>
<method name="StartReauthentication">
<arg name="pid_of_caller" direction="in" type="i"/>
<arg name="uid_of_caller" direction="in" type="i"/>
<arg name="address" direction="out" type="s"/>
</method>
<signal name="SessionExited">
<arg name="service_name" type="s" />
<!-- This is a combination of exit code and exit
signal. Use macros in sys/wait.h to handle it. -->
<arg name="status" type="i" />
</signal>
<signal name="SavedLanguageNameRead">
<arg name="language_name" type="s"/>
</signal>
<signal name="SavedSessionNameRead">
<arg name="session_name" type="s"/>
</signal>
+ <signal name="SavedSessionTypeRead">
+ <arg name="session_type" type="s"/>
+ </signal>
<signal name="UsernameChanged">
<arg name="new_username" type="s"/>
</signal>
<signal name="Reauthenticated">
<arg name="service_name" type="s"/>
</signal>
<signal name="CancelPendingQuery">
</signal>
</interface>
</node>
diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
index 29459346..43da024f 100644
--- a/daemon/gdm-session.c
+++ b/daemon/gdm-session.c
@@ -61,60 +61,61 @@
#define GDM_SESSION_DBUS_OBJECT_PATH "/org/gnome/DisplayManager/Session"
#define GDM_WORKER_DBUS_PATH "/org/gnome/DisplayManager/Worker"
typedef struct
{
GdmSession *session;
GdmSessionWorkerJob *job;
GPid worker_pid;
char *service_name;
GDBusMethodInvocation *starting_invocation;
char *starting_username;
GDBusMethodInvocation *pending_invocation;
GdmDBusWorkerManager *worker_manager_interface;
GdmDBusWorker *worker_proxy;
GCancellable *worker_cancellable;
char *session_id;
guint32 is_stopping : 1;
GPid reauth_pid_of_caller;
} GdmSessionConversation;
struct _GdmSession
{
GObject parent;
/* per open scope */
char *selected_program;
char *selected_session;
char *saved_session;
+ char *saved_session_type;
char *saved_language;
char *selected_user;
char *user_x11_authority_file;
char *timed_login_username;
int timed_login_delay;
GList *pending_timed_login_invocations;
GHashTable *conversations;
GdmSessionConversation *session_conversation;
char **conversation_environment;
GdmDBusUserVerifier *user_verifier_interface;
GHashTable *user_verifier_extensions;
GdmDBusGreeter *greeter_interface;
GdmDBusRemoteGreeter *remote_greeter_interface;
GdmDBusChooser *chooser_interface;
GList *pending_worker_connections;
GList *outside_connections;
GPid session_pid;
/* object lifetime scope */
char *session_type;
char *display_name;
char *display_hostname;
char *display_device;
@@ -328,309 +329,325 @@ on_establish_credentials_cb (GdmDBusWorker *proxy,
case GDM_SESSION_VERIFICATION_MODE_REAUTHENTICATE:
if (self->user_verifier_interface != NULL) {
gdm_dbus_user_verifier_emit_verification_complete (self->user_verifier_interface,
service_name);
g_signal_emit (self, signals[VERIFICATION_COMPLETE], 0, service_name);
}
break;
default:
break;
}
} else {
report_and_stop_conversation (self, service_name, error);
}
g_free (service_name);
g_object_unref (self);
}
static gboolean
supports_session_type (GdmSession *self,
const char *session_type)
{
if (session_type == NULL)
return TRUE;
return g_strv_contains ((const char * const *) self->supported_session_types,
session_type);
}
static char **
-get_system_session_dirs (GdmSession *self)
+get_system_session_dirs (GdmSession *self,
+ const char *type)
{
GArray *search_array = NULL;
char **search_dirs;
int i, j;
const gchar * const *system_data_dirs = g_get_system_data_dirs ();
static const char *x_search_dirs[] = {
"/etc/X11/sessions/",
DMCONFDIR "/Sessions/",
DATADIR "/gdm/BuiltInSessions/",
DATADIR "/xsessions/",
};
static const char *wayland_search_dir = DATADIR "/wayland-sessions/";
search_array = g_array_new (TRUE, TRUE, sizeof (char *));
for (j = 0; self->supported_session_types[j] != NULL; j++) {
const char *supported_type = self->supported_session_types[j];
- if (g_str_equal (supported_type, "x11")) {
+ if (g_str_equal (supported_type, "x11") ||
+ (type == NULL || g_str_equal (type, supported_type))) {
for (i = 0; system_data_dirs[i]; i++) {
gchar *dir = g_build_filename (system_data_dirs[i], "xsessions", NULL);
g_array_append_val (search_array, dir);
}
g_array_append_vals (search_array, x_search_dirs, G_N_ELEMENTS (x_search_dirs));
}
#ifdef ENABLE_WAYLAND_SUPPORT
- if (g_str_equal (supported_type, "wayland")) {
+ if (g_str_equal (supported_type, "wayland") ||
+ (type == NULL || g_str_equal (type, supported_type))) {
for (i = 0; system_data_dirs[i]; i++) {
gchar *dir = g_build_filename (system_data_dirs[i], "wayland-sessions", NULL);
g_array_append_val (search_array, dir);
}
g_array_append_val (search_array, wayland_search_dir);
}
#endif
}
search_dirs = g_strdupv ((char **) search_array->data);
g_array_free (search_array, TRUE);
return search_dirs;
}
static gboolean
is_prog_in_path (const char *prog)
{
char *f;
gboolean ret;
f = g_find_program_in_path (prog);
ret = (f != NULL);
g_free (f);
return ret;
}
static GKeyFile *
load_key_file_for_file (GdmSession *self,
const char *file,
+ const char *type,
char **full_path)
{
GKeyFile *key_file;
- GError *error;
+ GError *error = NULL;
gboolean res;
char **search_dirs;
key_file = g_key_file_new ();
- search_dirs = get_system_session_dirs (self),
+ search_dirs = get_system_session_dirs (self, type);
+
error = NULL;
res = g_key_file_load_from_dirs (key_file,
file,
(const char **) search_dirs,
full_path,
G_KEY_FILE_NONE,
&error);
if (! res) {
- g_debug ("GdmSession: File '%s' not found: %s", file, error->message);
- g_error_free (error);
+ g_debug ("GdmSession: File '%s' not found in search dirs", file);
+ if (error != NULL) {
+ g_debug ("GdmSession: %s", error->message);
+ g_error_free (error);
+ }
g_key_file_free (key_file);
key_file = NULL;
}
g_strfreev (search_dirs);
return key_file;
}
static gboolean
get_session_command_for_file (GdmSession *self,
const char *file,
+ const char *type,
char **command)
{
GKeyFile *key_file;
GError *error;
char *exec;
gboolean ret;
gboolean res;
exec = NULL;
ret = FALSE;
if (command != NULL) {
*command = NULL;
}
+ if (!supports_session_type (self, type)) {
+ g_debug ("GdmSession: ignoring %s session command request for file '%s'",
+ type, file);
+ goto out;
+ }
+
g_debug ("GdmSession: getting session command for file '%s'", file);
- key_file = load_key_file_for_file (self, file, NULL);
+ key_file = load_key_file_for_file (self, file, type, NULL);
if (key_file == NULL) {
goto out;
}
error = NULL;
res = g_key_file_get_boolean (key_file,
G_KEY_FILE_DESKTOP_GROUP,
G_KEY_FILE_DESKTOP_KEY_HIDDEN,
&error);
if (error == NULL && res) {
g_debug ("GdmSession: Session %s is marked as hidden", file);
goto out;
}
exec = g_key_file_get_string (key_file,
G_KEY_FILE_DESKTOP_GROUP,
G_KEY_FILE_DESKTOP_KEY_TRY_EXEC,
NULL);
if (exec != NULL) {
res = is_prog_in_path (exec);
g_free (exec);
exec = NULL;
if (! res) {
g_debug ("GdmSession: Command not found: %s",
G_KEY_FILE_DESKTOP_KEY_TRY_EXEC);
goto out;
}
}
error = NULL;
exec = g_key_file_get_string (key_file,
G_KEY_FILE_DESKTOP_GROUP,
G_KEY_FILE_DESKTOP_KEY_EXEC,
&error);
if (error != NULL) {
g_debug ("GdmSession: %s key not found: %s",
G_KEY_FILE_DESKTOP_KEY_EXEC,
error->message);
g_error_free (error);
goto out;
}
if (command != NULL) {
*command = g_strdup (exec);
}
ret = TRUE;
out:
g_free (exec);
return ret;
}
static gboolean
get_session_command_for_name (GdmSession *self,
const char *name,
+ const char *type,
char **command)
{
gboolean res;
char *filename;
filename = g_strdup_printf ("%s.desktop", name);
- res = get_session_command_for_file (self, filename, command);
+ res = get_session_command_for_file (self, filename, type, command);
g_free (filename);
return res;
}
static const char *
get_default_language_name (GdmSession *self)
{
const char *default_language;
if (self->saved_language != NULL) {
return self->saved_language;
}
default_language = g_hash_table_lookup (self->environment,
"LANG");
if (default_language != NULL) {
return default_language;
}
return setlocale (LC_MESSAGES, NULL);
}
static const char *
get_fallback_session_name (GdmSession *self)
{
char **search_dirs;
int i;
char *name;
GSequence *sessions;
GSequenceIter *session;
if (self->fallback_session_name != NULL) {
/* verify that the cached version still exists */
- if (get_session_command_for_name (self, self->fallback_session_name, NULL)) {
+ if (get_session_command_for_name (self, self->fallback_session_name, NULL, NULL)) {
goto out;
}
}
name = g_strdup ("gnome");
- if (get_session_command_for_name (self, name, NULL)) {
+ if (get_session_command_for_name (self, name, NULL, NULL)) {
g_free (self->fallback_session_name);
self->fallback_session_name = name;
goto out;
}
g_free (name);
sessions = g_sequence_new (g_free);
- search_dirs = get_system_session_dirs (self);
+ search_dirs = get_system_session_dirs (self, NULL);
for (i = 0; search_dirs[i] != NULL; i++) {
GDir *dir;
const char *base_name;
dir = g_dir_open (search_dirs[i], 0, NULL);
if (dir == NULL) {
continue;
}
do {
base_name = g_dir_read_name (dir);
if (base_name == NULL) {
break;
}
if (!g_str_has_suffix (base_name, ".desktop")) {
continue;
}
- if (get_session_command_for_file (self, base_name, NULL)) {
+ if (get_session_command_for_file (self, base_name, NULL, NULL)) {
name = g_strndup (base_name, strlen (base_name) - strlen (".desktop"));
g_sequence_insert_sorted (sessions, name, (GCompareDataFunc) g_strcmp0, NULL);
}
} while (base_name != NULL);
g_dir_close (dir);
}
g_strfreev (search_dirs);
name = NULL;
session = g_sequence_get_begin_iter (sessions);
if (g_sequence_iter_is_end (session))
g_error ("GdmSession: no session desktop files installed, aborting...");
do {
name = g_sequence_get (session);
if (name) {
break;
}
session = g_sequence_iter_next (session);
} while (!g_sequence_iter_is_end (session));
g_free (self->fallback_session_name);
self->fallback_session_name = g_strdup (name);
g_sequence_free (sessions);
out:
return self->fallback_session_name;
@@ -649,60 +666,63 @@ get_default_session_name (GdmSession *self)
static void
gdm_session_defaults_changed (GdmSession *self)
{
update_session_type (self);
if (self->greeter_interface != NULL) {
gdm_dbus_greeter_emit_default_language_name_changed (self->greeter_interface,
get_default_language_name (self));
gdm_dbus_greeter_emit_default_session_name_changed (self->greeter_interface,
get_default_session_name (self));
}
}
void
gdm_session_select_user (GdmSession *self,
const char *text)
{
g_debug ("GdmSession: selecting user '%s' for session '%s' (%p)",
text,
gdm_session_get_session_id (self),
self);
g_free (self->selected_user);
self->selected_user = g_strdup (text);
g_free (self->saved_session);
self->saved_session = NULL;
+ g_free (self->saved_session_type);
+ self->saved_session_type = NULL;
+
g_free (self->saved_language);
self->saved_language = NULL;
}
static void
cancel_pending_query (GdmSessionConversation *conversation)
{
if (conversation->pending_invocation == NULL) {
return;
}
g_debug ("GdmSession: Cancelling pending query");
g_dbus_method_invocation_return_dbus_error (conversation->pending_invocation,
GDM_SESSION_DBUS_ERROR_CANCEL,
"Operation cancelled");
conversation->pending_invocation = NULL;
}
static void
answer_pending_query (GdmSessionConversation *conversation,
const char *answer)
{
g_dbus_method_invocation_return_value (conversation->pending_invocation,
g_variant_new ("(s)", answer));
conversation->pending_invocation = NULL;
}
static void
set_pending_query (GdmSessionConversation *conversation,
@@ -969,83 +989,94 @@ worker_on_reauthenticated (GdmDBusWorker *worker,
GdmSession *self = conversation->session;
g_debug ("GdmSession: Emitting 'reauthenticated' signal ");
g_signal_emit (self, signals[REAUTHENTICATED], 0, service_name);
}
static void
worker_on_saved_language_name_read (GdmDBusWorker *worker,
const char *language_name,
GdmSessionConversation *conversation)
{
GdmSession *self = conversation->session;
if (strlen (language_name) > 0) {
g_free (self->saved_language);
self->saved_language = g_strdup (language_name);
if (self->greeter_interface != NULL) {
gdm_dbus_greeter_emit_default_language_name_changed (self->greeter_interface,
language_name);
}
}
}
static void
worker_on_saved_session_name_read (GdmDBusWorker *worker,
const char *session_name,
GdmSessionConversation *conversation)
{
GdmSession *self = conversation->session;
- if (! get_session_command_for_name (self, session_name, NULL)) {
+ if (! get_session_command_for_name (self, session_name, self->saved_session_type, NULL)) {
/* ignore sessions that don't exist */
g_debug ("GdmSession: not using invalid .dmrc session: %s", session_name);
g_free (self->saved_session);
self->saved_session = NULL;
update_session_type (self);
} else {
if (strcmp (session_name,
get_default_session_name (self)) != 0) {
g_free (self->saved_session);
self->saved_session = g_strdup (session_name);
if (self->greeter_interface != NULL) {
gdm_dbus_greeter_emit_default_session_name_changed (self->greeter_interface,
session_name);
}
}
if (self->saved_session_type != NULL)
set_session_type (self, self->saved_session_type);
}
}
+static void
+worker_on_saved_session_type_read (GdmDBusWorker *worker,
+ const char *session_type,
+ GdmSessionConversation *conversation)
+{
+ GdmSession *self = conversation->session;
+
+ g_free (self->saved_session_type);
+ self->saved_session_type = g_strdup (session_type);
+}
+
static GdmSessionConversation *
find_conversation_by_pid (GdmSession *self,
GPid pid)
{
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init (&iter, self->conversations);
while (g_hash_table_iter_next (&iter, &key, &value)) {
GdmSessionConversation *conversation;
conversation = (GdmSessionConversation *) value;
if (conversation->worker_pid == pid) {
return conversation;
}
}
return NULL;
}
static gboolean
allow_worker_function (GDBusAuthObserver *observer,
GIOStream *stream,
GCredentials *credentials,
GdmSession *self)
{
uid_t connecting_user;
connecting_user = g_credentials_get_unix_user (credentials, NULL);
@@ -1125,60 +1156,63 @@ register_worker (GdmDBusWorkerManager *worker_manager_interface,
g_dbus_method_invocation_return_value (invocation, NULL);
conversation->worker_proxy = gdm_dbus_worker_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
GDM_WORKER_DBUS_PATH,
NULL, NULL);
/* drop the reference we stole from the pending connections list
* since the proxy owns the connection now */
g_object_unref (connection);
g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (conversation->worker_proxy), G_MAXINT);
conversation->worker_cancellable = g_cancellable_new ();
g_signal_connect (conversation->worker_proxy,
"username-changed",
G_CALLBACK (worker_on_username_changed), conversation);
g_signal_connect (conversation->worker_proxy,
"session-exited",
G_CALLBACK (worker_on_session_exited), conversation);
g_signal_connect (conversation->worker_proxy,
"reauthenticated",
G_CALLBACK (worker_on_reauthenticated), conversation);
g_signal_connect (conversation->worker_proxy,
"saved-language-name-read",
G_CALLBACK (worker_on_saved_language_name_read), conversation);
g_signal_connect (conversation->worker_proxy,
"saved-session-name-read",
G_CALLBACK (worker_on_saved_session_name_read), conversation);
+ g_signal_connect (conversation->worker_proxy,
+ "saved-session-type-read",
+ G_CALLBACK (worker_on_saved_session_type_read), conversation);
g_signal_connect (conversation->worker_proxy,
"cancel-pending-query",
G_CALLBACK (worker_on_cancel_pending_query), conversation);
conversation->worker_manager_interface = g_object_ref (worker_manager_interface);
g_debug ("GdmSession: worker connection is %p", connection);
g_debug ("GdmSession: Emitting conversation-started signal");
g_signal_emit (self, signals[CONVERSATION_STARTED], 0, conversation->service_name);
if (self->user_verifier_interface != NULL) {
gdm_dbus_user_verifier_emit_conversation_started (self->user_verifier_interface,
conversation->service_name);
}
if (conversation->starting_invocation != NULL) {
if (conversation->starting_username != NULL) {
gdm_session_setup_for_user (self, conversation->service_name, conversation->starting_username);
g_clear_pointer (&conversation->starting_username,
(GDestroyNotify)
g_free);
} else {
gdm_session_setup (self, conversation->service_name);
}
}
g_debug ("GdmSession: Conversation started");
return TRUE;
@@ -1921,60 +1955,63 @@ free_conversation (GdmSessionConversation *conversation)
close_conversation (conversation);
if (conversation->job != NULL) {
g_warning ("Freeing conversation '%s' with active job", conversation->service_name);
}
g_free (conversation->service_name);
g_free (conversation->starting_username);
g_free (conversation->session_id);
g_clear_object (&conversation->worker_manager_interface);
g_cancellable_cancel (conversation->worker_cancellable);
g_clear_object (&conversation->worker_cancellable);
if (conversation->worker_proxy != NULL) {
g_signal_handlers_disconnect_by_func (conversation->worker_proxy,
G_CALLBACK (worker_on_username_changed),
conversation);
g_signal_handlers_disconnect_by_func (conversation->worker_proxy,
G_CALLBACK (worker_on_session_exited),
conversation);
g_signal_handlers_disconnect_by_func (conversation->worker_proxy,
G_CALLBACK (worker_on_reauthenticated),
conversation);
g_signal_handlers_disconnect_by_func (conversation->worker_proxy,
G_CALLBACK (worker_on_saved_language_name_read),
conversation);
g_signal_handlers_disconnect_by_func (conversation->worker_proxy,
G_CALLBACK (worker_on_saved_session_name_read),
conversation);
+ g_signal_handlers_disconnect_by_func (conversation->worker_proxy,
+ G_CALLBACK (worker_on_saved_session_type_read),
+ conversation);
g_signal_handlers_disconnect_by_func (conversation->worker_proxy,
G_CALLBACK (worker_on_cancel_pending_query),
conversation);
g_clear_object (&conversation->worker_proxy);
}
g_clear_object (&conversation->session);
g_free (conversation);
}
static void
load_lang_config_file (GdmSession *self)
{
static const char *config_file = LANG_CONFIG_FILE;
gchar *contents = NULL;
gchar *p;
gchar *key;
gchar *value;
gsize length;
GError *error;
GString *line;
GRegex *re;
if (!g_file_test (config_file, G_FILE_TEST_EXISTS)) {
g_debug ("Cannot access '%s'", config_file);
return;
}
error = NULL;
if (!g_file_get_contents (config_file, &contents, &length, &error)) {
g_debug ("Failed to parse '%s': %s",
@@ -2533,83 +2570,83 @@ gdm_session_send_environment (GdmSession *self,
g_return_if_fail (GDM_IS_SESSION (self));
conversation = find_conversation_by_name (self, service_name);
if (conversation != NULL) {
send_environment (self, conversation);
}
}
static const char *
get_session_name (GdmSession *self)
{
/* FIXME: test the session names before we use them? */
if (self->selected_session != NULL) {
return self->selected_session;
}
return get_default_session_name (self);
}
static char *
get_session_command (GdmSession *self)
{
gboolean res;
char *command;
const char *session_name;
session_name = get_session_name (self);
command = NULL;
- res = get_session_command_for_name (self, session_name, &command);
+ res = get_session_command_for_name (self, session_name, NULL, &command);
if (! res) {
g_critical ("Cannot find a command for specified session: %s", session_name);
exit (EXIT_FAILURE);
}
return command;
}
static gchar *
get_session_desktop_names (GdmSession *self)
{
gchar *filename;
GKeyFile *keyfile;
gchar *desktop_names = NULL;
if (self->selected_program != NULL) {
return g_strdup ("GNOME-Greeter:GNOME");
}
filename = g_strdup_printf ("%s.desktop", get_session_name (self));
g_debug ("GdmSession: getting desktop names for file '%s'", filename);
- keyfile = load_key_file_for_file (self, filename, NULL);
+ keyfile = load_key_file_for_file (self, filename, NULL, NULL);
if (keyfile != NULL) {
gchar **names;
names = g_key_file_get_string_list (keyfile, G_KEY_FILE_DESKTOP_GROUP,
"DesktopNames", NULL, NULL);
if (names != NULL) {
desktop_names = g_strjoinv (":", names);
g_strfreev (names);
}
}
g_key_file_free (keyfile);
g_free (filename);
return desktop_names;
}
void
gdm_session_set_environment_variable (GdmSession *self,
const char *key,
const char *value)
{
g_return_if_fail (key != NULL);
g_return_if_fail (value != NULL);
g_hash_table_replace (self->environment,
g_strdup (key),
g_strdup (value));
}
@@ -3179,148 +3216,150 @@ gdm_session_get_conversation_session_id (GdmSession *self,
conversation = find_conversation_by_name (self, service_name);
if (conversation == NULL) {
return NULL;
}
return conversation->session_id;
}
static char *
get_session_filename (GdmSession *self)
{
return g_strdup_printf ("%s.desktop", get_session_name (self));
}
#ifdef ENABLE_WAYLAND_SUPPORT
static gboolean
gdm_session_is_wayland_session (GdmSession *self)
{
GKeyFile *key_file;
gboolean is_wayland_session = FALSE;
char *filename;
char *full_path = NULL;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (GDM_IS_SESSION (self), FALSE);
filename = get_session_filename (self);
if (supports_session_type (self, "wayland")) {
- key_file = load_key_file_for_file (self, filename, &full_path);
+ key_file = load_key_file_for_file (self, filename, NULL, &full_path);
- if (key_file == NULL) {
- goto out;
- }
+ if (key_file == NULL) {
+ goto out;
+ }
}
if (full_path != NULL && strstr (full_path, "/wayland-sessions/") != NULL) {
is_wayland_session = TRUE;
}
g_debug ("GdmSession: checking if file '%s' is wayland session: %s", filename, is_wayland_session? "yes" : "no");
out:
g_clear_pointer (&key_file, g_key_file_free);
g_free (filename);
return is_wayland_session;
}
#endif
static void
update_session_type (GdmSession *self)
{
#ifdef ENABLE_WAYLAND_SUPPORT
- gboolean is_wayland_session;
+ gboolean is_wayland_session = FALSE;
+
+ if (supports_session_type (self, "wayland"))
+ is_wayland_session = gdm_session_is_wayland_session (self);
- is_wayland_session = gdm_session_is_wayland_session (self);
if (is_wayland_session) {
set_session_type (self, "wayland");
} else {
set_session_type (self, NULL);
}
#endif
}
gboolean
gdm_session_session_registers (GdmSession *self)
{
g_autoptr(GError) error = NULL;
g_autoptr(GKeyFile) key_file = NULL;
gboolean session_registers = FALSE;
g_autofree char *filename = NULL;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (GDM_IS_SESSION (self), FALSE);
filename = get_session_filename (self);
- key_file = load_key_file_for_file (self, filename, NULL);
+ key_file = load_key_file_for_file (self, filename, NULL, NULL);
session_registers = g_key_file_get_boolean (key_file,
G_KEY_FILE_DESKTOP_GROUP,
"X-GDM-SessionRegisters",
&error);
if (!session_registers &&
error != NULL &&
!g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND)) {
g_warning ("GdmSession: Couldn't read session file '%s'", filename);
return FALSE;
}
g_debug ("GdmSession: '%s' %s self", filename,
session_registers ? "registers" : "does not register");
return session_registers;
}
gboolean
gdm_session_bypasses_xsession (GdmSession *self)
{
GError *error;
GKeyFile *key_file;
gboolean res;
gboolean bypasses_xsession = FALSE;
char *filename = NULL;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (GDM_IS_SESSION (self), FALSE);
#ifdef ENABLE_WAYLAND_SUPPORT
if (gdm_session_is_wayland_session (self)) {
bypasses_xsession = TRUE;
goto out;
}
#endif
filename = get_session_filename (self);
- key_file = load_key_file_for_file (self, filename, NULL);
+ key_file = load_key_file_for_file (self, filename, "x11", NULL);
error = NULL;
res = g_key_file_has_key (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GDM-BypassXsession", NULL);
if (!res) {
goto out;
} else {
bypasses_xsession = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GDM-BypassXsession", &error);
if (error) {
bypasses_xsession = FALSE;
g_error_free (error);
goto out;
}
}
out:
if (bypasses_xsession) {
g_debug ("GdmSession: Session %s bypasses Xsession wrapper script", filename);
}
g_free (filename);
return bypasses_xsession;
}
GdmSessionDisplayMode
gdm_session_get_display_mode (GdmSession *self)
{
g_debug ("GdmSession: type %s, program? %s, seat %s",
self->session_type,
self->is_program_session? "yes" : "no",
self->display_seat_id);
--
2.27.0