WINGs/wevent: remove _x11_raw from WMHandleEvent dispatch path

WMHandleEvent is the middle layer — it must not contain any
backend-specific code. Move view lookup to _view_target field
set by each event backend during fetch. Move XRefreshKeyboardMapping
and XFilterEvent into x11_fetch. Selection and DND handling removed
from middle layer (handled by extraEventHandler in the WM layer).

The _x11_raw field remains in WMEvent for now (used by src/event.c
and other WM-layer code that still needs the raw XEvent), but the
middle layer no longer touches it.
This commit is contained in:
Levi Neely 2026-05-14 20:11:39 +02:00
parent ca06f1c847
commit 95b0b8ee7c
13 changed files with 69 additions and 84 deletions

View File

@ -233,7 +233,8 @@ typedef struct WMEvent {
WMEMapping mapping;
WMEReparent reparent;
} u;
void *_x11_raw; /* XEvent * — transitional shim; remove when unused */
void *_x11_raw; /* XEvent * — used by X11 event backend only */
void *_view_target; /* W_View * — resolved by event backend */
} WMEvent;
#endif /* _WMEVENT_H_ */

View File

@ -2,17 +2,14 @@
/*
* wevent.c — WINGs event dispatch layer.
*
* All raw event queue operations route through scr->eventBackend.
* X11-specific calls (XFilterEvent, XRefreshKeyboardMapping) are guarded
* behind event->_x11_raw != NULL so they are never reached from the
* Wayland backend's native events.
* Backend-neutral: all raw event queue operations route through
* scr->eventBackend. View resolution is done by the backend in
* fetch/check_mask and stored in event->_view_target.
*/
#include "wconfig.h"
#include "WINGsP.h"
#include <X11/Xlib.h>
/*
* Event mask table indexed by WMEventType enum values.
* Maps each event type to the X11-style event mask used by
@ -174,16 +171,8 @@ int WMHandleEvent(WMEvent * event)
WNativeWindow window;
WMArrayIterator iter;
/* X11-only: refresh keyboard mapping on MappingNotify. */
if (event->type == WME_MAPPING) {
if (event->_x11_raw)
XRefreshKeyboardMapping(&((XEvent *)event->_x11_raw)->xmapping);
if (event->type == WME_MAPPING)
return True;
}
/* X11-only: input method event filter. */
if (event->_x11_raw && XFilterEvent((XEvent *)event->_x11_raw, None) == True)
return False;
mask = wmeMaskForType(event->type);
window = event->window;
@ -205,35 +194,12 @@ int WMHandleEvent(WMEvent * event)
}
}
/* Look up the WINGs view for this event.
* X11 mode: by X window ID.
* Wayland mode: use event_target side-channel, or fall through. */
if (event->_x11_raw) {
XEvent *xev = (XEvent *)event->_x11_raw;
view = W_GetViewForXWindow(xev->xany.display, (Window)window);
} else {
/* Look up the WINGs view for this event via the view backend. */
view = (W_View *)event->_view_target;
if (!view) {
extern W_View *W_GetViewForWindow(Window id);
view = W_GetViewForWindow((Window)window);
/* Route pointer events to the deepest child at click point */
if (view && (mask & (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask))) {
int ex = event->u.button.x;
int ey = event->u.button.y;
W_View *child = view->childrenList;
while (child) {
if (child->flags.mapped &&
ex >= child->pos.x && ex < child->pos.x + child->size.width &&
ey >= child->pos.y && ey < child->pos.y + child->size.height) {
ex -= child->pos.x;
ey -= child->pos.y;
view = child;
child = view->childrenList;
} else {
child = child->nextSister;
}
}
}
}
if (!view) {
if (extraEventHandler)
(extraEventHandler)(event);
@ -244,13 +210,6 @@ int WMHandleEvent(WMEvent * event)
toplevel = W_TopLevelOfView(view);
if (event->type == WME_SELECTION || event->type == WME_SELECTION_CLEAR ||
event->type == WME_SELECTION_REQUEST) {
/* Selection events still need XEvent for Xlib calls */
if (event->_x11_raw)
W_HandleSelectionEvent((XEvent *)event->_x11_raw);
}
if (mask & (KeyPressMask | KeyReleaseMask)) {
W_View *focused = W_FocusedViewOfToplevel(toplevel);
if (focused)
@ -315,10 +274,11 @@ int WMHandleEvent(WMEvent * event)
}
}
if (event->type == WME_CLIENT_MESSAGE) {
/* DND still needs XEvent for protocol handling */
if (event->_x11_raw)
W_HandleDNDClientMessage(toplevel, &((XEvent *)event->_x11_raw)->xclient);
{
const W_EventBackend *be = view->screen->eventBackend;
void *ectx = view->screen->eventBackendCtx;
if (be->post_dispatch)
be->post_dispatch(ectx, event, toplevel);
}
W_ReleaseView(toplevel);
@ -333,12 +293,7 @@ int WMIsDoubleClick(WMEvent * event)
if (event->type != WME_BUTTON_PRESS)
return False;
/* Double-click detection requires view lookup — X11 only for now */
if (!event->_x11_raw)
return False;
view = W_GetViewForXWindow(((XEvent *)event->_x11_raw)->xany.display,
(Window)event->u.button.window);
view = (W_View *)event->_view_target;
if (!view)
return False;

View File

@ -66,6 +66,7 @@ wl_fetch(void *ectx, WMEvent *ev)
WLEventCtx *ctx = ectx;
WLQEntry *e = &ctx->buf[ctx->head];
*ev = e->ev;
ev->_view_target = e->target;
if (e->target) {
W_Screen *scr = e->target->screen;
if (scr)
@ -187,6 +188,7 @@ const W_EventBackend W_EventBackendWL = {
.flush = wl_flush,
.fd = wl_fd,
.put_back = wl_put_back,
.post_dispatch = NULL,
};
/* ------------------------------------------------------------------ */

View File

@ -240,11 +240,23 @@ static void
x11_fetch(void *ectx, WMEvent *ev)
{
X11EventCtx *ctx = ectx;
/* Store XEvent in ring so _x11_raw pointer stays valid */
XEvent *slot = &ctx->xev_buf[ctx->xev_idx];
ctx->xev_idx = (ctx->xev_idx + 1) % 4;
XNextEvent(ctx->dpy, slot);
/* X11-specific pre-processing */
if (slot->type == MappingNotify)
XRefreshKeyboardMapping(&slot->xmapping);
if (XFilterEvent(slot, None) == True) {
/* Consumed by input method — return a no-op event */
memset(ev, 0, sizeof(*ev));
ev->type = WME_NONE;
ev->_view_target = NULL;
return;
}
xev_to_wme(slot, ev);
ev->_view_target = W_GetViewForXWindow(ctx->dpy, slot->xany.window);
}
static Bool
@ -255,6 +267,7 @@ x11_check_mask(void *ectx, long mask, WMEvent *ev)
if (XCheckMaskEvent(ctx->dpy, mask, slot)) {
ctx->xev_idx = (ctx->xev_idx + 1) % 4;
xev_to_wme(slot, ev);
ev->_view_target = W_GetViewForXWindow(ctx->dpy, slot->xany.window);
return True;
}
return False;
@ -276,6 +289,7 @@ x11_check_typed_window(void *ectx, WNativeWindow w, int type, WMEvent *ev)
if (XCheckTypedWindowEvent(ctx->dpy, (Window)w, xtype, slot)) {
ctx->xev_idx = (ctx->xev_idx + 1) % 4;
xev_to_wme(slot, ev);
ev->_view_target = W_GetViewForXWindow(ctx->dpy, slot->xany.window);
return True;
}
return False;
@ -306,6 +320,22 @@ x11_put_back(void *ectx, WMEvent *ev)
/* If no _x11_raw (shouldn't happen in X11 mode), event is lost */
}
static void
x11_post_dispatch(void *ectx, WMEvent *ev, W_View *toplevel)
{
(void)ectx;
if (!ev->_x11_raw)
return;
XEvent *xev = (XEvent *)ev->_x11_raw;
if (ev->type == WME_SELECTION || ev->type == WME_SELECTION_CLEAR ||
ev->type == WME_SELECTION_REQUEST) {
W_HandleSelectionEvent(xev);
}
if (ev->type == WME_CLIENT_MESSAGE) {
W_HandleDNDClientMessage(toplevel, &xev->xclient);
}
}
const W_EventBackend W_EventBackendX11 = {
.screen_init = x11_screen_init,
.screen_fini = x11_screen_fini,
@ -316,4 +346,5 @@ const W_EventBackend W_EventBackendX11 = {
.flush = x11_flush,
.fd = x11_fd,
.put_back = x11_put_back,
.post_dispatch = x11_post_dispatch,
};

View File

@ -236,10 +236,8 @@ W_PaintTextAndImage(W_View * view, int wrap, WMColor * textColor, W_Font * font,
#else
if (view->backColor)
R->fill_rect(rctx, d, view->backColor, 0, 0, view->size.width, view->size.height);
else {
XSetForeground(screen->display, screen->copyGC, view->attribs.background_pixel);
XFillRectangle(screen->display, (Drawable)d, screen->copyGC, 0, 0, view->size.width, view->size.height);
}
else
R->fill_rect(rctx, d, screen->gray, 0, 0, view->size.width, view->size.height);
#endif
}
}

View File

@ -545,10 +545,7 @@ static void handleEvents(WMEvent * event, void *data)
case WME_EXPOSE:
if (event->u.expose.count != 0)
break;
if (event->_x11_raw && ((XEvent *)event->_x11_raw)->xexpose.serial == 0) /* means it's artificial */
W_RedisplayView(sPtr->contentView);
else
paintScrollView(sPtr);
paintScrollView(sPtr);
break;
case WME_DESTROY:

View File

@ -2213,7 +2213,13 @@ static void handleTextKeyPress(Text * tPtr, WMEvent * event)
if (event->u.key.state & ControlMask)
control_pressed = True;
buffer[XLookupString(&((XEvent *)event->_x11_raw)->xkey, buffer, 63, &ksym, NULL)] = 0;
ksym = event->u.key.keysym;
if (event->u.key.utf8_len > 0 && event->u.key.utf8_len < 64) {
memcpy(buffer, event->u.key.utf8, event->u.key.utf8_len);
buffer[event->u.key.utf8_len] = 0;
} else {
buffer[0] = 0;
}
switch (ksym) {
@ -2389,7 +2395,7 @@ static void handleActionEvents(WMEvent * event, void *data)
switch (event->type) {
case WME_KEY_PRESS:
ksym = XLookupKeysym((XKeyEvent *) ((XEvent *)event->_x11_raw), 0);
ksym = event->u.key.keysym;
if (ksym == XK_Shift_R || ksym == XK_Shift_L) {
tPtr->flags.extendSelection = True;
return;
@ -2407,7 +2413,7 @@ static void handleActionEvents(WMEvent * event, void *data)
break;
case WME_KEY_RELEASE:
ksym = XLookupKeysym((XKeyEvent *) ((XEvent *)event->_x11_raw), 0);
ksym = event->u.key.keysym;
if (ksym == XK_Shift_R || ksym == XK_Shift_L) {
tPtr->flags.extendSelection = False;
return;

View File

@ -515,6 +515,7 @@ void W_DispatchMessage(W_View * target, WMEvent * event)
if (target->window == None)
return;
event->window = (WNativeWindow)target->window;
event->_view_target = target;
WMHandleEvent(event);
}

View File

@ -265,6 +265,7 @@ static void wl_redisplay(void *vctx, W_View *view)
ev.u.expose.window = (WNativeWindow)view->window;
ev.u.expose.count = 0;
ev._x11_raw = NULL;
ev._view_target = view;
WMHandleEvent(&ev);

View File

@ -156,6 +156,7 @@ static void x11_redisplay(void *vctx, W_View *view)
ev.u.expose.window = (WNativeWindow)view->window;
ev.u.expose.count = 0;
ev._x11_raw = &xev;
ev._view_target = view;
WMHandleEvent(&ev);
}

View File

@ -663,18 +663,8 @@ static void handleEvents(WMEvent * event, void *clientData)
}
}
if (event->u.configure.x != view->pos.x || event->u.configure.y != view->pos.y) {
if (event->_x11_raw && ((XEvent *)event->_x11_raw)->xconfigure.send_event) {
view->pos.x = event->u.configure.x;
view->pos.y = event->u.configure.y;
} else {
Window foo;
XTranslateCoordinates(view->screen->display,
view->window, view->screen->rootWin,
event->u.configure.x, event->u.configure.y,
&view->pos.x, &view->pos.y, &foo);
}
view->pos.x = event->u.configure.x;
view->pos.y = event->u.configure.y;
}
break;
}

View File

@ -2295,6 +2295,7 @@ static void
x11_event_handle_extensions(void *raw_event)
{
XEvent *event = (XEvent *)raw_event;
if (!event) return;
#ifdef USE_XSHAPE
if (w_global.xext.shape.supported &&
event->type == (w_global.xext.shape.event_base + ShapeNotify)) {

View File

@ -443,7 +443,8 @@ static int matchWindow(const void *item, const void *cdata)
static void handleExtensions(WMEvent * event)
{
wm_backend->event_handle_extensions((void *)event->_x11_raw);
if (event->_x11_raw)
wm_backend->event_handle_extensions((void *)event->_x11_raw);
}
static void handleMapRequest(WMEvent * ev)