|
|
400dab |
From a9422c7b5f4200ad36300bb06134d545bb9d48d2 Mon Sep 17 00:00:00 2001
|
|
|
400dab |
From: Lubomir Rintel <lkundrak@v3.sk>
|
|
|
400dab |
Date: Tue, 17 Jul 2018 20:20:55 +0000
|
|
|
400dab |
Subject: [PATCH 01/51] display-factory: avoid removing a display from store
|
|
|
400dab |
while iterating it
|
|
|
400dab |
|
|
|
400dab |
---
|
|
|
400dab |
daemon/gdm-display-factory.c | 41 ++++++++++++++++++++++++++++++
|
|
|
400dab |
daemon/gdm-display-factory.h | 1 +
|
|
|
400dab |
daemon/gdm-local-display-factory.c | 7 ++---
|
|
|
400dab |
daemon/gdm-xdmcp-display-factory.c | 7 ++---
|
|
|
400dab |
4 files changed, 46 insertions(+), 10 deletions(-)
|
|
|
400dab |
|
|
|
400dab |
diff --git a/daemon/gdm-display-factory.c b/daemon/gdm-display-factory.c
|
|
|
400dab |
index d86a4c8ad..c520e1088 100644
|
|
|
400dab |
--- a/daemon/gdm-display-factory.c
|
|
|
400dab |
+++ b/daemon/gdm-display-factory.c
|
|
|
400dab |
@@ -8,84 +8,120 @@
|
|
|
400dab |
* (at your option) any later version.
|
|
|
400dab |
*
|
|
|
400dab |
* This program is distributed in the hope that it will be useful,
|
|
|
400dab |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
400dab |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
400dab |
* GNU General Public License for more details.
|
|
|
400dab |
*
|
|
|
400dab |
* You should have received a copy of the GNU General Public License
|
|
|
400dab |
* along with this program; if not, write to the Free Software
|
|
|
400dab |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
400dab |
*
|
|
|
400dab |
*/
|
|
|
400dab |
|
|
|
400dab |
#include "config.h"
|
|
|
400dab |
|
|
|
400dab |
#include <stdlib.h>
|
|
|
400dab |
#include <stdio.h>
|
|
|
400dab |
|
|
|
400dab |
#include <glib.h>
|
|
|
400dab |
#include <glib/gi18n.h>
|
|
|
400dab |
#include <glib-object.h>
|
|
|
400dab |
|
|
|
400dab |
#include "gdm-display-factory.h"
|
|
|
400dab |
#include "gdm-display-store.h"
|
|
|
400dab |
|
|
|
400dab |
#define GDM_DISPLAY_FACTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_DISPLAY_FACTORY, GdmDisplayFactoryPrivate))
|
|
|
400dab |
|
|
|
400dab |
struct GdmDisplayFactoryPrivate
|
|
|
400dab |
{
|
|
|
400dab |
GdmDisplayStore *display_store;
|
|
|
400dab |
+ guint purge_displays_id;
|
|
|
400dab |
};
|
|
|
400dab |
|
|
|
400dab |
enum {
|
|
|
400dab |
PROP_0,
|
|
|
400dab |
PROP_DISPLAY_STORE,
|
|
|
400dab |
};
|
|
|
400dab |
|
|
|
400dab |
static void gdm_display_factory_class_init (GdmDisplayFactoryClass *klass);
|
|
|
400dab |
static void gdm_display_factory_init (GdmDisplayFactory *factory);
|
|
|
400dab |
static void gdm_display_factory_finalize (GObject *object);
|
|
|
400dab |
|
|
|
400dab |
G_DEFINE_ABSTRACT_TYPE (GdmDisplayFactory, gdm_display_factory, G_TYPE_OBJECT)
|
|
|
400dab |
|
|
|
400dab |
GQuark
|
|
|
400dab |
gdm_display_factory_error_quark (void)
|
|
|
400dab |
{
|
|
|
400dab |
static GQuark ret = 0;
|
|
|
400dab |
if (ret == 0) {
|
|
|
400dab |
ret = g_quark_from_static_string ("gdm_display_factory_error");
|
|
|
400dab |
}
|
|
|
400dab |
|
|
|
400dab |
return ret;
|
|
|
400dab |
}
|
|
|
400dab |
|
|
|
400dab |
+static gboolean
|
|
|
400dab |
+purge_display (char *id,
|
|
|
400dab |
+ GdmDisplay *display,
|
|
|
400dab |
+ gpointer user_data)
|
|
|
400dab |
+{
|
|
|
400dab |
+ int status;
|
|
|
400dab |
+
|
|
|
400dab |
+ status = gdm_display_get_status (display);
|
|
|
400dab |
+
|
|
|
400dab |
+ switch (status) {
|
|
|
400dab |
+ case GDM_DISPLAY_FINISHED:
|
|
|
400dab |
+ case GDM_DISPLAY_FAILED:
|
|
|
400dab |
+ return TRUE;
|
|
|
400dab |
+ default:
|
|
|
400dab |
+ return FALSE;
|
|
|
400dab |
+ }
|
|
|
400dab |
+}
|
|
|
400dab |
+
|
|
|
400dab |
+static void
|
|
|
400dab |
+purge_displays (GdmDisplayFactory *factory)
|
|
|
400dab |
+{
|
|
|
400dab |
+ factory->priv->purge_displays_id = 0;
|
|
|
400dab |
+ gdm_display_store_foreach_remove (factory->priv->display_store,
|
|
|
400dab |
+ (GdmDisplayStoreFunc)purge_display,
|
|
|
400dab |
+ NULL);
|
|
|
400dab |
+}
|
|
|
400dab |
+
|
|
|
400dab |
+void
|
|
|
400dab |
+gdm_display_factory_queue_purge_displays (GdmDisplayFactory *factory)
|
|
|
400dab |
+{
|
|
|
400dab |
+ if (factory->priv->purge_displays_id == 0) {
|
|
|
400dab |
+ factory->priv->purge_displays_id = g_idle_add ((GSourceFunc) purge_displays, factory);
|
|
|
400dab |
+ }
|
|
|
400dab |
+}
|
|
|
400dab |
+
|
|
|
400dab |
GdmDisplayStore *
|
|
|
400dab |
gdm_display_factory_get_display_store (GdmDisplayFactory *factory)
|
|
|
400dab |
{
|
|
|
400dab |
g_return_val_if_fail (GDM_IS_DISPLAY_FACTORY (factory), NULL);
|
|
|
400dab |
|
|
|
400dab |
return factory->priv->display_store;
|
|
|
400dab |
}
|
|
|
400dab |
|
|
|
400dab |
gboolean
|
|
|
400dab |
gdm_display_factory_start (GdmDisplayFactory *factory)
|
|
|
400dab |
{
|
|
|
400dab |
gboolean ret;
|
|
|
400dab |
|
|
|
400dab |
g_return_val_if_fail (GDM_IS_DISPLAY_FACTORY (factory), FALSE);
|
|
|
400dab |
|
|
|
400dab |
g_object_ref (factory);
|
|
|
400dab |
ret = GDM_DISPLAY_FACTORY_GET_CLASS (factory)->start (factory);
|
|
|
400dab |
g_object_unref (factory);
|
|
|
400dab |
|
|
|
400dab |
return ret;
|
|
|
400dab |
}
|
|
|
400dab |
|
|
|
400dab |
gboolean
|
|
|
400dab |
gdm_display_factory_stop (GdmDisplayFactory *factory)
|
|
|
400dab |
{
|
|
|
400dab |
gboolean ret;
|
|
|
400dab |
|
|
|
400dab |
g_return_val_if_fail (GDM_IS_DISPLAY_FACTORY (factory), FALSE);
|
|
|
400dab |
|
|
|
400dab |
g_object_ref (factory);
|
|
|
400dab |
@@ -160,32 +196,37 @@ gdm_display_factory_class_init (GdmDisplayFactoryClass *klass)
|
|
|
400dab |
|
|
|
400dab |
g_object_class_install_property (object_class,
|
|
|
400dab |
PROP_DISPLAY_STORE,
|
|
|
400dab |
g_param_spec_object ("display-store",
|
|
|
400dab |
"display store",
|
|
|
400dab |
"display store",
|
|
|
400dab |
GDM_TYPE_DISPLAY_STORE,
|
|
|
400dab |
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
|
|
400dab |
|
|
|
400dab |
g_type_class_add_private (klass, sizeof (GdmDisplayFactoryPrivate));
|
|
|
400dab |
}
|
|
|
400dab |
|
|
|
400dab |
static void
|
|
|
400dab |
gdm_display_factory_init (GdmDisplayFactory *factory)
|
|
|
400dab |
{
|
|
|
400dab |
factory->priv = GDM_DISPLAY_FACTORY_GET_PRIVATE (factory);
|
|
|
400dab |
}
|
|
|
400dab |
|
|
|
400dab |
static void
|
|
|
400dab |
gdm_display_factory_finalize (GObject *object)
|
|
|
400dab |
{
|
|
|
400dab |
GdmDisplayFactory *factory;
|
|
|
400dab |
|
|
|
400dab |
g_return_if_fail (object != NULL);
|
|
|
400dab |
g_return_if_fail (GDM_IS_DISPLAY_FACTORY (object));
|
|
|
400dab |
|
|
|
400dab |
factory = GDM_DISPLAY_FACTORY (object);
|
|
|
400dab |
|
|
|
400dab |
g_return_if_fail (factory->priv != NULL);
|
|
|
400dab |
|
|
|
400dab |
+ if (factory->priv->purge_displays_id != 0) {
|
|
|
400dab |
+ g_source_remove (factory->priv->purge_displays_id);
|
|
|
400dab |
+ factory->priv->purge_displays_id = 0;
|
|
|
400dab |
+ }
|
|
|
400dab |
+
|
|
|
400dab |
G_OBJECT_CLASS (gdm_display_factory_parent_class)->finalize (object);
|
|
|
400dab |
}
|
|
|
400dab |
diff --git a/daemon/gdm-display-factory.h b/daemon/gdm-display-factory.h
|
|
|
400dab |
index 6b30f83dc..1cffa1bd5 100644
|
|
|
400dab |
--- a/daemon/gdm-display-factory.h
|
|
|
400dab |
+++ b/daemon/gdm-display-factory.h
|
|
|
400dab |
@@ -37,34 +37,35 @@ G_BEGIN_DECLS
|
|
|
400dab |
|
|
|
400dab |
typedef struct GdmDisplayFactoryPrivate GdmDisplayFactoryPrivate;
|
|
|
400dab |
|
|
|
400dab |
typedef struct
|
|
|
400dab |
{
|
|
|
400dab |
GObject parent;
|
|
|
400dab |
GdmDisplayFactoryPrivate *priv;
|
|
|
400dab |
} GdmDisplayFactory;
|
|
|
400dab |
|
|
|
400dab |
typedef struct
|
|
|
400dab |
{
|
|
|
400dab |
GObjectClass parent_class;
|
|
|
400dab |
|
|
|
400dab |
gboolean (*start) (GdmDisplayFactory *factory);
|
|
|
400dab |
gboolean (*stop) (GdmDisplayFactory *factory);
|
|
|
400dab |
} GdmDisplayFactoryClass;
|
|
|
400dab |
|
|
|
400dab |
typedef enum
|
|
|
400dab |
{
|
|
|
400dab |
GDM_DISPLAY_FACTORY_ERROR_GENERAL
|
|
|
400dab |
} GdmDisplayFactoryError;
|
|
|
400dab |
|
|
|
400dab |
#define GDM_DISPLAY_FACTORY_ERROR gdm_display_factory_error_quark ()
|
|
|
400dab |
|
|
|
400dab |
GQuark gdm_display_factory_error_quark (void);
|
|
|
400dab |
GType gdm_display_factory_get_type (void);
|
|
|
400dab |
|
|
|
400dab |
gboolean gdm_display_factory_start (GdmDisplayFactory *manager);
|
|
|
400dab |
gboolean gdm_display_factory_stop (GdmDisplayFactory *manager);
|
|
|
400dab |
GdmDisplayStore * gdm_display_factory_get_display_store (GdmDisplayFactory *manager);
|
|
|
400dab |
+void gdm_display_factory_queue_purge_displays (GdmDisplayFactory *manager);
|
|
|
400dab |
|
|
|
400dab |
G_END_DECLS
|
|
|
400dab |
|
|
|
400dab |
#endif /* __GDM_DISPLAY_FACTORY_H */
|
|
|
400dab |
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
|
|
|
400dab |
index ab7e12e91..1a9196ee1 100644
|
|
|
400dab |
--- a/daemon/gdm-local-display-factory.c
|
|
|
400dab |
+++ b/daemon/gdm-local-display-factory.c
|
|
|
400dab |
@@ -222,107 +222,104 @@ gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *fact
|
|
|
400dab |
"seat-id", "seat0",
|
|
|
400dab |
"allow-timed-login", FALSE,
|
|
|
400dab |
NULL);
|
|
|
400dab |
|
|
|
400dab |
store_display (factory, display);
|
|
|
400dab |
|
|
|
400dab |
if (! gdm_display_manage (display)) {
|
|
|
400dab |
display = NULL;
|
|
|
400dab |
goto out;
|
|
|
400dab |
}
|
|
|
400dab |
|
|
|
400dab |
if (! gdm_display_get_id (display, id, NULL)) {
|
|
|
400dab |
display = NULL;
|
|
|
400dab |
goto out;
|
|
|
400dab |
}
|
|
|
400dab |
|
|
|
400dab |
ret = TRUE;
|
|
|
400dab |
out:
|
|
|
400dab |
/* ref either held by store or not at all */
|
|
|
400dab |
g_object_unref (display);
|
|
|
400dab |
|
|
|
400dab |
return ret;
|
|
|
400dab |
}
|
|
|
400dab |
|
|
|
400dab |
static void
|
|
|
400dab |
on_display_status_changed (GdmDisplay *display,
|
|
|
400dab |
GParamSpec *arg1,
|
|
|
400dab |
GdmLocalDisplayFactory *factory)
|
|
|
400dab |
{
|
|
|
400dab |
int status;
|
|
|
400dab |
- GdmDisplayStore *store;
|
|
|
400dab |
int num;
|
|
|
400dab |
char *seat_id = NULL;
|
|
|
400dab |
char *session_type = NULL;
|
|
|
400dab |
gboolean is_initial = TRUE;
|
|
|
400dab |
gboolean is_local = TRUE;
|
|
|
400dab |
|
|
|
400dab |
num = -1;
|
|
|
400dab |
gdm_display_get_x11_display_number (display, &num, NULL);
|
|
|
400dab |
|
|
|
400dab |
- store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
|
|
|
400dab |
-
|
|
|
400dab |
g_object_get (display,
|
|
|
400dab |
"seat-id", &seat_id,
|
|
|
400dab |
"is-initial", &is_initial,
|
|
|
400dab |
"is-local", &is_local,
|
|
|
400dab |
"session-type", &session_type,
|
|
|
400dab |
NULL);
|
|
|
400dab |
|
|
|
400dab |
status = gdm_display_get_status (display);
|
|
|
400dab |
|
|
|
400dab |
g_debug ("GdmLocalDisplayFactory: display status changed: %d", status);
|
|
|
400dab |
switch (status) {
|
|
|
400dab |
case GDM_DISPLAY_FINISHED:
|
|
|
400dab |
/* remove the display number from factory->priv->used_display_numbers
|
|
|
400dab |
so that it may be reused */
|
|
|
400dab |
if (num != -1) {
|
|
|
400dab |
g_hash_table_remove (factory->priv->used_display_numbers, GUINT_TO_POINTER (num));
|
|
|
400dab |
}
|
|
|
400dab |
- gdm_display_store_remove (store, display);
|
|
|
400dab |
+ gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory));
|
|
|
400dab |
|
|
|
400dab |
/* if this is a local display, do a full resync. Only
|
|
|
400dab |
* seats without displays will get created anyway. This
|
|
|
400dab |
* ensures we get a new login screen when the user logs out,
|
|
|
400dab |
* if there isn't one.
|
|
|
400dab |
*/
|
|
|
400dab |
if (is_local) {
|
|
|
400dab |
/* reset num failures */
|
|
|
400dab |
factory->priv->num_failures = 0;
|
|
|
400dab |
|
|
|
400dab |
gdm_local_display_factory_sync_seats (factory);
|
|
|
400dab |
}
|
|
|
400dab |
break;
|
|
|
400dab |
case GDM_DISPLAY_FAILED:
|
|
|
400dab |
/* leave the display number in factory->priv->used_display_numbers
|
|
|
400dab |
so that it doesn't get reused */
|
|
|
400dab |
- gdm_display_store_remove (store, display);
|
|
|
400dab |
+ gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory));
|
|
|
400dab |
|
|
|
400dab |
/* Create a new equivalent display if it was static */
|
|
|
400dab |
if (is_local) {
|
|
|
400dab |
|
|
|
400dab |
factory->priv->num_failures++;
|
|
|
400dab |
|
|
|
400dab |
if (factory->priv->num_failures > MAX_DISPLAY_FAILURES) {
|
|
|
400dab |
/* oh shit */
|
|
|
400dab |
g_warning ("GdmLocalDisplayFactory: maximum number of X display failures reached: check X server log for errors");
|
|
|
400dab |
} else {
|
|
|
400dab |
#ifdef ENABLE_WAYLAND_SUPPORT
|
|
|
400dab |
if (g_strcmp0 (session_type, "wayland") == 0) {
|
|
|
400dab |
g_free (session_type);
|
|
|
400dab |
session_type = NULL;
|
|
|
400dab |
|
|
|
400dab |
/* workaround logind race for now
|
|
|
400dab |
* bug 1643874
|
|
|
400dab |
*/
|
|
|
400dab |
g_usleep (2 * G_USEC_PER_SEC);
|
|
|
400dab |
}
|
|
|
400dab |
|
|
|
400dab |
#endif
|
|
|
400dab |
create_display (factory, seat_id, session_type, is_initial);
|
|
|
400dab |
}
|
|
|
400dab |
}
|
|
|
400dab |
break;
|
|
|
400dab |
case GDM_DISPLAY_UNMANAGED:
|
|
|
400dab |
break;
|
|
|
400dab |
case GDM_DISPLAY_PREPARED:
|
|
|
400dab |
break;
|
|
|
400dab |
diff --git a/daemon/gdm-xdmcp-display-factory.c b/daemon/gdm-xdmcp-display-factory.c
|
|
|
400dab |
index 46a0d9ffa..5b5786c6f 100644
|
|
|
400dab |
--- a/daemon/gdm-xdmcp-display-factory.c
|
|
|
400dab |
+++ b/daemon/gdm-xdmcp-display-factory.c
|
|
|
400dab |
@@ -2039,93 +2039,90 @@ on_hostname_selected (GdmXdmcpChooserDisplay *display,
|
|
|
400dab |
char *ip;
|
|
|
400dab |
ic->chosen_address = gdm_address_new_from_sockaddr (ai->ai_addr, ai->ai_addrlen);
|
|
|
400dab |
|
|
|
400dab |
ip = NULL;
|
|
|
400dab |
gdm_address_get_numeric_info (ic->chosen_address, &ip, NULL);
|
|
|
400dab |
g_debug ("GdmXdmcpDisplayFactory: hostname resolves to %s",
|
|
|
400dab |
ip ? ip : "(null)");
|
|
|
400dab |
g_free (ip);
|
|
|
400dab |
}
|
|
|
400dab |
|
|
|
400dab |
freeaddrinfo (ai_list);
|
|
|
400dab |
}
|
|
|
400dab |
|
|
|
400dab |
static void
|
|
|
400dab |
on_client_disconnected (GdmDisplay *display)
|
|
|
400dab |
{
|
|
|
400dab |
if (gdm_display_get_status (display) != GDM_DISPLAY_MANAGED)
|
|
|
400dab |
return;
|
|
|
400dab |
|
|
|
400dab |
gdm_display_stop_greeter_session (display);
|
|
|
400dab |
gdm_display_unmanage (display);
|
|
|
400dab |
gdm_display_finish (display);
|
|
|
400dab |
}
|
|
|
400dab |
|
|
|
400dab |
static void
|
|
|
400dab |
on_display_status_changed (GdmDisplay *display,
|
|
|
400dab |
GParamSpec *arg1,
|
|
|
400dab |
GdmXdmcpDisplayFactory *factory)
|
|
|
400dab |
{
|
|
|
400dab |
int status;
|
|
|
400dab |
- GdmDisplayStore *store;
|
|
|
400dab |
GdmLaunchEnvironment *launch_environment;
|
|
|
400dab |
GdmSession *session;
|
|
|
400dab |
GdmAddress *address;
|
|
|
400dab |
gint32 session_number;
|
|
|
400dab |
int display_number;
|
|
|
400dab |
|
|
|
400dab |
- store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
|
|
|
400dab |
-
|
|
|
400dab |
launch_environment = NULL;
|
|
|
400dab |
g_object_get (display, "launch-environment", &launch_environment, NULL);
|
|
|
400dab |
|
|
|
400dab |
session = NULL;
|
|
|
400dab |
if (launch_environment != NULL) {
|
|
|
400dab |
session = gdm_launch_environment_get_session (launch_environment);
|
|
|
400dab |
}
|
|
|
400dab |
|
|
|
400dab |
status = gdm_display_get_status (display);
|
|
|
400dab |
|
|
|
400dab |
g_debug ("GdmXdmcpDisplayFactory: xdmcp display status changed: %d", status);
|
|
|
400dab |
switch (status) {
|
|
|
400dab |
case GDM_DISPLAY_FINISHED:
|
|
|
400dab |
g_object_get (display,
|
|
|
400dab |
"remote-address", &address,
|
|
|
400dab |
"x11-display-number", &display_number,
|
|
|
400dab |
"session-number", &session_number,
|
|
|
400dab |
NULL);
|
|
|
400dab |
gdm_xdmcp_send_alive (factory, address, display_number, session_number);
|
|
|
400dab |
|
|
|
400dab |
- gdm_display_store_remove (store, display);
|
|
|
400dab |
+ gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory));
|
|
|
400dab |
break;
|
|
|
400dab |
case GDM_DISPLAY_FAILED:
|
|
|
400dab |
- gdm_display_store_remove (store, display);
|
|
|
400dab |
+ gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory));
|
|
|
400dab |
break;
|
|
|
400dab |
case GDM_DISPLAY_UNMANAGED:
|
|
|
400dab |
if (session != NULL) {
|
|
|
400dab |
g_signal_handlers_disconnect_by_func (G_OBJECT (session),
|
|
|
400dab |
G_CALLBACK (on_client_disconnected),
|
|
|
400dab |
display);
|
|
|
400dab |
}
|
|
|
400dab |
break;
|
|
|
400dab |
case GDM_DISPLAY_PREPARED:
|
|
|
400dab |
break;
|
|
|
400dab |
case GDM_DISPLAY_MANAGED:
|
|
|
400dab |
if (session != NULL) {
|
|
|
400dab |
g_signal_connect_object (G_OBJECT (session),
|
|
|
400dab |
"client-disconnected",
|
|
|
400dab |
G_CALLBACK (on_client_disconnected),
|
|
|
400dab |
display, G_CONNECT_SWAPPED);
|
|
|
400dab |
g_signal_connect_object (G_OBJECT (session),
|
|
|
400dab |
"disconnected",
|
|
|
400dab |
G_CALLBACK (on_client_disconnected),
|
|
|
400dab |
display, G_CONNECT_SWAPPED);
|
|
|
400dab |
}
|
|
|
400dab |
break;
|
|
|
400dab |
default:
|
|
|
400dab |
g_assert_not_reached ();
|
|
|
400dab |
break;
|
|
|
400dab |
}
|
|
|
400dab |
}
|
|
|
400dab |
|
|
|
400dab |
static GdmDisplay *
|
|
|
400dab |
gdm_xdmcp_display_create (GdmXdmcpDisplayFactory *factory,
|
|
|
400dab |
--
|
|
|
400dab |
2.27.0
|
|
|
400dab |
|