[gdm/fix-jump-back-to-login-screen: 1/21] local-display-factory: Provide more flexibility for configuring display server




commit 881455d1f1d4ce4be051dbcaef8acbb7b64bff9d
Author: Ray Strode <rstrode redhat com>
Date:   Fri Jul 16 12:34:57 2021 -0400

    local-display-factory: Provide more flexibility for configuring display server
    
    There's currently a way to disable wayland, but no way to disable Xorg.
    We currently prefer wayland if it's not disabled, but have no way to
    prefer Xorg without disabling wayland entirely.
    
    There's currently no way use legacy Xorg support at all if user display
    server support is enabled at a build time.
    
    This commit adds more flexibility to display server selection. It adds
    two new keys: XorgEnable and and PreferredDisplayServer.
    
    XorgEnable=false disables Xorg support entirely on seat 0.
    
    PreferredDisplayServer can be set to "wayland", "xorg", "legacy-xorg" or
    "none" to select which display server is used by default. If it's set to
    "wayland", it will fall back to "xorg". If it's set to "xorg" it will
    fall back to "wayland".

 common/gdm-settings-keys.h         |   2 +
 daemon/gdm-display.c               |  36 ++++++
 daemon/gdm-launch-environment.c    |   9 ++
 daemon/gdm-local-display-factory.c | 224 ++++++++++++++++++++++++++++++-------
 daemon/gdm-manager.c               |  22 ++--
 daemon/gdm-session.c               | 115 ++++++++++---------
 data/gdm.schemas.in                |  10 ++
 libgdm/gdm-sessions.c              |  72 ++++++++----
 8 files changed, 366 insertions(+), 124 deletions(-)
---
diff --git a/common/gdm-settings-keys.h b/common/gdm-settings-keys.h
index f0059b5cf..87685d3cd 100644
--- a/common/gdm-settings-keys.h
+++ b/common/gdm-settings-keys.h
@@ -33,7 +33,9 @@ G_BEGIN_DECLS
 #define GDM_KEY_TIMED_LOGIN_USER "daemon/TimedLogin"
 #define GDM_KEY_TIMED_LOGIN_DELAY "daemon/TimedLoginDelay"
 #define GDM_KEY_INITIAL_SETUP_ENABLE "daemon/InitialSetupEnable"
+#define GDM_KEY_PREFERRED_DISPLAY_SERVER "daemon/PreferredDisplayServer"
 #define GDM_KEY_WAYLAND_ENABLE "daemon/WaylandEnable"
+#define GDM_KEY_XORG_ENABLE "daemon/XorgEnable"
 
 #define GDM_KEY_DEBUG "debug/Enable"
 
diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c
index 3a260923a..344678564 100644
--- a/daemon/gdm-display.c
+++ b/daemon/gdm-display.c
@@ -93,6 +93,8 @@ typedef struct _GdmDisplayPrivate
         guint                 have_existing_user_accounts : 1;
         guint                 doing_initial_setup : 1;
         guint                 session_registered : 1;
