wayland: XWayland bridge — block on ready signal, return Display* for full WM UI
wl_display_open now pumps the Wayland event loop until XWayland fires its "ready" signal, then calls XOpenDisplay() and returns the Display* to the core WM. This makes dpy non-NULL so screen.c takes the full X11 code path: RCreateContext, WINGs screen, workspaces, root menus, and EWMH hints all initialise via the WM's own XWayland connection. - wl_handle_x11_events: new fd watcher registered on ConnectionNumber(dpy) so WINGs menus, dialogs, and keyboard events are dispatched during wl_display_run() via XPending/XNextEvent/WMHandleEvent - wl_screen_open: sets root_win/depth/colormap from DefaultRootWindow(dpy) when bridge is active so RCreateContext gets valid X11 screen values - wl_screen_create_internals: creates a 1x1 info_window on XWayland for _NET_SUPPORTING_WM_CHECK and clipboard selection ownership - handle_xwayland_map: guard against w_global.screen_count==0 (fires before StartUp() in edge cases) to avoid assert in wScreenWithNumber - wl_display_close: removes fd watcher and calls XCloseDisplay before killing XWayland to avoid stale fd events Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
398d467880
commit
2fc7e45ffa
|
|
@ -307,6 +307,9 @@ struct wl_compositor_state {
|
|||
struct wl_listener xwayland_new_surface_listener;
|
||||
struct wl_listener xwayland_ready_listener;
|
||||
struct wl_listener xwayland_server_destroy_listener;
|
||||
bool xwayland_ready; /* set by handle_xwayland_ready */
|
||||
Display *x_display; /* WM's Xlib connection to own XWayland */
|
||||
struct wl_event_source *x11_event_source; /* wl_event_loop fd watcher for x_display */
|
||||
/* Phase 20: real input devices from nested backend + their listeners */
|
||||
struct wlr_input_device *real_keyboard_dev;
|
||||
struct wlr_input_device *real_pointer_dev;
|
||||
|
|
@ -1063,7 +1066,10 @@ handle_xwayland_map(struct wl_listener *listener, void *data)
|
|||
}
|
||||
|
||||
|
||||
/* Pure Wayland mode: manage as WM client. */
|
||||
/* Manage as WM client. Guard: wScreenWithNumber asserts screen_count > 0,
|
||||
* so skip if StartUp() hasn't initialised the screen yet. */
|
||||
if (w_global.screen_count == 0)
|
||||
return;
|
||||
WScreen *scr = wScreenWithNumber(0);
|
||||
if (scr) {
|
||||
WWindow *wwin = wManageWindow(scr, view->id);
|
||||
|
|
@ -1189,13 +1195,24 @@ handle_xwayland_ready(struct wl_listener *listener, void *data)
|
|||
|
||||
if (!wl_state.xwayland || !wl_state.xwayland->display_name) {
|
||||
wwarning("wl_backend: XWayland ready but display_name unavailable");
|
||||
wl_state.xwayland_ready = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Advertise the XWayland display so X11 client apps can connect. */
|
||||
setenv("DISPLAY", wl_state.xwayland->display_name, 1);
|
||||
wwarning("wl_backend: XWayland ready on %s (X11 clients can now connect)",
|
||||
wwarning("wl_backend: XWayland ready on %s — opening WM Xlib connection",
|
||||
wl_state.xwayland->display_name);
|
||||
|
||||
/* Open the WM's own Xlib connection to its XWayland instance.
|
||||
* This Display* is returned from wl_display_open so WINGs, title bars,
|
||||
* root menus, and the dock all work via the X11 code path. */
|
||||
wl_state.x_display = XOpenDisplay(wl_state.xwayland->display_name);
|
||||
if (!wl_state.x_display)
|
||||
wwarning("wl_backend: XOpenDisplay(%s) failed — WM UI limited to native Wayland",
|
||||
wl_state.xwayland->display_name);
|
||||
|
||||
wl_state.xwayland_ready = true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1567,6 +1584,23 @@ handle_backend_new_output(struct wl_listener *listener, void *data)
|
|||
/* Display lifecycle (Phase 32 / Phase 34) */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/* Called by the Wayland event loop whenever the X11 connection fd is readable.
|
||||
* Drains all pending X11 events and dispatches them through WINGs so that
|
||||
* menus, dialogs, and other WINGs widgets work during wl_display_run(). */
|
||||
static int
|
||||
wl_handle_x11_events(int fd, uint32_t mask, void *data)
|
||||
{
|
||||
(void)fd; (void)mask; (void)data;
|
||||
if (!wl_state.x_display)
|
||||
return 0;
|
||||
XEvent event;
|
||||
while (XPending(wl_state.x_display)) {
|
||||
XNextEvent(wl_state.x_display, &event);
|
||||
WMHandleEvent(&event);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *
|
||||
wl_display_open(const char *name)
|
||||
{
|
||||
|
|
@ -2117,12 +2151,36 @@ wl_display_open(const char *name)
|
|||
|
||||
wl_state.started = 1;
|
||||
|
||||
/* XWayland is started but we do not block on its ready signal here.
|
||||
* The ready callback (handle_xwayland_ready) will set DISPLAY when it
|
||||
* fires so X11 client apps can connect. The WM's own UI renders via
|
||||
* native Wayland surfaces — no X11 Display* needed by the WM itself. */
|
||||
/* Block until XWayland fires the "ready" signal — pump the Wayland server
|
||||
* event loop so the XWayland process can complete its handshake.
|
||||
* handle_xwayland_ready() calls XOpenDisplay and stores the result in
|
||||
* wl_state.x_display, then sets xwayland_ready = true to break the loop.
|
||||
* If XWayland is not available, return NULL (pure Wayland path). */
|
||||
if (wl_state.xwayland) {
|
||||
wwarning("wl_backend: waiting for XWayland ready signal...");
|
||||
struct wl_event_loop *ev_loop =
|
||||
wl_display_get_event_loop(wl_state.display);
|
||||
while (!wl_state.xwayland_ready) {
|
||||
wl_display_flush_clients(wl_state.display);
|
||||
wl_event_loop_dispatch(ev_loop, 10);
|
||||
}
|
||||
if (wl_state.x_display) {
|
||||
wwarning("wl_backend: XWayland bridge ready — Display*=%p, full WM UI enabled",
|
||||
(void *)wl_state.x_display);
|
||||
/* Integrate X11 events into the Wayland event loop so WINGs
|
||||
* menus, dialogs, and keyboard events are processed during
|
||||
* wl_display_run(). ConnectionNumber(dpy) is the Xlib socket fd. */
|
||||
wl_state.x11_event_source = wl_event_loop_add_fd(
|
||||
wl_display_get_event_loop(wl_state.display),
|
||||
ConnectionNumber(wl_state.x_display),
|
||||
WL_EVENT_READABLE,
|
||||
wl_handle_x11_events, NULL);
|
||||
} else {
|
||||
wwarning("wl_backend: XWayland ready but XOpenDisplay failed — pure Wayland mode");
|
||||
}
|
||||
}
|
||||
|
||||
return NULL; /* pure Wayland: no X11 Display* used by the WM */
|
||||
return wl_state.x_display;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -2130,6 +2188,18 @@ wl_display_close(void)
|
|||
{
|
||||
if (!wl_state.started)
|
||||
return;
|
||||
|
||||
/* Remove the X11 event source and close the Xlib bridge connection
|
||||
* before killing XWayland so we don't get stale readable events. */
|
||||
if (wl_state.x11_event_source) {
|
||||
wl_event_source_remove(wl_state.x11_event_source);
|
||||
wl_state.x11_event_source = NULL;
|
||||
}
|
||||
if (wl_state.x_display) {
|
||||
XCloseDisplay(wl_state.x_display);
|
||||
wl_state.x_display = NULL;
|
||||
}
|
||||
|
||||
/* Phase 17: shut down XWayland.
|
||||
*
|
||||
* wlroots 0.15 bug: wlr_xwayland_server_destroy() calls wl_client_destroy()
|
||||
|
|
@ -2970,8 +3040,17 @@ wl_screen_open(WScreen *scr)
|
|||
scr->scr_height = wl_state.output ?
|
||||
(int)wl_state.output->height : 1080;
|
||||
scr->depth = 24;
|
||||
scr->root_win = WNATIVE_NONE;
|
||||
scr->root_win = WNATIVE_NONE;
|
||||
scr->colormap = 0;
|
||||
|
||||
/* XWayland bridge: fill in real X11 screen values so RCreateContext
|
||||
* and WINGs can use the display connection for drawing and fonts. */
|
||||
if (dpy) {
|
||||
int snum = DefaultScreen(dpy);
|
||||
scr->root_win = DefaultRootWindow(dpy);
|
||||
scr->depth = DefaultDepth(dpy, snum);
|
||||
scr->colormap = DefaultColormap(dpy, snum);
|
||||
}
|
||||
}
|
||||
|
||||
static void wl_screen_close(WScreen *scr) { (void)scr; }
|
||||
|
|
@ -4753,6 +4832,15 @@ wl_screen_create_internals(WScreen *scr)
|
|||
|
||||
wSetModifierMasks(Mod1Mask, Mod1Mask, Mod4Mask, 0);
|
||||
|
||||
/* XWayland bridge: create a real X11 helper window for EWMH
|
||||
* (_NET_SUPPORTING_WM_CHECK) and clipboard selection ownership. */
|
||||
if (dpy) {
|
||||
Window xwin = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
|
||||
0, 0, 1, 1, 0, 0, 0);
|
||||
if (xwin)
|
||||
scr->info_window = (WNativeWindow)xwin;
|
||||
}
|
||||
|
||||
/* Phase 30: the WDock X11 code path is still disabled (it needs X11 GCs /
|
||||
* pixmaps we don't have in pure Wayland mode). The visual dock panel is
|
||||
* created below via wm_dock_create() which uses wm_shm_surface directly. */
|
||||
|
|
|
|||
Loading…
Reference in New Issue