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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2864>
This commit is contained in:
parent
a5042000c6
commit
ab9ea61d3d
@ -476,6 +476,7 @@ if have_x11_client
|
|||||||
'x11/meta-x11-display.c',
|
'x11/meta-x11-display.c',
|
||||||
'x11/meta-x11-display-private.h',
|
'x11/meta-x11-display-private.h',
|
||||||
'x11/meta-x11-errors.c',
|
'x11/meta-x11-errors.c',
|
||||||
|
'x11/meta-x11-event-source.c',
|
||||||
'x11/meta-x11-selection.c',
|
'x11/meta-x11-selection.c',
|
||||||
'x11/meta-x11-selection-private.h',
|
'x11/meta-x11-selection-private.h',
|
||||||
'x11/meta-x11-selection-input-stream.c',
|
'x11/meta-x11-selection-input-stream.c',
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
#include "meta/meta-x11-errors.h"
|
#include "meta/meta-x11-errors.h"
|
||||||
#include "x11/meta-startup-notification-x11.h"
|
#include "x11/meta-startup-notification-x11.h"
|
||||||
#include "x11/meta-x11-display-private.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-private.h"
|
||||||
#include "x11/meta-x11-selection-input-stream-private.h"
|
#include "x11/meta-x11-selection-input-stream-private.h"
|
||||||
#include "x11/meta-x11-selection-output-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",
|
meta_verbose ("Got selection clear for on display %s",
|
||||||
x11_display->name);
|
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)
|
if (!x11_display->display_close_idle)
|
||||||
{
|
{
|
||||||
x11_display->xselectionclear_timestamp = event->xselectionclear.time;
|
x11_display->xselectionclear_timestamp = event->xselectionclear.time;
|
||||||
@ -1919,6 +1920,9 @@ meta_x11_display_handle_xevent (MetaX11Display *x11_display,
|
|||||||
COGL_TRACE_BEGIN (MetaX11DisplayHandleXevent,
|
COGL_TRACE_BEGIN (MetaX11DisplayHandleXevent,
|
||||||
"X11Display (handle X11 event)");
|
"X11Display (handle X11 event)");
|
||||||
|
|
||||||
|
if (event->type == GenericEvent)
|
||||||
|
XGetEventData (x11_display->xdisplay, &event->xcookie);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
meta_spew_event_print (x11_display, event);
|
meta_spew_event_print (x11_display, event);
|
||||||
#endif
|
#endif
|
||||||
@ -2030,6 +2034,9 @@ meta_x11_display_handle_xevent (MetaX11Display *x11_display,
|
|||||||
|
|
||||||
display->current_time = META_CURRENT_TIME;
|
display->current_time = META_CURRENT_TIME;
|
||||||
|
|
||||||
|
if (event->type == GenericEvent)
|
||||||
|
XFreeEventData (x11_display->xdisplay, &event->xcookie);
|
||||||
|
|
||||||
COGL_TRACE_DESCRIBE (MetaX11DisplayHandleXevent,
|
COGL_TRACE_DESCRIBE (MetaX11DisplayHandleXevent,
|
||||||
get_event_name (x11_display, event));
|
get_event_name (x11_display, event));
|
||||||
COGL_TRACE_END (MetaX11DisplayHandleXevent);
|
COGL_TRACE_END (MetaX11DisplayHandleXevent);
|
||||||
@ -2038,27 +2045,30 @@ meta_x11_display_handle_xevent (MetaX11Display *x11_display,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static GdkFilterReturn
|
static gboolean
|
||||||
xevent_filter (GdkXEvent *xevent,
|
xevent_func (XEvent *xevent,
|
||||||
GdkEvent *event,
|
gpointer data)
|
||||||
gpointer data)
|
|
||||||
{
|
{
|
||||||
MetaX11Display *x11_display = data;
|
MetaX11Display *x11_display = data;
|
||||||
|
|
||||||
if (meta_x11_display_handle_xevent (x11_display, xevent))
|
meta_x11_display_handle_xevent (x11_display, xevent);
|
||||||
return GDK_FILTER_REMOVE;
|
|
||||||
else
|
return G_SOURCE_CONTINUE;
|
||||||
return GDK_FILTER_CONTINUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_x11_display_init_events (MetaX11Display *x11_display)
|
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
|
void
|
||||||
meta_x11_display_free_events (MetaX11Display *x11_display)
|
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);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
#define META_X11_DISPLAY_PRIVATE_H
|
#define META_X11_DISPLAY_PRIVATE_H
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <gdk/gdk.h>
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
#include "backends/meta-monitor-manager-private.h"
|
#include "backends/meta-monitor-manager-private.h"
|
||||||
@ -66,7 +65,6 @@ struct _MetaX11Display
|
|||||||
GObject parent;
|
GObject parent;
|
||||||
|
|
||||||
MetaDisplay *display;
|
MetaDisplay *display;
|
||||||
GdkDisplay *gdk_display;
|
|
||||||
|
|
||||||
char *name;
|
char *name;
|
||||||
char *screen_name;
|
char *screen_name;
|
||||||
@ -145,6 +143,7 @@ struct _MetaX11Display
|
|||||||
GCancellable *frames_client_cancellable;
|
GCancellable *frames_client_cancellable;
|
||||||
|
|
||||||
GList *error_traps;
|
GList *error_traps;
|
||||||
|
GSource *event_source;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
Window xwindow;
|
Window xwindow;
|
||||||
|
@ -33,9 +33,6 @@
|
|||||||
#include "core/display-private.h"
|
#include "core/display-private.h"
|
||||||
#include "x11/meta-x11-display-private.h"
|
#include "x11/meta-x11-display-private.h"
|
||||||
|
|
||||||
#include <gdk/gdk.h>
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
#include <gdk/gdkx.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -271,15 +268,10 @@ meta_x11_display_dispose (GObject *object)
|
|||||||
{
|
{
|
||||||
meta_x11_display_free_events (x11_display);
|
meta_x11_display_free_events (x11_display);
|
||||||
|
|
||||||
|
XCloseDisplay (x11_display->xdisplay);
|
||||||
x11_display->xdisplay = NULL;
|
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_clear_handle_id (&x11_display->display_close_idle, g_source_remove);
|
||||||
|
|
||||||
g_free (x11_display->name);
|
g_free (x11_display->name);
|
||||||
@ -764,11 +756,6 @@ init_leader_window (MetaX11Display *x11_display,
|
|||||||
gulong data[1];
|
gulong data[1];
|
||||||
XEvent event;
|
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 =
|
x11_display->leader_window =
|
||||||
meta_x11_display_create_offscreen_window (x11_display,
|
meta_x11_display_create_offscreen_window (x11_display,
|
||||||
x11_display->xroot,
|
x11_display->xroot,
|
||||||
@ -1047,15 +1034,11 @@ get_display_name (MetaDisplay *display)
|
|||||||
return g_getenv ("DISPLAY");
|
return g_getenv ("DISPLAY");
|
||||||
}
|
}
|
||||||
|
|
||||||
static GdkDisplay *
|
static Display *
|
||||||
open_gdk_display (MetaDisplay *display,
|
open_x_display (MetaDisplay *display,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
const char *xdisplay_name;
|
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;
|
Display *xdisplay;
|
||||||
|
|
||||||
xdisplay_name = get_display_name (display);
|
xdisplay_name = get_display_name (display);
|
||||||
@ -1066,72 +1049,22 @@ open_gdk_display (MetaDisplay *display,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
gdk_set_allowed_backends ("x11");
|
meta_verbose ("Opening display '%s'", xdisplay_name);
|
||||||
|
|
||||||
gdk_backend_env = g_getenv ("GDK_BACKEND");
|
xdisplay = XOpenDisplay (xdisplay_name);
|
||||||
/* 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);
|
|
||||||
|
|
||||||
if (xdisplay == NULL)
|
if (xdisplay == NULL)
|
||||||
{
|
{
|
||||||
meta_warning (_("Failed to open X Window System display “%s”"),
|
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,
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
"Failed to open X11 display");
|
"Failed to open X11 display");
|
||||||
|
|
||||||
gdk_display_close (gdk_display);
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return gdk_display;
|
return xdisplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1230,7 +1163,6 @@ meta_x11_display_new (MetaDisplay *display,
|
|||||||
Atom atom_restart_helper;
|
Atom atom_restart_helper;
|
||||||
Window restart_helper_window = None;
|
Window restart_helper_window = None;
|
||||||
gboolean is_restart = FALSE;
|
gboolean is_restart = FALSE;
|
||||||
GdkDisplay *gdk_display;
|
|
||||||
|
|
||||||
/* A list of all atom names, so that we can intern them in one go. */
|
/* A list of all atom names, so that we can intern them in one go. */
|
||||||
const char *atom_names[] = {
|
const char *atom_names[] = {
|
||||||
@ -1240,12 +1172,10 @@ meta_x11_display_new (MetaDisplay *display,
|
|||||||
};
|
};
|
||||||
Atom atoms[G_N_ELEMENTS(atom_names)];
|
Atom atoms[G_N_ELEMENTS(atom_names)];
|
||||||
|
|
||||||
gdk_display = open_gdk_display (display, error);
|
xdisplay = open_x_display (display, error);
|
||||||
if (!gdk_display)
|
if (!xdisplay)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display);
|
|
||||||
|
|
||||||
XSynchronize (xdisplay, meta_context_is_x11_sync (context));
|
XSynchronize (xdisplay, meta_context_is_x11_sync (context));
|
||||||
|
|
||||||
#ifdef HAVE_XWAYLAND
|
#ifdef HAVE_XWAYLAND
|
||||||
@ -1261,9 +1191,6 @@ meta_x11_display_new (MetaDisplay *display,
|
|||||||
replace_current_wm =
|
replace_current_wm =
|
||||||
meta_context_is_replacing (meta_backend_get_context (backend));
|
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);
|
number = DefaultScreen (xdisplay);
|
||||||
|
|
||||||
xroot = RootWindow (xdisplay, number);
|
xroot = RootWindow (xdisplay, number);
|
||||||
@ -1282,8 +1209,6 @@ meta_x11_display_new (MetaDisplay *display,
|
|||||||
XFlush (xdisplay);
|
XFlush (xdisplay);
|
||||||
XCloseDisplay (xdisplay);
|
XCloseDisplay (xdisplay);
|
||||||
|
|
||||||
gdk_display_close (gdk_display);
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1298,7 +1223,6 @@ meta_x11_display_new (MetaDisplay *display,
|
|||||||
}
|
}
|
||||||
|
|
||||||
x11_display = g_object_new (META_TYPE_X11_DISPLAY, NULL);
|
x11_display = g_object_new (META_TYPE_X11_DISPLAY, NULL);
|
||||||
x11_display->gdk_display = gdk_display;
|
|
||||||
x11_display->display = display;
|
x11_display->display = display;
|
||||||
|
|
||||||
/* here we use XDisplayName which is what the user
|
/* here we use XDisplayName which is what the user
|
||||||
|
93
src/x11/meta-x11-event-source.c
Normal file
93
src/x11/meta-x11-event-source.c
Normal file
@ -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;
|
||||||
|
}
|
31
src/x11/meta-x11-event-source.h
Normal file
31
src/x11/meta-x11-event-source.h
Normal file
@ -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 <glib.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
typedef gboolean (* MetaX11EventFunc) (XEvent *xevent,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
GSource * meta_x11_event_source_new (Display *xdisplay);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user