Implement input dispatch: hit-test pointer events to WM windows

- frame_buf_at(): hit-test finds which WM frame_buf is under pointer
- Button/motion events set window field to frame_buf ID or root_win
- Root window gets synthetic ID (0x0FFFFFFF) in Wayland mode
- Right-click on background → handleButtonPress → OpenRootMenu path
- wSelectWindows: remove XEvent dependency, take (x, y) coordinates
- Zero X11 symbols in event.o and moveres.o (verified with nm)
This commit is contained in:
Levi Neely 2026-05-13 15:57:40 +02:00
parent fe8f7a923f
commit ac739a1a5c
4 changed files with 67 additions and 17 deletions

View File

@ -53,7 +53,7 @@ void wUnshadeWindow(WWindow *wwin);
void wIconifyWindow(WWindow *wwin);
void wDeiconifyWindow(WWindow *wwin);
void wSelectWindows(WScreen *scr, XEvent *ev);
void wSelectWindows(WScreen *scr, int x_root, int y_root);
void wSelectWindow(WWindow *wwin, Bool flag);
void wUnselectWindows(WScreen *scr);

View File

@ -3442,7 +3442,7 @@ 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 = (WNativeWindow)0x0FFFFFFF; /* synthetic root window ID */
scr->colormap = 0;
/* XWayland bridge: fill in real X11 screen values so RCreateContext
@ -3501,6 +3501,22 @@ frame_buf_find(WNativeWindow id)
return NULL;
}
/* Hit-test: find the topmost frame_buf containing (px, py). */
static struct wl_frame_buf *
frame_buf_at(int px, int py)
{
struct wl_frame_buf *hit = NULL;
struct wl_frame_buf *fb;
wl_list_for_each(fb, &wl_state.frame_list, link) {
if (!fb->scene_buf || !fb->scene_buf->node.enabled)
continue;
if (px >= fb->x && px < fb->x + fb->width &&
py >= fb->y && py < fb->y + fb->height)
hit = fb; /* last match = topmost in scene order */
}
return hit;
}
/* ------------------------------------------------------------------ */
/* Frame / window lifecycle */
/* ------------------------------------------------------------------ */
@ -3879,10 +3895,22 @@ handle_pointer_motion(struct wl_listener *listener, void *data)
WMEvent wev;
memset(&wev, 0, sizeof(wev));
wev.type = WME_MOTION;
wev.window = WNATIVE_NONE;
struct wl_frame_buf *fb = frame_buf_at(wl_state.pointer_x,
wl_state.pointer_y);
if (fb) {
wev.window = fb->id;
wev.u.motion.window = fb->id;
wev.u.motion.x = wl_state.pointer_x - fb->x;
wev.u.motion.y = wl_state.pointer_y - fb->y;
} else {
WScreen *scr0 = wScreenWithNumber(0);
WNativeWindow root = scr0 ? scr0->root_win : (WNativeWindow)0x0FFFFFFF;
wev.window = root;
wev.u.motion.window = root;
wev.u.motion.x = wl_state.pointer_x;
wev.u.motion.y = wl_state.pointer_y;
}
wev.u.motion.time = ev->time_msec;
wev.u.motion.x = wl_state.pointer_x;
wev.u.motion.y = wl_state.pointer_y;
wev.u.motion.x_root = wl_state.pointer_x;
wev.u.motion.y_root = wl_state.pointer_y;
W_WL_EnqueueEvent(wmscr, &wev, NULL);
@ -3920,10 +3948,22 @@ handle_pointer_motion_absolute(struct wl_listener *listener, void *data)
WMEvent wev;
memset(&wev, 0, sizeof(wev));
wev.type = WME_MOTION;
wev.window = WNATIVE_NONE;
struct wl_frame_buf *fb = frame_buf_at(wl_state.pointer_x,
wl_state.pointer_y);
if (fb) {
wev.window = fb->id;
wev.u.motion.window = fb->id;
wev.u.motion.x = wl_state.pointer_x - fb->x;
wev.u.motion.y = wl_state.pointer_y - fb->y;
} else {
WScreen *scr0 = wScreenWithNumber(0);
WNativeWindow root = scr0 ? scr0->root_win : (WNativeWindow)0x0FFFFFFF;
wev.window = root;
wev.u.motion.window = root;
wev.u.motion.x = wl_state.pointer_x;
wev.u.motion.y = wl_state.pointer_y;
}
wev.u.motion.time = ev->time_msec;
wev.u.motion.x = wl_state.pointer_x;
wev.u.motion.y = wl_state.pointer_y;
wev.u.motion.x_root = wl_state.pointer_x;
wev.u.motion.y_root = wl_state.pointer_y;
W_WL_EnqueueEvent(wmscr2, &wev, NULL);
@ -4448,10 +4488,24 @@ handle_pointer_button(struct wl_listener *listener, void *data)
memset(&wev, 0, sizeof(wev));
wev.type = (ev->state == WLR_BUTTON_PRESSED)
? WME_BUTTON_PRESS : WME_BUTTON_RELEASE;
wev.window = WNATIVE_NONE;
/* Hit-test: determine which WM window was clicked */
struct wl_frame_buf *fb = frame_buf_at(wl_state.pointer_x,
wl_state.pointer_y);
if (fb) {
wev.window = fb->id;
wev.u.button.window = fb->id;
wev.u.button.x = wl_state.pointer_x - fb->x;
wev.u.button.y = wl_state.pointer_y - fb->y;
} else {
WScreen *scr0 = wScreenWithNumber(0);
WNativeWindow root = scr0 ? scr0->root_win : (WNativeWindow)0x0FFFFFFF;
wev.window = root;
wev.u.button.window = root;
wev.u.button.x = wl_state.pointer_x;
wev.u.button.y = wl_state.pointer_y;
}
wev.u.button.time = ev->time_msec;
wev.u.button.x = wl_state.pointer_x;
wev.u.button.y = wl_state.pointer_y;
wev.u.button.x_root = wl_state.pointer_x;
wev.u.button.y_root = wl_state.pointer_y;
/* Linux evdev BTN_LEFT=0x110, BTN_RIGHT=0x111, BTN_MIDDLE=0x112

View File

@ -744,7 +744,7 @@ static void executeButtonAction(WScreen *scr, WMEvent *event, int action)
switch (action) {
case WA_SELECT_WINDOWS:
wUnselectWindows(scr);
wSelectWindows(scr, (XEvent *)event->_x11_raw);
wSelectWindows(scr, event->u.button.x_root, event->u.button.y_root);
if (wPreferences.close_rootmenu_left_right_click){
WMenu *menu = NULL;
WMPropList *definition;

View File

@ -2311,12 +2311,10 @@ static void selectWindowsInside(WScreen * scr, int x1, int y1, int x2, int y2)
}
}
void wSelectWindows(WScreen * scr, XEvent * ev)
void wSelectWindows(WScreen * scr, int xp, int yp)
{
WMEvent event;
WNativeWindow root = scr->root_win;
int xp = ev->xbutton.x_root;
int yp = ev->xbutton.y_root;
int w = 0, h = 0;
int x = xp, y = yp;
@ -2357,8 +2355,6 @@ void wSelectWindows(WScreen * scr, XEvent * ev)
break;
case WME_BUTTON_RELEASE:
if (event.u.button.button != ev->xbutton.button)
break;
wm_backend->overlay_draw_rect(scr, x, y, w, h);
wm_backend->server_ungrab();