diff --git a/src/backend/backend.h b/src/backend/backend.h index 27549bf..3e29aba 100644 --- a/src/backend/backend.h +++ b/src/backend/backend.h @@ -1206,7 +1206,7 @@ typedef struct WMBackend { * RRScreenChangeNotify (calls XRRUpdateConfiguration then restarts). * No-op for event types not matching any known extension. */ - void (*event_handle_extensions)(void *event); + void (*event_handle_extensions)(WMEvent *event); /* * Notify the backend of a ConfigureNotify on the root window. @@ -1795,6 +1795,15 @@ typedef struct WMBackend { int (*event_check_type)(int event_type, WMEvent *event_out); void (*client_send_event)(WNativeWindow win, void *event_data); + /* + * Forward a ClientMessage event that was delivered to one window + * to a different target window. Used by handleClientMessage to + * redirect OffiX DND ClientMessages from icon frames to the actual + * client_win. Only meaningful for X11 (and XWayland clients via + * the Wayland backend). + */ + void (*client_message_forward)(WMEvent *event, WNativeWindow target_win); + /* * Deliver a synthetic key press/release to a client window. Used by * usermenu.c to translate menu entries into keystrokes for the @@ -1819,8 +1828,8 @@ typedef struct WMBackend { int (*window_get_command)(WNativeWindow win, char ***argv_out, int *argc_out); /* NETWM/XDND mechanism (Phase 80s) */ - int (*netwm_process_client_message)(void *xevent); - int (*xdnd_process_client_message)(void *xevent); + int (*netwm_process_client_message)(WMEvent *event); + int (*xdnd_process_client_message)(WMEvent *event); void (*xdnd_process_selection)(WMEvent *event); void (*xdnd_make_awareness)(WNativeWindow win); void (*netwm_check_client_hint_change)(WWindow *wwin, void *event); diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index 10d3fdc..67210b0 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -6252,7 +6252,7 @@ static void wl_event_sync(int discard) 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_handle_extensions(WMEvent *event) { (void)event; } static void wl_event_randr_update(WMEvent *event) { (void)event; } /* ------------------------------------------------------------------ */ @@ -8863,6 +8863,16 @@ static void wl_noop_event_flush_type(int t) { (void)t; } static int wl_noop_event_check_window(WNativeWindow win, int t) { (void)win; (void)t; return 0; } static int wl_noop_event_check_type(int t, WMEvent *e) { (void)t; (void)e; return 0; } static void wl_noop_client_send_event(WNativeWindow win, void *d) { (void)win; (void)d; } +static void wl_client_message_forward(WMEvent *event, WNativeWindow target_win) +{ + /* Forward OffiX DND ClientMessage to the real client_win for + * XWayland clients. Native Wayland clients have no analog. */ + if (!wl_state.x_display || !event) return; + XEvent *xev = (XEvent *)event->_x11_raw; + if (!xev) return; + xev->xclient.window = (Window)target_win; + XSendEvent(wl_state.x_display, (Window)target_win, False, 0L, xev); +} static void wl_client_send_key(WNativeWindow win, unsigned int keycode, unsigned int modifier_mask, int press) { @@ -8895,8 +8905,8 @@ static void wl_pointer_get_position(int *x, int *y) { } 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 int wl_noop_netwm_process_client_message(WMEvent *e) { (void)e; return 0; } +static int wl_noop_xdnd_process_client_message(WMEvent *e) { (void)e; return 0; } 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; } @@ -9165,6 +9175,7 @@ const WMBackend wl_backend = { .event_check_window = wl_noop_event_check_window, .event_check_type = wl_noop_event_check_type, .client_send_event = wl_noop_client_send_event, + .client_message_forward = wl_client_message_forward, .client_send_key = wl_client_send_key, .window_exists = wl_noop_window_exists, .window_get_colormap = wl_noop_window_get_colormap, diff --git a/src/backend/x11/x11_backend.c b/src/backend/x11/x11_backend.c index 1c3ba3b..8e049b4 100644 --- a/src/backend/x11/x11_backend.c +++ b/src/backend/x11/x11_backend.c @@ -2319,9 +2319,9 @@ x11_handle_xkb_indicator_state(XEvent *event) #endif /* KEEP_XKB_LOCK_STATUS */ static void -x11_event_handle_extensions(void *raw_event) +x11_event_handle_extensions(WMEvent *wev) { - XEvent *event = (XEvent *)raw_event; + XEvent *event = wev ? (XEvent *)wev->_x11_raw : NULL; if (!event) return; #ifdef USE_XSHAPE if (w_global.xext.shape.supported && @@ -3550,6 +3550,14 @@ static void x11_client_send_event(WNativeWindow win, void *event_data) XSendEvent(dpy, (Window)win, False, 0L, (XEvent *)event_data); } +static void x11_client_message_forward(WMEvent *event, WNativeWindow target_win) +{ + XEvent *xev = event ? (XEvent *)event->_x11_raw : NULL; + if (!xev) return; + xev->xclient.window = (Window)target_win; + XSendEvent(dpy, (Window)target_win, False, 0L, xev); +} + static void x11_client_send_key(WNativeWindow win, unsigned int keycode, unsigned int modifier_mask, int press) { @@ -3682,13 +3690,17 @@ static int x11_window_get_command(WNativeWindow win, char ***argv_out, int *argc return 0; } -static int x11_netwm_process_client_message(void *xevent) +static int x11_netwm_process_client_message(WMEvent *event) { - return wNETWMProcessClientMessage(&((XEvent *)xevent)->xclient); + XEvent *xev = event ? (XEvent *)event->_x11_raw : NULL; + if (!xev) return 0; + return wNETWMProcessClientMessage(&xev->xclient); } -static int x11_xdnd_process_client_message(void *xevent) +static int x11_xdnd_process_client_message(WMEvent *event) { - return wXDNDProcessClientMessage(&((XEvent *)xevent)->xclient); + XEvent *xev = event ? (XEvent *)event->_x11_raw : NULL; + if (!xev) return 0; + return wXDNDProcessClientMessage(&xev->xclient); } static void x11_xdnd_process_selection(WMEvent *event) { @@ -4672,6 +4684,7 @@ const WMBackend x11_backend = { .event_check_window = x11_event_check_window, .event_check_type = x11_event_check_type, .client_send_event = x11_client_send_event, + .client_message_forward = x11_client_message_forward, .client_send_key = x11_client_send_key, .window_exists = x11_window_exists, .window_get_colormap = x11_window_get_colormap, diff --git a/src/event.c b/src/event.c index bd3b6a7..e49c2a7 100644 --- a/src/event.c +++ b/src/event.c @@ -430,8 +430,7 @@ static int matchWindow(const void *item, const void *cdata) static void handleExtensions(WMEvent * event) { - if (event->_x11_raw) - wm_backend->event_handle_extensions((void *)event->_x11_raw); + wm_backend->event_handle_extensions(event); } static void handleMapRequest(WMEvent * ev) @@ -948,10 +947,10 @@ static void handleClientMessage(WMEvent * event) if (!scr) return; scr->flags.ignore_focus_events = event->u.clientMessage.data.l[0] ? 1 : 0; - } else if (event->_x11_raw && wm_backend->netwm_process_client_message(event->_x11_raw)) { + } else if (wm_backend->netwm_process_client_message(event)) { /* do nothing */ #ifdef USE_DOCK_XDND - } else if (event->_x11_raw && wm_backend->xdnd_process_client_message(event->_x11_raw)) { + } else if (wm_backend->xdnd_process_client_message(event)) { /* do nothing */ #endif /* USE_DOCK_XDND */ } else { @@ -969,13 +968,8 @@ static void handleClientMessage(WMEvent * event) icon = ((WAppIcon *) desc->parent)->icon; } if (icon && (wwin = icon->owner)) { - if (wwin->client_win != event->u.clientMessage.window) { - XEvent *xev = (XEvent *)event->_x11_raw; - if (xev) { - xev->xclient.window = wwin->client_win; - wm_backend->client_send_event((WNativeWindow)wwin->client_win, xev); - } - } + if (wwin->client_win != event->u.clientMessage.window) + wm_backend->client_message_forward(event, wwin->client_win); } } }