+
+        GStrv                 supported_session_types;
 } GdmDisplayPrivate;
 
 enum {
@@ -116,6 +118,7 @@ enum {
         PROP_HAVE_EXISTING_USER_ACCOUNTS,
         PROP_DOING_INITIAL_SETUP,
         PROP_SESSION_REGISTERED,
+        PROP_SUPPORTED_SESSION_TYPES,
 };
 
 static void     gdm_display_class_init  (GdmDisplayClass *klass);
@@ -910,6 +913,23 @@ _gdm_display_set_allow_timed_login (GdmDisplay     *self,
         priv->allow_timed_login = allow_timed_login;
 }
 
+static void
+_gdm_display_set_supported_session_types (GdmDisplay         *self,
+                                          const char * const *supported_session_types)
+
+{
+        GdmDisplayPrivate *priv;
+        g_autofree char *supported_session_types_string = NULL;
+
+        if (supported_session_types != NULL)
+                supported_session_types_string = g_strjoinv (":", (GStrv) supported_session_types);
+
+        priv = gdm_display_get_instance_private (self);
+        g_debug ("GdmDisplay: supported session types: %s", supported_session_types_string);
+        g_strfreev (priv->supported_session_types);
+        priv->supported_session_types = g_strdupv ((GStrv) supported_session_types);
+}
+
 static void
 gdm_display_set_property (GObject        *object,
                           guint           prop_id,
@@ -966,6 +986,9 @@ gdm_display_set_property (GObject        *object,
         case PROP_SESSION_REGISTERED:
                 _gdm_display_set_session_registered (self, g_value_get_boolean (value));
                 break;
+        case PROP_SUPPORTED_SESSION_TYPES:
+                _gdm_display_set_supported_session_types (self, g_value_get_boxed (value));
+                break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -1044,6 +1067,9 @@ gdm_display_get_property (GObject        *object,
         case PROP_ALLOW_TIMED_LOGIN:
                 g_value_set_boolean (value, priv->allow_timed_login);
                 break;
+        case PROP_SUPPORTED_SESSION_TYPES:
+                g_value_set_boxed (value, priv->supported_session_types);
+                break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -1229,6 +1255,7 @@ gdm_display_dispose (GObject *object)
                 priv->finish_idle_id = 0;
         }
         g_clear_object (&priv->launch_environment);
+        g_clear_pointer (&priv->supported_session_types, g_strfreev);
 
         g_warn_if_fail (priv->status != GDM_DISPLAY_MANAGED);
         g_warn_if_fail (priv->user_access_file == NULL);
@@ -1389,6 +1416,14 @@ gdm_display_class_init (GdmDisplayClass *klass)
                                                            G_MAXINT,
                                                            GDM_DISPLAY_UNMANAGED,
                                                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT | 
G_PARAM_STATIC_STRINGS));
+
+        g_object_class_install_property (object_class,
+                                         PROP_SUPPORTED_SESSION_TYPES,
+                                         g_param_spec_boxed ("supported-session-types",
+                                                             "supported session types",
+                                                             "supported session types",
+                                                             G_TYPE_STRV,
+                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT | 
G_PARAM_STATIC_STRINGS));
 }
 
 static void
@@ -1721,6 +1756,7 @@ gdm_display_start_greeter_session (GdmDisplay *self)
         session = gdm_launch_environment_get_session (priv->launch_environment);
         g_object_set (G_OBJECT (session),
                       "display-is-initial", priv->is_initial,
+                      "supported-session-types", priv->supported_session_types,
                       NULL);
 
         g_free (display_name);
diff --git a/daemon/gdm-launch-environment.c b/daemon/gdm-launch-environment.c
index 87a1c5ffe..14ecfac2d 100644
--- a/daemon/gdm-launch-environment.c
+++ b/daemon/gdm-launch-environment.c
@@ -161,6 +161,7 @@ build_launch_environment (GdmLaunchEnvironment *launch_environment,
                 NULL
         };
         char *system_data_dirs;
+        g_auto (GStrv) supported_session_types = NULL;
         int i;
 
         /* create a hash table of current environment, then update keys has necessary */
@@ -244,6 +245,14 @@ build_launch_environment (GdmLaunchEnvironment *launch_environment,
                                               system_data_dirs));
         g_free (system_data_dirs);
 
+        g_object_get (launch_environment->priv->session,
+                      "supported-session-types",
+                      &supported_session_types,
+                      NULL);
+        g_hash_table_insert (hash,
+                             g_strdup ("GDM_SUPPORTED_SESSION_TYPES"),
+                             g_strjoinv (":", supported_session_types));
+
         return hash;
 }
 
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
index 8a4ef06cd..141d64c6b 100644
--- a/daemon/gdm-local-display-factory.c
+++ b/daemon/gdm-local-display-factory.c
@@ -183,6 +183,93 @@ take_next_display_number (GdmLocalDisplayFactory *factory)
         return ret;
 }
 
