arch: eliminate _x11_raw escapes from event.c

Five _x11_raw accesses in shared event.c (the worst architectural leak)
removed by widening vtable signatures and moving X11-only logic into
the X11 backend:

  WME_SELECTION_REQUEST / WME_SELECTION_CLEAR
    * handle_selection_request/clear functions deleted from event.c
    * Reimplemented in x11_backend.c as x11_handle_selection_request/clear
      where they read _x11_raw internally and call XChangeProperty etc.
    * New vtable slots handle_selection_request / handle_selection_clear
      (WMEvent*).  Wayland: no-ops (wmaker UI does not own a WM_Sn
      selection on the X server).

  WME_CONFIGURE
    * event_randr_update vtable widened to (WMEvent*).
    * Root-window check (DefaultRootWindow) moved into x11 impl.

  WME_MAPPING
    * Dropped the if (xev) guard — keyboard_mapping_refresh already
      took WMEvent*.

  WME_SELECTION
    * xdnd_process_selection vtable widened to (WMEvent*).

Net: event.c is X11-free except for DefaultRootWindow uses elsewhere
that will be cleaned up in subsequent tasks.
This commit is contained in:
Window Maker 2026-05-24 08:37:50 +02:00
parent f2e49a8b67
commit 1c1f261fb2
5 changed files with 126 additions and 124 deletions

1
.gitignore vendored
View File

@ -85,3 +85,4 @@ WindowMaker/menu.*
WindowMaker/plmenu
WindowMaker/plmenu.*
WindowMaker/wmmacros
core.*

View File

