From ab9ea61d3db5343b49d2289b659a6f4533d2db2a Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 16 Feb 2023 13:43:02 +0100 Subject: [PATCH] x11: Open a X11 Display directly Do the few remaining things that GDK is doing for us: - Open and close the X11 Display - Set up a GSource on the Display FD to handle events - Allocate and free the content of XGenericEventCookie, to "unroll" the few XInput2 events that Mutter still does handle. And remove the GdkDisplay we've so long relied on. Part-of: --- src/meson.build | 1 + src/x11/events.c | 32 ++++++---- src/x11/meta-x11-display-private.h | 3 +- src/x11/meta-x11-display.c | 96 ++++-------------------------- src/x11/meta-x11-event-source.c | 93 +++++++++++++++++++++++++++++ src/x11/meta-x11-event-source.h | 31 ++++++++++ 6 files changed, 157 insertions(+), 99 deletions(-) create mode 100644 src/x11/meta-x11-event-source.c create mode 100644 src/x11/meta-x11-event-source.h diff --git a/src/meson.build b/src/meson.build index 47852d7fd..1223ae586 100644 --- a/src/meson.build +++ b/src/meson.build @@ -476,6 +476,7 @@ if have_x11_client 'x11/meta-x11-display.c', 'x11/meta-x11-display-private.h', 'x11/meta-x11-errors.c', + 'x11/meta-x11-event-source.c', 'x11/meta-x11-selection.c', 'x11/meta-x11-selection-private.h', 'x11/meta-x11-selection-input-stream.c', diff --git a/src/x11/events.c b/src/x11/events.c index 5a57062ef..694e380a7 100644 --- a/src/x11/events.c +++ b/src/x11/events.c @@ -44,6 +44,7 @@ #include "meta/meta-x11-errors.h" #include "x11/meta-startup-notification-x11.h" #include "x11/meta-x11-display-private.h" +#include "x11/meta-x11-event-source.h" #include "x11/meta-x11-selection-private.h" #include "x11/meta-x11-selection-input-stream-private.h" #include "x11/meta-x11-selection-output-stream-private.h" @@ -1266,7 +1267,7 @@ process_selection_clear (MetaX11Display *x11_display, meta_verbose ("Got selection clear for on display %s", x11_display->name); - /* We can't close a GdkDisplay in an even handler. */ + /* We can't close a Display in an event handler. */ if (!x11_display->display_close_idle) { x11_display->xselectionclear_timestamp = event->xselectionclear.time; @@ -1919,6 +1920,9 @@ meta_x11_display_handle_xevent (MetaX11Display *x11_display, COGL_TRACE_BEGIN (MetaX11DisplayHandleXevent, "X11Display (handle X11 event)"); + if (event->type == GenericEvent) + XGetEventData (x11_display->xdisplay, &event->xcookie); + #if 0 meta_spew_event_print (x11_display, event); #endif @@ -2030,6 +2034,9 @@ meta_x11_display_handle_xevent (MetaX11Display *x11_display, display->current_time = META_CURRENT_TIME; + if (event->type == GenericEvent) + XFreeEventData (x11_display->xdisplay, &event->xcookie); + COGL_TRACE_DESCRIBE (MetaX11DisplayHandleXevent, get_event_name (x11_display, event)); COGL_TRACE_END (MetaX11DisplayHandleXevent); @@ -2038,27 +2045,30 @@ meta_x11_display_handle_xevent (MetaX11Display *x11_display, } -static GdkFilterReturn -xevent_filter (GdkXEvent *xevent, - GdkEvent *event, - gpointer data) +static gboolean +xevent_func (XEvent *xevent, + gpointer data) { MetaX11Display *x11_display = data; - if (meta_x11_display_handle_xevent (x11_display, xevent)) - return GDK_FILTER_REMOVE; - else - return GDK_FILTER_CONTINUE; + meta_x11_display_handle_xevent (x11_display, xevent); + + return G_SOURCE_CONTINUE; } void meta_x11_display_init_events (MetaX11Display *x11_display) { - gdk_window_add_filter (NULL, xevent_filter, x11_display); + x11_display->event_source = meta_x11_event_source_new (x11_display->xdisplay); + g_source_set_callback (x11_display->event_source, + (GSourceFunc) xevent_func, + x11_display, NULL); + g_source_attach (x11_display->event_source, NULL); } void meta_x11_display_free_events (MetaX11Display *x11_display) { - gdk_window_remove_filter (NULL, xevent_filter, x11_display); + g_source_destroy (x11_display->event_source); + g_clear_pointer (&x11_display->event_source, g_source_unref); } diff --git a/src/x11/meta-x11-display-private.h b/src/x11/meta-x11-display-private.h index c9a888409..c50e52a2a 100644 --- a/src/x11/meta-x11-display-private.h +++ b/src/x11/meta-x11-display-private.h @@ -26,7 +26,6 @@ #define META_X11_DISPLAY_PRIVATE_H #include -#include #include #include "backends/meta-monitor-manager-private.h" @@ -66,7 +65,6 @@ struct _MetaX11Display GObject parent; MetaDisplay *display; - GdkDisplay *gdk_display; char *name; char *screen_name; @@ -145,6 +143,7 @@ struct _MetaX11Display GCancellable *frames_client_cancellable; GList *error_traps; + GSource *event_source; struct { Window xwindow; diff --git a/src/x11/meta-x11-display.c b/src/x11/meta-x11-display.c index 3de93b8dc..363d816a4 100644 --- a/src/x11/meta-x11-display.c +++ b/src/x11/meta-x11-display.c @@ -33,9 +33,6 @@ #include "core/display-private.h" #include "x11/meta-x11-display-private.h" -#include -#include -#include #include #include #include @@ -271,15 +268,10 @@ meta_x11_display_dispose (GObject *object) { meta_x11_display_free_events (x11_display); + XCloseDisplay (x11_display->xdisplay); x11_display->xdisplay = NULL; } - if (x11_display->gdk_display) - { - gdk_display_close (x11_display->gdk_display); - x11_display->gdk_display = NULL; - } - g_clear_handle_id (&x11_display->display_close_idle, g_source_remove); g_free (x11_display->name); @@ -764,11 +756,6 @@ init_leader_window (MetaX11Display *x11_display, gulong data[1]; XEvent event; - /* We only care about the PropertyChangeMask in the next 30 or so lines of - * code. Note that gdk will at some point unset the PropertyChangeMask for - * this window, so we can't rely on it still being set later. See bug - * 354213 for details. - */ x11_display->leader_window = meta_x11_display_create_offscreen_window (x11_display, x11_display->xroot, @@ -1047,15 +1034,11 @@ get_display_name (MetaDisplay *display) return g_getenv ("DISPLAY"); } -static GdkDisplay * -open_gdk_display (MetaDisplay *display, - GError **error) +static Display * +open_x_display (MetaDisplay *display, + GError **error) { const char *xdisplay_name; - GdkDisplay *gdk_display; - const char *gdk_backend_env = NULL; - const char *gdk_gl_env = NULL; - const char *old_no_at_bridge; Display *xdisplay; xdisplay_name = get_display_name (display); @@ -1066,72 +1049,22 @@ open_gdk_display (MetaDisplay *display, return NULL; } - gdk_set_allowed_backends ("x11"); + meta_verbose ("Opening display '%s'", xdisplay_name); - gdk_backend_env = g_getenv ("GDK_BACKEND"); - /* GDK would fail to initialize with e.g. GDK_BACKEND=wayland */ - g_unsetenv ("GDK_BACKEND"); - - gdk_gl_env = g_getenv ("GDK_GL"); - g_setenv ("GDK_GL", "disable", TRUE); - - gdk_parse_args (NULL, NULL); - if (!gtk_parse_args (NULL, NULL)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Failed to initialize gtk"); - return NULL; - } - - old_no_at_bridge = g_getenv ("NO_AT_BRIDGE"); - g_setenv ("NO_AT_BRIDGE", "1", TRUE); - gdk_display = gdk_display_open (xdisplay_name); - - if (old_no_at_bridge) - g_setenv ("NO_AT_BRIDGE", old_no_at_bridge, TRUE); - else - g_unsetenv ("NO_AT_BRIDGE"); - - if (!gdk_display) - { - meta_warning (_("Failed to initialize GDK")); - - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Failed to initialize GDK"); - return NULL; - } - - if (gdk_backend_env) - g_setenv("GDK_BACKEND", gdk_backend_env, TRUE); - - if (gdk_gl_env) - g_setenv("GDK_GL", gdk_gl_env, TRUE); - else - unsetenv("GDK_GL"); - - /* We need to be able to fully trust that the window and monitor sizes - that Gdk reports corresponds to the X ones, so we disable the automatic - scale handling */ - gdk_x11_display_set_window_scale (gdk_display, 1); - - meta_verbose ("Opening display '%s'", XDisplayName (NULL)); - - xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display); + xdisplay = XOpenDisplay (xdisplay_name); if (xdisplay == NULL) { meta_warning (_("Failed to open X Window System display ā€œ%sā€"), - XDisplayName (NULL)); + xdisplay_name); g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Failed to open X11 display"); - gdk_display_close (gdk_display); - return NULL; } - return gdk_display; + return xdisplay; } static void @@ -1230,7 +1163,6 @@ meta_x11_display_new (MetaDisplay *display, Atom atom_restart_helper; Window restart_helper_window = None; gboolean is_restart = FALSE; - GdkDisplay *gdk_display; /* A list of all atom names, so that we can intern them in one go. */ const char *atom_names[] = { @@ -1240,12 +1172,10 @@ meta_x11_display_new (MetaDisplay *display, }; Atom atoms[G_N_ELEMENTS(atom_names)]; - gdk_display = open_gdk_display (display, error); - if (!gdk_display) + xdisplay = open_x_display (display, error); + if (!xdisplay) return NULL; - xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display); - XSynchronize (xdisplay, meta_context_is_x11_sync (context)); #ifdef HAVE_XWAYLAND @@ -1261,9 +1191,6 @@ meta_x11_display_new (MetaDisplay *display, replace_current_wm = meta_context_is_replacing (meta_backend_get_context (backend)); - /* According to _gdk_x11_display_open (), this will be returned - * by gdk_display_get_default_screen () - */ number = DefaultScreen (xdisplay); xroot = RootWindow (xdisplay, number); @@ -1282,8 +1209,6 @@ meta_x11_display_new (MetaDisplay *display, XFlush (xdisplay); XCloseDisplay (xdisplay); - gdk_display_close (gdk_display); - return NULL; } @@ -1298,7 +1223,6 @@ meta_x11_display_new (MetaDisplay *display, } x11_display = g_object_new (META_TYPE_X11_DISPLAY, NULL); - x11_display->gdk_display = gdk_display; x11_display->display = display; /* here we use XDisplayName which is what the user diff --git a/src/x11/meta-x11-event-source.c b/src/x11/meta-x11-event-source.c new file mode 100644 index 000000000..0c92faf45 --- /dev/null +++ b/src/x11/meta-x11-event-source.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2023 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "meta-x11-event-source.h" + +typedef struct { + GSource base; + GPollFD event_poll_fd; + Display *xdisplay; +} MetaX11EventSource; + +static gboolean +meta_x11_event_source_prepare (GSource *source, + int *timeout) +{ + MetaX11EventSource *event_source = (MetaX11EventSource *) source; + + *timeout = -1; + + return XPending (event_source->xdisplay); +} + +static gboolean +meta_x11_event_source_check (GSource *source) +{ + MetaX11EventSource *event_source = (MetaX11EventSource *) source; + + return XPending (event_source->xdisplay); +} + +static gboolean +meta_x11_event_source_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + MetaX11EventSource *event_source = (MetaX11EventSource *) source; + MetaX11EventFunc event_func = (MetaX11EventFunc) callback; + gboolean retval = G_SOURCE_CONTINUE; + + while (retval == G_SOURCE_CONTINUE && + XPending (event_source->xdisplay)) + { + XEvent xevent; + + XNextEvent (event_source->xdisplay, &xevent); + retval = event_func (&xevent, user_data); + } + + return retval; +} + +static GSourceFuncs meta_x11_event_source_funcs = { + meta_x11_event_source_prepare, + meta_x11_event_source_check, + meta_x11_event_source_dispatch, +}; + +GSource * +meta_x11_event_source_new (Display *xdisplay) +{ + GSource *source; + MetaX11EventSource *event_source; + + source = g_source_new (&meta_x11_event_source_funcs, + sizeof (MetaX11EventSource)); + g_source_set_name (source, "[mutter] MetaX11Display events"); + + event_source = (MetaX11EventSource *) source; + event_source->xdisplay = xdisplay; + event_source->event_poll_fd.fd = ConnectionNumber (xdisplay); + event_source->event_poll_fd.events = G_IO_IN; + g_source_add_poll (source, &event_source->event_poll_fd); + + return source; +} diff --git a/src/x11/meta-x11-event-source.h b/src/x11/meta-x11-event-source.h new file mode 100644 index 000000000..60e224a1b --- /dev/null +++ b/src/x11/meta-x11-event-source.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2023 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_X11_EVENT_SOURCE_H +#define META_X11_EVENT_SOURCE_H + +#include +#include + +typedef gboolean (* MetaX11EventFunc) (XEvent *xevent, + gpointer user_data); + +GSource * meta_x11_event_source_new (Display *xdisplay); + +#endif