+static char *
+get_preferred_display_server (GdmLocalDisplayFactory *factory)
+{
+        g_autofree gchar *preferred_display_server = NULL;
+        gboolean wayland_enabled = FALSE, xorg_enabled = FALSE;
+
+        gdm_settings_direct_get_boolean (GDM_KEY_WAYLAND_ENABLE, &wayland_enabled);
+        gdm_settings_direct_get_boolean (GDM_KEY_XORG_ENABLE, &xorg_enabled);
+
+        if (wayland_enabled && !xorg_enabled) {
+                return g_strdup ("wayland");
+        }
+
+        if (!wayland_enabled && !xorg_enabled) {
+                return g_strdup ("none");
+        }
+
+        gdm_settings_direct_get_string (GDM_KEY_PREFERRED_DISPLAY_SERVER, &preferred_display_server);
+
+        if (g_strcmp0 (preferred_display_server, "wayland") == 0) {
+                if (wayland_enabled)
+                        return g_strdup (preferred_display_server);
+                else
+                        return g_strdup ("xorg");
+        }
+
+        if (g_strcmp0 (preferred_display_server, "xorg") == 0) {
+                if (xorg_enabled)
+                        return g_strdup (preferred_display_server);
+                else
+                        return g_strdup ("wayland");
+        }
+
+        if (g_strcmp0 (preferred_display_server, "legacy-xorg") == 0) {
+                if (xorg_enabled)
+                        return g_strdup (preferred_display_server);
+        }
+
+        return g_strdup ("none");
+}
+
+static const char *
+gdm_local_display_factory_get_session_type (GdmLocalDisplayFactory *factory,
+                                            gboolean                should_fall_back)
+{
+        const char *session_types[3] = { NULL };
+        gsize i, session_type_index = 0;
+        g_autofree gchar *preferred_display_server = NULL;
+
+        preferred_display_server = get_preferred_display_server (factory);
+
+        if (g_strcmp0 (preferred_display_server, "wayland") != 0 &&
+            g_strcmp0 (preferred_display_server, "xorg") != 0)
+              return NULL;
+
+        for (i = 0; i < G_N_ELEMENTS (session_types) - 1; i++) {
+#ifdef ENABLE_WAYLAND_SUPPORT
+            if (i > 0 ||
+                g_strcmp0 (preferred_display_server, "wayland") == 0) {
+                    gboolean wayland_enabled = FALSE;
+                    if (gdm_settings_direct_get_boolean (GDM_KEY_WAYLAND_ENABLE, &wayland_enabled)) {
+                            if (wayland_enabled && g_file_test ("/usr/bin/Xwayland", 
G_FILE_TEST_IS_EXECUTABLE)) {
+                                    session_types[i] = "wayland";
+                                    continue;
+                            }
+                    }
+            }
+#endif
+
+            if (i > 0 ||
+                g_strcmp0 (preferred_display_server, "xorg") == 0) {
+                    gboolean xorg_enabled = FALSE;
+                    if (gdm_settings_direct_get_boolean (GDM_KEY_XORG_ENABLE, &xorg_enabled)) {
+                            if (xorg_enabled && g_file_test ("/usr/bin/Xorg", G_FILE_TEST_IS_EXECUTABLE)) {
+                                    session_types[i] = "x11";
+                                    continue;
+                            }
+                    }
+            }
+        }
+
+        if (should_fall_back)
+                session_type_index++;
+
+        return session_types[session_type_index];
+}
+
 static void
 on_display_disposed (GdmLocalDisplayFactory *factory,
                      GdmDisplay             *display)
@@ -200,19 +287,6 @@ store_display (GdmLocalDisplayFactory *factory,
         gdm_display_store_add (store, display);
 }
 
