Fix: set global dpy=NULL in Wayland mode

The global 'dpy' variable was set to the XWayland Display*, causing
120+ direct Xlib calls in the WM core (XMapWindow, XClearWindow, etc.)
to pass synthetic frame buffer IDs to XWayland — hanging the startup.

Fix: wl_display_open returns NULL so global dpy=NULL. All existing
'if (dpy)' guards in the WM core now correctly skip Xlib calls.
The Wayland backend uses wl_state.x_display directly for the few
XWayland operations it needs (atom interning, screen info, GC alloc
for the no-focus window).

This unblocks startup — the event loop now runs successfully.
This commit is contained in:
Levi Neely 2026-05-13 07:23:02 +02:00
parent 499d4fac7e
commit cc3655d2fd
2 changed files with 28 additions and 28 deletions

0
out.txt Normal file
View File

View File

@ -2514,7 +2514,7 @@ wl_display_open(const char *name)
}
}
return wl_state.x_display;
return NULL; /* dpy=NULL so WM core skips Xlib calls */
}
static void
@ -3288,7 +3288,7 @@ static uint32_t *
wm_dock_load_icon(struct wl_toplevel_view *v, int *out_w, int *out_h)
{
*out_w = *out_h = 0;
if (!v->xw_surface || !dpy)
if (!v->xw_surface || !wl_state.x_display)
return NULL; /* XDG native: no X11 icon path */
RImage *ri = get_window_image_from_x11((Window)v->id);
@ -3439,11 +3439,11 @@ wl_screen_open(WScreen *scr)
/* 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);
if (wl_state.x_display) {
int snum = DefaultScreen(wl_state.x_display);
scr->root_win = DefaultRootWindow(wl_state.x_display);
scr->depth = DefaultDepth(wl_state.x_display, snum);
scr->colormap = DefaultColormap(wl_state.x_display, snum);
}
}
@ -4998,14 +4998,14 @@ wl_stacking_query(WNativeWindow root,
static void wl_event_flush(void)
{
/* Flush pending Xlib requests to XWayland so drawing becomes visible. */
if (dpy)
XFlush(dpy);
if (wl_state.x_display)
XFlush(wl_state.x_display);
}
static void wl_event_flush_expose(void) {}
static void wl_event_sync(int discard)
{
if (dpy)
XSync(dpy, discard ? True : False);
if (wl_state.x_display)
XSync(wl_state.x_display, discard ? True : False);
}
static int wl_event_pending(void) { return 0; }
static void wl_event_drain_motion(void) {}
@ -5629,7 +5629,7 @@ wl_screen_alloc_gcs(WScreen *scr)
* (framewin, icon, menu) uses these regardless of the display backend.
* Mirrors x11_screen_alloc_gcs exactly; without these, CopyArea and
* XRender calls use GC/drawable 0 → BadDrawable → XWayland broken pipe. */
if (!dpy)
if (!wl_state.x_display)
return;
/* Mark the wrlib drawable as override_redirect so XWayland's XWM does not
@ -5643,11 +5643,11 @@ wl_screen_alloc_gcs(WScreen *scr)
wl_state.rcontext_xwin = (Window)scr->w_win;
XSetWindowAttributes or_attr;
or_attr.override_redirect = True;
XChangeWindowAttributes(dpy, (Window)scr->w_win, CWOverrideRedirect, &or_attr);
XFlush(dpy);
XChangeWindowAttributes(wl_state.x_display, (Window)scr->w_win, CWOverrideRedirect, &or_attr);
XFlush(wl_state.x_display);
}
scr->stipple_bitmap = XCreateBitmapFromData(dpy, (Window)scr->w_win,
scr->stipple_bitmap = XCreateBitmapFromData(wl_state.x_display, (Window)scr->w_win,
stipple_data, 2, 2);
gcv.stipple = scr->stipple_bitmap;
@ -5655,7 +5655,7 @@ wl_screen_alloc_gcs(WScreen *scr)
gcv.fill_style = FillStippled;
gcv.graphics_exposures = False;
gcm = GCForeground | GCStipple | GCFillStyle | GCGraphicsExposures;
scr->stipple_gc = XCreateGC(dpy, (Window)scr->w_win, gcm, &gcv);
scr->stipple_gc = XCreateGC(wl_state.x_display, (Window)scr->w_win, gcm, &gcv);
gcv.function = GXcopy;
gcv.foreground = scr->white_pixel;
@ -5668,7 +5668,7 @@ wl_screen_alloc_gcs(WScreen *scr)
gcv.graphics_exposures = False;
gcm = GCFunction | GCGraphicsExposures | GCForeground | GCBackground
| GCLineWidth | GCLineStyle | GCFillStyle | GCDashOffset | GCDashList;
scr->icon_select_gc = XCreateGC(dpy, (Window)scr->w_win, gcm, &gcv);
scr->icon_select_gc = XCreateGC(wl_state.x_display, (Window)scr->w_win, gcm, &gcv);
gcv.function = GXxor;
gcv.plane_mask = AllPlanes;
@ -5678,7 +5678,7 @@ wl_screen_alloc_gcs(WScreen *scr)
gcv.line_width = DEF_FRAME_THICKNESS;
gcv.subwindow_mode = IncludeInferiors;
gcv.graphics_exposures = False;
scr->frame_gc = XCreateGC(dpy, (Window)scr->root_win,
scr->frame_gc = XCreateGC(wl_state.x_display, (Window)scr->root_win,
GCForeground | GCGraphicsExposures | GCFunction
| GCSubwindowMode | GCLineWidth | GCPlaneMask, &gcv);
@ -5692,19 +5692,19 @@ wl_screen_alloc_gcs(WScreen *scr)
gcv.graphics_exposures = False;
gcm = GCForeground | GCFunction | GCSubwindowMode | GCLineWidth
| GCCapStyle | GCGraphicsExposures;
scr->line_gc = XCreateGC(dpy, (Window)scr->root_win, gcm, &gcv);
scr->line_gc = XCreateGC(wl_state.x_display, (Window)scr->root_win, gcm, &gcv);
scr->line_pixel = gcv.foreground;
gcv.foreground = scr->white_pixel;
gcv.background = scr->black_pixel;
gcv.graphics_exposures = False;
scr->copy_gc = XCreateGC(dpy, (Window)scr->w_win,
scr->copy_gc = XCreateGC(wl_state.x_display, (Window)scr->w_win,
GCForeground | GCBackground | GCGraphicsExposures, &gcv);
gcv.graphics_exposures = False;
scr->draw_gc = XCreateGC(dpy, (Window)scr->w_win, GCGraphicsExposures, &gcv);
scr->draw_gc = XCreateGC(wl_state.x_display, (Window)scr->w_win, GCGraphicsExposures, &gcv);
scr->mono_gc = XCreateGC(dpy, scr->stipple_bitmap, GCGraphicsExposures, &gcv);
scr->mono_gc = XCreateGC(wl_state.x_display, scr->stipple_bitmap, GCGraphicsExposures, &gcv);
}
static void
wl_screen_create_internals(WScreen *scr)
@ -5713,17 +5713,17 @@ wl_screen_create_internals(WScreen *scr)
* when no application window holds it. This mirrors x11_screen_create_internals
* exactly: without a mapped, viewable focus-sink window, any XSetInputFocus
* call targeting it (serial ~1626 during manageAllWindows) returns BadMatch. */
if (dpy) {
if (wl_state.x_display) {
XSetWindowAttributes attribs;
int vmask = CWEventMask | CWOverrideRedirect;
attribs.event_mask = KeyPressMask | FocusChangeMask;
attribs.override_redirect = True;
Window xwin = XCreateWindow(dpy, DefaultRootWindow(dpy),
Window xwin = XCreateWindow(wl_state.x_display, DefaultRootWindow(wl_state.x_display),
-10, -10, 4, 4, 0,
0, InputOnly, CopyFromParent, vmask, &attribs);
if (xwin) {
XSelectInput(dpy, xwin, KeyPressMask | KeyReleaseMask);
XMapWindow(dpy, xwin);
XSelectInput(wl_state.x_display, xwin, KeyPressMask | KeyReleaseMask);
XMapWindow(wl_state.x_display, xwin);
/* Do NOT call XSetInputFocus here: the window may not be viewable
* yet in XWayland (map is async), triggering BadMatch that perturbs
* XWayland state and causes a Wayland broken-pipe cascade.
@ -5745,10 +5745,10 @@ wl_screen_create_internals(WScreen *scr)
* override_redirect=True prevents XWayland's XWM from managing it as a
* client window (otherwise it appears as class=(none) and generates
* BadDrawable errors from wlroots when wManageWindow tries to reparent it). */
if (dpy) {
if (wl_state.x_display) {
XSetWindowAttributes iattr;
iattr.override_redirect = True;
Window xwin = XCreateWindow(dpy, DefaultRootWindow(dpy),
Window xwin = XCreateWindow(wl_state.x_display, DefaultRootWindow(wl_state.x_display),
-2, -2, 1, 1, 0,
0, InputOutput, CopyFromParent,
CWOverrideRedirect, &iattr);