@ -1215,7 +1215,7 @@ typedef struct WMBackend {
* Called from the ConfigureNotify case in the main event switch.
* No-op if USE_RANDR is not compiled in (or equivalent).
*/
void (*event_randr_update)(void *event);
void (*event_randr_update)(WMEvent *event);
/*
* Return the current XKB keyboard group (layout index, 0-based).
@ -1807,9 +1807,25 @@ typedef struct WMBackend {
/* NETWM/XDND mechanism (Phase 80s) */
int (*netwm_process_client_message)(void *xevent);
int (*xdnd_process_client_message)(void *xevent);
void (*xdnd_process_selection)(void *xevent);
void (*xdnd_process_selection)(WMEvent *event);
void (*xdnd_make_awareness)(WNativeWindow win);
void (*netwm_check_client_hint_change)(WWindow *wwin, void *event);
/*
* ICCCM WM-replacement SelectionRequest / SelectionClear handling.
*
* The X server delivers SelectionRequest/SelectionClear events for
* the WM_Sn selection that wmaker holds when running under X11.
* Both handlers need access to the X display, atom interning, and
* XChangeProperty — all X11-only. They live in the X11 backend.
*
* Wayland: the Wayland backend's wmaker UI does not own a WM_Sn
* selection on the X server, so these are no-ops. XWayland clients
* still receive their own selections via wlroots' data device path
* and never reach these slots.
*/
void (*handle_selection_request)(WMEvent *event);
void (*handle_selection_clear)(WMEvent *event);
void (*netwm_position_splash)(WWindow *wwin, int *x, int *y, int width, int height);
void (*netwm_check_initial_frame_state)(WWindow *wwin);

View File

@ -6253,7 +6253,7 @@ static int wl_event_pending(void) { return 0; }
static void wl_event_drain_motion(void) {}
static void wl_event_discard_enter_leave_until(unsigned long timestamp) { (void)timestamp; }
static void wl_event_handle_extensions(void *event) { (void)event; }
static void wl_event_randr_update(void *event) { (void)event; }
static void wl_event_randr_update(WMEvent *event) { (void)event; }
/* ------------------------------------------------------------------ */
/* Properties */
@ -8876,8 +8876,10 @@ static const char *wl_noop_keysym_to_string(unsigned long ks) { (void)ks; return
static int wl_noop_window_get_command(WNativeWindow win, char ***a, int *c) { (void)win; (void)a; *c=0; return 0; }
static int wl_noop_netwm_process_client_message(void *x) { (void)x; return 0; }
static int wl_noop_xdnd_process_client_message(void *x) { (void)x; return 0; }
static void wl_noop_xdnd_process_selection(void *x) { (void)x; }
static void wl_noop_xdnd_process_selection(WMEvent *e) { (void)e; }
static void wl_noop_xdnd_make_awareness(WNativeWindow w) { (void)w; }
static void wl_noop_handle_selection_request(WMEvent *e) { (void)e; }
static void wl_noop_handle_selection_clear(WMEvent *e) { (void)e; }
static void wl_noop_netwm_check_client_hint_change(WWindow *w, void *e) { (void)w; (void)e; }
static void wl_noop_netwm_position_splash(WWindow *w, int *x, int *y, int ww, int h) { (void)w;(void)x;(void)y;(void)ww;(void)h; }
static void wl_noop_netwm_check_initial_frame_state(WWindow *w) { (void)w; }
@ -9152,9 +9154,10 @@ const WMBackend wl_backend = {
.netwm_process_client_message = wl_noop_netwm_process_client_message,
.xdnd_process_client_message = wl_noop_xdnd_process_client_message,
.xdnd_process_selection = wl_noop_xdnd_process_selection,
.xdnd_make_awareness = wl_noop_xdnd_make_awareness,
.netwm_check_client_hint_change = wl_noop_netwm_check_client_hint_change,
.xdnd_make_awareness = wl_noop_xdnd_make_awareness, .netwm_check_client_hint_change = wl_noop_netwm_check_client_hint_change,
.netwm_position_splash = wl_noop_netwm_position_splash,
.netwm_check_initial_frame_state = wl_noop_netwm_check_initial_frame_state,
.handle_selection_request = wl_noop_handle_selection_request,
.handle_selection_clear = wl_noop_handle_selection_clear,
.create_rcontext = wl_create_rcontext,
};

View File

@ -2339,12 +2339,19 @@ x11_event_handle_extensions(void *raw_event)
}
static void
x11_event_randr_update(void *raw_event)
x11_event_randr_update(WMEvent *event)
{
#ifdef USE_RANDR
XRRUpdateConfiguration((XEvent *)raw_event);
if (!event)
return;
/* RandR root events only — ignore configure events on regular windows. */
if (event->u.configure.window != DefaultRootWindow(dpy))
return;
XEvent *xev = (XEvent *)event->_x11_raw;
if (xev)
XRRUpdateConfiguration(xev);
#else
(void) raw_event;
(void) event;
#endif
}
@ -3553,9 +3560,86 @@ static int x11_xdnd_process_client_message(void *xevent)
{
return wXDNDProcessClientMessage(&((XEvent *)xevent)->xclient);
}
static void x11_xdnd_process_selection(void *xevent)
static void x11_xdnd_process_selection(WMEvent *event)
{
wXDNDProcessSelection((XEvent *)xevent);
XEvent *xev = event ? (XEvent *)event->_x11_raw : NULL;
if (xev)
wXDNDProcessSelection(xev);
}
static void x11_handle_selection_request(WMEvent *event)
{
XEvent *xev = event ? (XEvent *)event->_x11_raw : NULL;
if (!xev) return;
XSelectionRequestEvent *xsr = &xev->xselectionrequest;
#ifdef USE_ICCCM_WMREPLACE
static Atom atom_version = None;
WScreen *scr;
XSelectionEvent notify;
/* Default reply: 'no selection'. */
notify.type = SelectionNotify;
notify.display = dpy;
notify.requestor = xsr->requestor;
notify.selection = xsr->selection;
notify.target = xsr->target;
notify.property = None;
notify.time = xsr->time;
scr = wScreenForWindow(xsr->owner);
if (!scr)
goto not_our_selection;
if (xsr->owner != scr->info_window)
goto not_our_selection;
if (xsr->selection != scr->sn_atom)
goto not_our_selection;
if (atom_version == None)
atom_version = XInternAtom(dpy, "VERSION", False);
if (xsr->target == atom_version) {
static const long icccm_version[] = { 2, 0 };
/* ICCCM 2.0: "Communication with the Window Manager by Means of
* Selections". Setting the property means the content of the
* selection is available. Old clients may pass property=None. */
notify.property = (xsr->property == None) ? xsr->target : xsr->property;
XChangeProperty(dpy, xsr->requestor, notify.property,
WA_INTEGER, 32, PropModeReplace,
(unsigned char *)icccm_version, wlengthof(icccm_version));
}
not_our_selection:
if (notify.property == None)
wwarning("received SelectionRequest(%s) for target=\"%s\" from "
"requestor 0x%lX but we have no answer",
XGetAtomName(dpy, xsr->selection),
XGetAtomName(dpy, xsr->target),
(long)xsr->requestor);
/* Send the answer to the requestor */
wm_backend->client_send_event((WNativeWindow)xsr->requestor, (void *)&notify);
#else
(void)xsr;
#endif
}
static void x11_handle_selection_clear(WMEvent *event)
{
XEvent *xev = event ? (XEvent *)event->_x11_raw : NULL;
if (!xev) return;
#ifdef USE_ICCCM_WMREPLACE
XSelectionClearEvent *xsc = &xev->xselectionclear;
WScreen *scr = wScreenForWindow(xsc->window);
if (!scr)
return;
if (xsc->selection != scr->sn_atom)
return;
wmessage(_("another window manager is replacing us!"));
Shutdown(WSExitMode);
#else
(void)xev;
#endif
}
static void x11_xdnd_make_awareness(WNativeWindow win)
{
@ -4470,6 +4554,8 @@ const WMBackend x11_backend = {
.xdnd_process_selection = x11_xdnd_process_selection,
.xdnd_make_awareness = x11_xdnd_make_awareness,
.netwm_check_client_hint_change = x11_netwm_check_client_hint_change,
.handle_selection_request = x11_handle_selection_request,
.handle_selection_clear = x11_handle_selection_clear,
.netwm_position_splash = x11_netwm_position_splash,
.netwm_check_initial_frame_state = x11_netwm_check_initial_frame_state,
.create_rcontext = x11_create_rcontext,

View File

@ -91,8 +91,6 @@ static void handleFocusIn(WMEvent *event);
static void handleMotionNotify(WMEvent *event);
static void handleVisibilityNotify(WMEvent *event);
/* inotify handling moved to x11_backend.c (x11_event_loop_run) */
static void handle_selection_request(XSelectionRequestEvent *event);
static void handle_selection_clear(XSelectionClearEvent *event);
static void wdelete_death_handler(WMagicNumber id);
@ -245,10 +243,8 @@ void DispatchEvent(WMEvent * event)
break;
case WME_MAPPING:
if (event->u.mapping.request == MappingKeyboard || event->u.mapping.request == MappingModifier) {
XEvent *xev = (XEvent *)event->_x11_raw;
if (xev) wm_backend->keyboard_mapping_refresh(event);
}
if (event->u.mapping.request == MappingKeyboard || event->u.mapping.request == MappingModifier)
wm_backend->keyboard_mapping_refresh(event);
break;
case WME_FOCUS_IN:
@ -260,22 +256,15 @@ void DispatchEvent(WMEvent * event)
break;
case WME_CONFIGURE:
if (event->u.configure.window == DefaultRootWindow(dpy))
wm_backend->event_randr_update((void *)event->_x11_raw);
wm_backend->event_randr_update(event);
break;
case WME_SELECTION_REQUEST:
{
XEvent *xev = (XEvent *)event->_x11_raw;
if (xev) handle_selection_request(&xev->xselectionrequest);
}
wm_backend->handle_selection_request(event);
break;
case WME_SELECTION_CLEAR:
{
XEvent *xev = (XEvent *)event->_x11_raw;
if (xev) handle_selection_clear(&xev->xselectionclear);
}
wm_backend->handle_selection_clear(event);
break;
default:
@ -427,10 +416,8 @@ static void saveTimestamp(WMEvent * event)
case WME_SELECTION:
w_global.timestamp.last_event = event->u.selection.time;
#ifdef USE_DOCK_XDND
if (event->type == WME_SELECTION) {
XEvent *xev = (XEvent *)event->_x11_raw;
if (xev) wm_backend->xdnd_process_selection(xev);
}
if (event->type == WME_SELECTION)
wm_backend->xdnd_process_selection(event);
#endif
break;
}
@ -1973,97 +1960,6 @@ static void handleVisibilityNotify(WMEvent * event)
wwin->flags.obscured = (event->u.visibility.state == VisibilityFullyObscured);
}
static void handle_selection_request(XSelectionRequestEvent *event)
{
#ifdef USE_ICCCM_WMREPLACE
static Atom atom_version = None;
WScreen *scr;
XSelectionEvent notify;
/* Selection request/clear handling moved to backend
* (X11 backend: x11_handle_selection_request/clear; Wayland: no-op) */
/*
* This event must be sent to the slection requester to not block him
*
* We create it with the answer 'there is no selection' by default
*/
notify.type = SelectionNotify;
notify.display = dpy;
notify.requestor = event->requestor;
notify.selection = event->selection;
notify.target = event->target;
notify.property = None; /* This says that there is no selection */
notify.time = event->time;
scr = wScreenForWindow(event->owner);
if (!scr)
goto not_our_selection;
if (event->owner != scr->info_window)
goto not_our_selection;
if (event->selection != scr->sn_atom)
goto not_our_selection;
if (atom_version == None)
atom_version = XInternAtom(dpy, "VERSION", False);
if (event->target == atom_version) {
static const long icccm_version[] = { 2, 0 };
/*
* This protocol is defined in ICCCM 2.0:
* http://www.x.org/releases/X11R7.7/doc/xorg-docs/icccm/icccm.html
* "Communication with the Window Manager by Means of Selections"
*/
/*
* Setting the property means the content of the selection is available
* According to the ICCCM spec, we need to support being asked for a property
* set to 'None' for compatibility with old clients
*/
notify.property = (event->property == None)?(event->target):(event->property);
XChangeProperty(dpy, event->requestor, notify.property,
WA_INTEGER, 32, PropModeReplace,
(unsigned char *) icccm_version, wlengthof(icccm_version));
}
not_our_selection:
if (notify.property == None)
wwarning("received SelectionRequest(%s) for target=\"%s\" from requestor 0x%lX but we have no answer",
XGetAtomName(dpy, event->selection), XGetAtomName(dpy, event->target), (long) event->requestor);
/* Send the answer to the requestor */
wm_backend->client_send_event((WNativeWindow)event->requestor, (void *)&notify);
#else
/*
* If the support for ICCCM window manager replacement was not enabled, we should not receive
* this kind of event, so we just ignore it (Conceptually, we should reply with 'SelectionNotify'
* event with property set to 'None' to tell that we don't have this selection, but that is a bit
* costly for an event that shall never happen).
*/
(void) event;
#endif
}
static void handle_selection_clear(XSelectionClearEvent *event)
{
#ifdef USE_ICCCM_WMREPLACE
WScreen *scr = wScreenForWindow(event->window);
if (!scr)
return;
if (event->selection != scr->sn_atom)
return;
wmessage(_("another window manager is replacing us!"));
Shutdown(WSExitMode);
#else
/*
* If the support for ICCCM window manager replacement was not enabled, we should not receive
* this kind of event, so we simply do nothing.
*/
(void) event;
#endif
}