-static gboolean
-gdm_local_display_factory_use_wayland (void)
-{
-#ifdef ENABLE_WAYLAND_SUPPORT
-        gboolean wayland_enabled = FALSE;
-        if (gdm_settings_direct_get_boolean (GDM_KEY_WAYLAND_ENABLE, &wayland_enabled)) {
-                if (wayland_enabled && g_file_test ("/usr/bin/Xwayland", G_FILE_TEST_IS_EXECUTABLE) )
-                        return TRUE;
-        }
-#endif
-        return FALSE;
-}
-
 /*
   Example:
   dbus-send --system --dest=org.gnome.DisplayManager \
@@ -228,6 +302,8 @@ gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *fact
         gboolean         ret;
         GdmDisplay      *display = NULL;
         gboolean         is_initial = FALSE;
+        const char      *session_type;
+        g_autofree gchar *preferred_display_server = NULL;
 
         g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE);
 
@@ -235,20 +311,43 @@ gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *fact
 
         g_debug ("GdmLocalDisplayFactory: Creating transient display");
 
-#ifdef ENABLE_USER_DISPLAY_SERVER
-        display = gdm_local_display_new ();
-        if (gdm_local_display_factory_use_wayland ())
-                g_object_set (G_OBJECT (display), "session-type", "wayland", NULL);
-        is_initial = TRUE;
-#else
-        if (display == NULL) {
-                guint32 num;
+        preferred_display_server = get_preferred_display_server (factory);
 
-                num = take_next_display_number (factory);
+#ifdef ENABLE_USER_DISPLAY_SERVER
+        if (g_strcmp0 (preferred_display_server, "wayland") == 0 ||
+            g_strcmp0 (preferred_display_server, "xorg") == 0) {
+                session_type = gdm_local_display_factory_get_session_type (factory, FALSE);
+
+                if (session_type == NULL) {
+                        g_set_error_literal (error,
+                                             GDM_DISPLAY_ERROR,
+                                             GDM_DISPLAY_ERROR_GENERAL,
+                                             "Both Wayland and Xorg are unavailable");
+                        return FALSE;
+                }
 
-                display = gdm_legacy_display_new (num);
+                display = gdm_local_display_new ();
+                g_object_set (G_OBJECT (display), "session-type", session_type, NULL);
+                is_initial = TRUE;
         }
 #endif
+        if (g_strcmp0 (preferred_display_server, "legacy-xorg") == 0) {
+                if (display == NULL) {
+                        guint32 num;
+
+                        num = take_next_display_number (factory);
+
+                        display = gdm_legacy_display_new (num);
+                }
+        }
+
+        if (display == NULL) {
+                g_set_error_literal (error,
+                                     GDM_DISPLAY_ERROR,
+                                     GDM_DISPLAY_ERROR_GENERAL,
+                                     "Invalid preferred display server configured");
+                return FALSE;
+        }
 
         g_object_set (display,
                       "seat-id", "seat0",
@@ -481,6 +580,19 @@ ensure_display_for_seat (GdmLocalDisplayFactory *factory,
         GdmDisplayStore *store;
         GdmDisplay      *display = NULL;
         g_autofree char *login_session_id = NULL;
+        gboolean wayland_enabled = FALSE, xorg_enabled = FALSE;
+        g_autofree gchar *preferred_display_server = NULL;
+        gboolean falling_back;
+
+        gdm_settings_direct_get_boolean (GDM_KEY_WAYLAND_ENABLE, &wayland_enabled);
+        gdm_settings_direct_get_boolean (GDM_KEY_XORG_ENABLE, &xorg_enabled);
+
+        preferred_display_server = get_preferred_display_server (factory);
+
+        if (g_strcmp0 (preferred_display_server, "none") == 0) {
+               g_debug ("GdmLocalDisplayFactory: Preferred display server is none, so not creating display");
+               return;
+        }
 
         ret = sd_seat_can_graphical (seat_id);
 
@@ -500,21 +612,18 @@ ensure_display_for_seat (GdmLocalDisplayFactory *factory,
         if (g_strcmp0 (seat_id, "seat0") == 0) {
                 is_seat0 = TRUE;
 
-                /* If we've failed, or are explicitly told to, fall back to legacy X11 support
-                 */
-                if (factory->num_failures > 0 || !gdm_local_display_factory_use_wayland ()) {
-                        session_type = NULL;
-                        g_debug ("GdmLocalDisplayFactory: New displays on seat0 will use X11 fallback");
-                } else {
-                        g_debug ("GdmLocalDisplayFactory: New displays on seat0 will use wayland");
-                }
+                falling_back = factory->num_failures > 0;
+                session_type = gdm_local_display_factory_get_session_type (factory, falling_back);
+
+                g_debug ("GdmLocalDisplayFactory: New displays on seat0 will use %s%s",
+                         session_type, falling_back? " fallback" : "");
         } else {
                 is_seat0 = FALSE;
 
                 g_debug ("GdmLocalDisplayFactory: New displays on seat %s will use X11 fallback", seat_id);
                 /* Force legacy X11 for all auxiliary seats */
                 seat_supports_graphics = TRUE;
-                session_type = NULL;
+                session_type = "x11";
         }
 
         /* For seat0, we have a fallback logic to still try starting it after
@@ -552,7 +661,8 @@ ensure_display_for_seat (GdmLocalDisplayFactory *factory,
                         g_debug ("GdmLocalDisplayFactory: Assuming we can use seat0 for X11 even though 
system says it doesn't support graphics!");
                         g_debug ("GdmLocalDisplayFactory: This might indicate an issue where the framebuffer 
device is not tagged as master-of-seat in udev.");
                         seat_supports_graphics = TRUE;
-                        session_type = NULL;
+                        session_type = "x11";
+                        wayland_enabled = FALSE;
                 } else {
                         g_clear_handle_id (&factory->seat0_graphics_check_timeout_id, g_source_remove);
                 }
@@ -561,8 +671,13 @@ ensure_display_for_seat (GdmLocalDisplayFactory *factory,
         if (!seat_supports_graphics)
                 return;
 
-        g_debug ("GdmLocalDisplayFactory: %s login display for seat %s requested",
-                 session_type? : "X11", seat_id);
+        if (session_type != NULL)
+                g_debug ("GdmLocalDisplayFactory: %s login display for seat %s requested",
+                         session_type, seat_id);
+        else if (g_strcmp0 (preferred_display_server, "legacy-xorg") == 0)
+                g_debug ("GdmLocalDisplayFactory: Legacy Xorg login display for seat %s requested",
+                         seat_id);
+
         store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
 
         if (is_seat0)
@@ -597,20 +712,53 @@ ensure_display_for_seat (GdmLocalDisplayFactory *factory,
         g_debug ("GdmLocalDisplayFactory: Adding display on seat %s", seat_id);
 
 #ifdef ENABLE_USER_DISPLAY_SERVER
-        if (is_seat0) {
-                display = gdm_local_display_new ();
-                if (session_type != NULL) {
+        if (g_strcmp0 (preferred_display_server, "wayland") == 0 ||
+            g_strcmp0 (preferred_display_server, "xorg") == 0) {
+                if (is_seat0) {
+                        g_autoptr (GPtrArray) supported_session_types = NULL;
+
+                        if (session_type == NULL) {
+                                g_warning ("GdmLocalDisplayFactory: Both Wayland and Xorg sessions are 
unavailable");
+                                return;
+                        }
+
+                        supported_session_types = g_ptr_array_new ();
+
+                        if (g_strcmp0 (preferred_display_server, "wayland") == 0) {
+                                if (wayland_enabled)
+                                        g_ptr_array_add (supported_session_types, "wayland");
+                        } else {
+                                if (xorg_enabled)
+                                        g_ptr_array_add (supported_session_types, "x11");
+                        }
+
+                        if (!falling_back) {
+                                if (g_strcmp0 (preferred_display_server, "wayland") == 0) {
+                                        if (xorg_enabled)
+                                                g_ptr_array_add (supported_session_types, "x11");
+                                } else {
+                                        if (wayland_enabled)
+                                                g_ptr_array_add (supported_session_types, "wayland");
+                                }
+                        }
+
+                        g_ptr_array_add (supported_session_types, NULL);
+
+                        display = gdm_local_display_new ();
                         g_object_set (G_OBJECT (display), "session-type", session_type, NULL);
+                        g_object_set (G_OBJECT (display), "supported-session-types", 
supported_session_types->pdata, NULL);
                 }
         }
 #endif
 
         if (display == NULL) {
                 guint32 num;
+                const char *supported_session_types[] = { "x11", NULL };
 
                 num = take_next_display_number (factory);
 
                 display = gdm_legacy_display_new (num);
+                g_object_set (G_OBJECT (display), "supported-session-types", supported_session_types, NULL);
         }
 
         g_object_set (display, "seat-id", seat_id, NULL);
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 9c10adff3..4c2752fee 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1333,7 +1333,7 @@ set_up_automatic_login_session (GdmManager *manager,
                                 GdmDisplay *display)
 {
         GdmSession *session;
-        char       *display_session_type = NULL;
+        g_auto (GStrv) supported_session_types = NULL;
 
         /* 0 is root user; since the daemon talks to the session object
          * directly, itself, for automatic login
@@ -1342,11 +1342,12 @@ set_up_automatic_login_session (GdmManager *manager,
         session = get_user_session_for_display (display);
 
         g_object_get (G_OBJECT (display),
-                      "session-type", &display_session_type,
+                      "supported-session-types", &supported_session_types,
                       NULL);
 
         g_object_set (G_OBJECT (session),
                       "display-is-initial", FALSE,
+                      "supported-session-types", supported_session_types,
                       NULL);
 
         g_debug ("GdmManager: Starting automatic login conversation");
@@ -2305,10 +2306,7 @@ create_user_session_for_display (GdmManager *manager,
         char       *display_auth_file = NULL;
         char       *display_seat_id = NULL;
         char       *display_id = NULL;
-#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
-        g_autofree char *display_session_type = NULL;
-        gboolean    greeter_is_wayland;
-#endif
+        g_auto (GStrv) supported_session_types = NULL;
 
         g_object_get (G_OBJECT (display),
                       "id", &display_id,
@@ -2317,9 +2315,7 @@ create_user_session_for_display (GdmManager *manager,
                       "remote-hostname", &remote_hostname,
                       "x11-authority-file", &display_auth_file,
                       "seat-id", &display_seat_id,
-#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
-                      "session-type", &display_session_type,
-#endif
+                      "supported-session-types", &supported_session_types,
                       NULL);
         display_device = get_display_device (manager, display);
 
@@ -2332,6 +2328,9 @@ create_user_session_for_display (GdmManager *manager,
                                    display_auth_file,
                                    display_is_local,
                                    NULL);
+        g_object_set (G_OBJECT (session),
+                      "supported-session-types", supported_session_types,
+                      NULL);
 
         g_debug ("GdmSession: Created user session for user %d on display %s (seat %s)",
                  (int) allowed_user,
@@ -2405,11 +2404,6 @@ create_user_session_for_display (GdmManager *manager,
                                 session,
                                 (GDestroyNotify)
                                 clean_user_session);
-
-#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
-        greeter_is_wayland = g_strcmp0 (display_session_type, "wayland") == 0;
-        g_object_set (G_OBJECT (session), "ignore-wayland", !greeter_is_wayland, NULL);
-#endif
 }
 
 static void
diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
index a010cecf5..2b941e5e1 100644
--- a/daemon/gdm-session.c
+++ b/daemon/gdm-session.c
@@ -133,11 +133,10 @@ struct _GdmSession
         GDBusServer         *outside_server;
         GHashTable          *environment;
 
+        GStrv                supported_session_types;
+
         guint32              is_program_session : 1;
         guint32              display_is_initial : 1;
-#ifdef ENABLE_WAYLAND_SUPPORT
-        guint32              ignore_wayland : 1;
-#endif
 };
 
 enum {
@@ -154,9 +153,7 @@ enum {
         PROP_DISPLAY_X11_AUTHORITY_FILE,
         PROP_USER_X11_AUTHORITY_FILE,
         PROP_CONVERSATION_ENVIRONMENT,
-#ifdef ENABLE_WAYLAND_SUPPORT
-        PROP_IGNORE_WAYLAND,
-#endif
+        PROP_SUPPORTED_SESSION_TYPES,
 };
 
 enum {
@@ -347,13 +344,24 @@ on_establish_credentials_cb (GdmDBusWorker *proxy,
         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,
                          const char *type)
 {
         GArray *search_array = NULL;
         char **search_dirs;
-        int i;
+        int i, j;
         const gchar * const *system_data_dirs = g_get_system_data_dirs ();
 
         static const char *x_search_dirs[] = {
@@ -367,35 +375,32 @@ get_system_session_dirs (GdmSession *self,
 
         search_array = g_array_new (TRUE, TRUE, sizeof (char *));
 
-        if (type == NULL || g_str_equal (type, "x11")) {
-                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);
+        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") &&
+                    (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));
                 }
 
-                g_array_append_vals (search_array, x_search_dirs, G_N_ELEMENTS (x_search_dirs));
-        }
 
 #ifdef ENABLE_WAYLAND_SUPPORT
-        if (!self->ignore_wayland &&
-            (type == NULL || g_str_equal (type, "wayland"))) {
-#ifdef ENABLE_USER_DISPLAY_SERVER
-                g_array_prepend_val (search_array, wayland_search_dir);
+                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);
+                        }
 
-                for (i = 0; system_data_dirs[i]; i++) {
-                        gchar *dir = g_build_filename (system_data_dirs[i], "wayland-sessions", NULL);
-                        g_array_insert_val (search_array, i, dir);
+                        g_array_append_val (search_array, wayland_search_dir);
                 }
-#else
-                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
         }
-#endif
 
         search_dirs = g_strdupv ((char **) search_array->data);
 
@@ -471,6 +476,12 @@ get_session_command_for_file (GdmSession  *self,
                 *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, type, NULL);
         if (key_file == NULL) {
@@ -2257,14 +2268,18 @@ stop_conversation_now (GdmSessionConversation *conversation)
         g_clear_object (&conversation->job);
 }
 
-#ifdef ENABLE_WAYLAND_SUPPORT
 void
-gdm_session_set_ignore_wayland (GdmSession *self,
-                                gboolean    ignore_wayland)
+gdm_session_set_supported_session_types (GdmSession         *self,
+                                         const char * const *supported_session_types)
 {
-        self->ignore_wayland = ignore_wayland;
+        const char * const session_types[] = { "wayland", "x11", NULL };
+        g_strfreev (self->supported_session_types);
+
+        if (supported_session_types == NULL)
+                self->supported_session_types = g_strdupv ((GStrv) session_types);
+        else
+                self->supported_session_types = g_strdupv ((GStrv) supported_session_types);
 }
-#endif
 
 gboolean
 gdm_session_start_conversation (GdmSession *self,
@@ -3189,15 +3204,15 @@ gdm_session_is_wayland_session (GdmSession *self)
 {
         GKeyFile   *key_file;
         gboolean    is_wayland_session = FALSE;
-        char       *filename;
-        char       *full_path = NULL;
+        char            *filename;
+        g_autofree 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);
 
-        key_file = load_key_file_for_file (self, filename, "wayland", &full_path);
+        key_file = load_key_file_for_file (self, filename, NULL, &full_path);
 
         if (key_file == NULL) {
                 goto out;
@@ -3540,11 +3555,9 @@ gdm_session_set_property (GObject      *object,
         case PROP_CONVERSATION_ENVIRONMENT:
                 set_conversation_environment (self, g_value_get_pointer (value));
                 break;
-#ifdef ENABLE_WAYLAND_SUPPORT
-        case PROP_IGNORE_WAYLAND:
-                gdm_session_set_ignore_wayland (self, g_value_get_boolean (value));
+        case PROP_SUPPORTED_SESSION_TYPES:
+                gdm_session_set_supported_session_types (self, g_value_get_boxed (value));
                 break;
-#endif
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -3598,11 +3611,9 @@ gdm_session_get_property (GObject    *object,
         case PROP_CONVERSATION_ENVIRONMENT:
                 g_value_set_pointer (value, self->environment);
                 break;
-#ifdef ENABLE_WAYLAND_SUPPORT
-        case PROP_IGNORE_WAYLAND:
-                g_value_set_boolean (value, self->ignore_wayland);
+        case PROP_SUPPORTED_SESSION_TYPES:
+                g_value_set_boxed (value, self->supported_session_types);
                 break;
-#endif
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -3620,6 +3631,8 @@ gdm_session_dispose (GObject *object)
 
         gdm_session_close (self);
 
+        g_clear_pointer (&self->supported_session_types,
+                         g_strfreev);
         g_clear_pointer (&self->conversations,
                          g_hash_table_unref);
 
@@ -4034,15 +4047,13 @@ gdm_session_class_init (GdmSessionClass *session_class)
                                                               NULL,
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT | 
G_PARAM_STATIC_STRINGS));
 
-#ifdef ENABLE_WAYLAND_SUPPORT
         g_object_class_install_property (object_class,
-                                         PROP_IGNORE_WAYLAND,
-                                         g_param_spec_boolean ("ignore-wayland",
-                                                               "ignore wayland",
-                                                               "ignore wayland",
-                                                               FALSE,
-                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT | 
G_PARAM_STATIC_STRINGS));
-#endif
+                                         PROP_SUPPORTED_SESSION_TYPES,
+                                         g_param_spec_boxed ("supported-session-types",
+                                                             "supported session types",
+                                                             "supported session types",
+                                                             G_TYPE_STRV,
+                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT | 
G_PARAM_STATIC_STRINGS));
 
         /* Ensure we can resolve errors */
         gdm_dbus_error_ensure (GDM_SESSION_WORKER_ERROR);
diff --git a/data/gdm.schemas.in b/data/gdm.schemas.in
index 255bff023..a1035f95e 100644
--- a/data/gdm.schemas.in
+++ b/data/gdm.schemas.in
@@ -52,11 +52,21 @@
       <signature>b</signature>
       <default>true</default>
     </schema>
+    <schema>
+      <key>daemon/PreferredDisplayServer</key>
+      <signature>s</signature>
+      <default>wayland</default>
+    </schema>
     <schema>
       <key>daemon/WaylandEnable</key>
       <signature>b</signature>
       <default>true</default>
     </schema>
+    <schema>
+      <key>daemon/XorgEnable</key>
+      <signature>b</signature>
+      <default>true</default>
+    </schema>
     <schema>
       <key>security/AllowRemoteAutoLogin</key>
       <signature>b</signature>
diff --git a/libgdm/gdm-sessions.c b/libgdm/gdm-sessions.c
index a13225050..f078e04b8 100644
--- a/libgdm/gdm-sessions.c
+++ b/libgdm/gdm-sessions.c
@@ -190,6 +190,8 @@ collect_sessions_from_directory (const char *dirname)
 
         gboolean is_x11 = g_getenv ("WAYLAND_DISPLAY") == NULL &&
                           g_getenv ("RUNNING_UNDER_GDM") != NULL;
+        gboolean is_wayland = g_getenv ("WAYLAND_DISPLAY") != NULL &&
+                              g_getenv ("RUNNING_UNDER_GDM") != NULL;
 
         /* FIXME: add file monitor to directory */
 
@@ -206,18 +208,46 @@ collect_sessions_from_directory (const char *dirname)
                         continue;
                 }
 
-                if (is_x11 && g_str_has_suffix (filename, "-xorg.desktop")) {
-                        char *base_name = g_strndup (filename, strlen (filename) - strlen ("-xorg.desktop"));
-                        char *fallback_name = g_strconcat (base_name, ".desktop", NULL);
-                        g_free (base_name);
-                        char *fallback_path = g_build_filename (dirname, fallback_name, NULL);
-                        g_free (fallback_name);
-                        if (g_file_test (fallback_path, G_FILE_TEST_EXISTS)) {
-                                g_free (fallback_path);
-                                g_debug ("Running under X11, ignoring %s", filename);
-                                continue;
+                if (is_wayland) {
+                        if (g_str_has_suffix (filename, "-wayland.desktop")) {
+                                g_autofree char *base_name = g_strndup (filename, strlen (filename) - strlen 
("-wayland.desktop"));
+                                g_autofree char *other_name = g_strconcat (base_name, ".desktop", NULL);
+                                g_autofree char *other_path = g_build_filename (dirname, other_name, NULL);
+
+                                if (g_file_test (other_path, G_FILE_TEST_EXISTS)) {
+                                        g_debug ("Running under Wayland, ignoring %s", filename);
+                                        continue;
+                                }
+                        } else {
+                                g_autofree char *base_name = g_strndup (filename, strlen (filename) - strlen 
(".desktop"));
+                                g_autofree char *other_name = g_strdup_printf ("%s-xorg.desktop", base_name);
+                                g_autofree char *other_path = g_build_filename (dirname, other_name, NULL);
+
+                                if (g_file_test (other_path, G_FILE_TEST_EXISTS)) {
+                                        g_debug ("Running under Wayland, ignoring %s", filename);
+                                        continue;
+                                }
+                        }
+                } else if (is_x11) {
+                        if (g_str_has_suffix (filename, "-xorg.desktop")) {
+                                g_autofree char *base_name = g_strndup (filename, strlen (filename) - strlen 
("-xorg.desktop"));
+                                g_autofree char *other_name = g_strconcat (base_name, ".desktop", NULL);
+                                g_autofree char *other_path = g_build_filename (dirname, other_name, NULL);
+
+                                if (g_file_test (other_path, G_FILE_TEST_EXISTS)) {
+                                        g_debug ("Running under X11, ignoring %s", filename);
+                                        continue;
+                                }
+                        } else {
+                                g_autofree char *base_name = g_strndup (filename, strlen (filename) - strlen 
(".desktop"));
+                                g_autofree char *other_name = g_strdup_printf ("%s-wayland.desktop", 
base_name);
+                                g_autofree char *other_path = g_build_filename (dirname, other_name, NULL);
+
+                                if (g_file_test (other_path, G_FILE_TEST_EXISTS)) {
+                                        g_debug ("Running under X11, ignoring %s", filename);
+                                        continue;
+                                }
                         }
-                        g_free (fallback_path);
                 }
 
                 id = g_strndup (filename, strlen (filename) - strlen (".desktop"));
@@ -247,6 +277,9 @@ collect_sessions (void)
                 DATADIR "/gdm/BuiltInSessions/",
                 DATADIR "/xsessions/",
         };
+        g_auto (GStrv) supported_session_types = NULL;
+
+        supported_session_types = g_strsplit (g_getenv ("GDM_SUPPORTED_SESSION_TYPES"), ":", -1);
 
         names_seen_before = g_hash_table_new (g_str_hash, g_str_equal);
         xorg_search_array = g_ptr_array_new_with_free_func (g_free);
@@ -284,23 +317,22 @@ collect_sessions (void)
                                                                     g_free, 
(GDestroyNotify)gdm_session_file_free);
         }
 
-        for (i = 0; i < xorg_search_array->len; i++) {
-                collect_sessions_from_directory (g_ptr_array_index (xorg_search_array, i));
+        if (!supported_session_types || g_strv_contains ((const char * const *) supported_session_types, 
"x11")) {
+                for (i = 0; i < xorg_search_array->len; i++) {
+                        collect_sessions_from_directory (g_ptr_array_index (xorg_search_array, i));
+                }
         }
 
 #ifdef ENABLE_WAYLAND_SUPPORT
 #ifdef ENABLE_USER_DISPLAY_SERVER
-        if (g_getenv ("WAYLAND_DISPLAY") == NULL && g_getenv ("RUNNING_UNDER_GDM") != NULL) {
-                goto out;
+        if (!supported_session_types  || g_strv_contains ((const char * const *) supported_session_types, 
"wayland")) {
+                for (i = 0; i < wayland_search_array->len; i++) {
+                        collect_sessions_from_directory (g_ptr_array_index (wayland_search_array, i));
+                }
         }
 #endif
-
-        for (i = 0; i < wayland_search_array->len; i++) {
-                collect_sessions_from_directory (g_ptr_array_index (wayland_search_array, i));
-        }
 #endif
 
-out:
         g_hash_table_foreach_remove (gdm_available_sessions_map,
                                      remove_duplicate_sessions,
                                      names_seen_before);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]