diff --git a/WINGs/wevent_wl.c b/WINGs/wevent_wl.c index 7b34ef4..608eaf3 100644 --- a/WINGs/wevent_wl.c +++ b/WINGs/wevent_wl.c @@ -150,7 +150,12 @@ wl_check_typed_window(void *ectx, WNativeWindow w, int type, WMEvent *ev) static void wl_flush(void *ectx, Bool discard) { - (void)ectx; (void)discard; + WLEventCtx *ctx = ectx; + (void)discard; + /* Pump the wlroots event loop so pointer/key events arrive in our queue. + * This is called from waitForEvent/WMMaskEvent when the queue is empty. */ + if (ctx->dispatch_fn) + ctx->dispatch_fn(0, ctx->dispatch_ud); } static int diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index 64a6ddf..b1c78f7 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -194,12 +194,13 @@ #include "../../icon.h" /* WIcon, TILE_* */ #include "../../appicon.h" /* WAppIcon */ #include "../../menu.h" /* WMenu, WMenuEntry */ +#include "../../balloon.h" /* WBalloon */ #include "../backend.h" #include "wl_backend.h" /* ------------------------------------------------------------------ */ -/* WINGs event backend interface (declared in WINGs/WINGsP.h) */ -/* Forward-declared here to avoid pulling the full private header. */ +/* WINGs private header — needed for W_EventBackend, W_Screen fields */ +#include /* ------------------------------------------------------------------ */ #include struct W_Screen; @@ -364,6 +365,7 @@ struct wl_compositor_state { struct wl_event_source *x11_event_source; /* wl_event_loop fd watcher for x_display */ pthread_t startup_pump_thread; /* pumps Wayland event loop during StartUp() */ volatile int startup_pump_running; /* 1 while pump thread is active */ + volatile int terminate; /* set to exit main loop */ /* Phase 20: real input devices from nested backend + their listeners */ struct wlr_input_device *real_keyboard_dev; struct wlr_input_device *real_pointer_dev; @@ -545,8 +547,7 @@ wl_shutdown_pipe_handler(int fd, uint32_t mask, void *data) /* drain the pipe so the fd does not stay readable */ while (read(fd, buf, sizeof(buf)) > 0) ; - if (wl_state.display) - wl_display_terminate(wl_state.display); + wl_state.terminate = 1; return 0; } @@ -554,13 +555,12 @@ static int frame_timer_cb(void *data) { (void)data; - /* Skip wlroots rendering calls while the startup pump thread is running — - * wlr_output_send_frame involves EGL context operations that are not safe - * to call from a non-main thread. */ + if (!wl_state.startup_pump_running) { if (!wl_state.is_nested && wl_state.output) wlr_output_send_frame(wl_state.output); } + if (wl_state.frame_timer) wl_event_source_timer_update(wl_state.frame_timer, 16); return 0; @@ -2797,9 +2797,8 @@ wl_signalfd_handler(int fd, uint32_t mask, void *data) /* Set the exit state flag so post-loop cleanup paths see it. */ SIG_WCHANGE_STATE(WSTATE_NEED_EXIT); - /* Terminate the event loop from within loop context. */ - if (wl_state.display) - wl_display_terminate(wl_state.display); + /* Terminate the event loop. */ + wl_state.terminate = 1; return 0; } @@ -2919,7 +2918,33 @@ wl_event_loop_run(void) } wwarning("wl_backend: event loop running"); - wl_display_run(wl_state.display); + + /* Custom event loop: pump wlroots, then drain WINGs events. + * We can't use wl_display_run() because WM event handlers (OpenRootMenu, + * etc.) call WMMaskEvent which re-enters the wlroots loop. By draining + * WINGs events BETWEEN dispatches (not inside a timer callback), modal + * loops in WMMaskEvent can safely call wl_event_loop_dispatch. */ + { + struct wl_event_loop *loop = wl_display_get_event_loop(wl_state.display); + while (!wl_state.terminate) { + wl_display_flush_clients(wl_state.display); + wl_event_loop_dispatch(loop, 16); + + /* Drain WINGs event queue */ + WMScreen *wmscr = wl_get_wmscreen(); + if (wmscr) { + const W_EventBackend *be = wmscr->eventBackend; + void *ectx = wmscr->eventBackendCtx; + WMEvent wev; + int limit = 64; + while (be->pending(ectx) && limit-- > 0) { + be->fetch(ectx, &wev); + WMHandleEvent(&wev); + } + } + } + } + wwarning("wl_backend: event loop exited"); } @@ -6414,7 +6439,10 @@ static void wl_noop_icon_select(WIcon *icon) { (void)icon; } static void wl_noop_icon_change_title(WIcon *icon, WWindow *wwin) { (void)icon; (void)wwin; } static void wl_clip_icon_paint(WAppIcon *aicon) { wl_appicon_paint(aicon); } static void wl_drawer_icon_paint(WAppIcon *aicon) { wl_appicon_paint(aicon); } -static void wl_noop_balloon_init(WScreen *scr) { (void)scr; } +static void wl_balloon_init(WScreen *scr) +{ + scr->balloon = wmalloc(sizeof(WBalloon)); +} static void wl_noop_do_kaboom(WScreen *scr, WNativeWindow win, int x, int y) { (void)scr; (void)win; (void)x; (void)y; } static void wl_menu_paint_entry(WMenu *menu, int index, int selected) @@ -6887,7 +6915,7 @@ const WMBackend wl_backend = { .icon_change_title = wl_noop_icon_change_title, .clip_icon_paint = wl_clip_icon_paint, .drawer_icon_paint = wl_drawer_icon_paint, - .balloon_init = wl_noop_balloon_init, + .balloon_init = wl_balloon_init, .do_kaboom = wl_noop_do_kaboom, .menu_paint_entry = wl_menu_paint_entry, .menu_draw_frame = wl_menu_draw_frame, diff --git a/src/balloon.c b/src/balloon.c index c5ac7c7..7b2c6e1 100644 --- a/src/balloon.c +++ b/src/balloon.c @@ -262,7 +262,7 @@ void wBalloonEnteredObject(WScreen *scr, WObjDescriptor *object) void wBalloonHide(WScreen *scr) { - if (scr) { + if (scr && scr->balloon) { if (scr->balloon->mapped) { wm_backend->window_unmap((WNativeWindow)scr->balloon->window); scr->balloon->mapped = 0; diff --git a/src/event.c b/src/event.c index 8f71d88..db28d5e 100644 --- a/src/event.c +++ b/src/event.c @@ -149,6 +149,7 @@ static void wdelete_death_handler(WMagicNumber id) void DispatchEvent(WMEvent * event) { + if (deathHandlers) handleDeadProcess(); diff --git a/src/startup.c b/src/startup.c index e91ce00..e920e93 100644 --- a/src/startup.c +++ b/src/startup.c @@ -379,11 +379,9 @@ void StartUp(Bool defaultScreenOnly) /* handle X shutdowns and errors via backend */ wm_backend->register_error_handlers(); - /* set hook for our event dispatcher in WINGs event dispatcher (X11 only). - * Skip for Wayland: we run a wlroots event loop, not a WINGs/X11 loop. - * dpy may be set (XWayland bridge), but X11 event dispatch is not used. */ - if (!wm_backend->is_wayland) - WMHookEventHandler(DispatchEvent); + /* set hook for our event dispatcher in WINGs event dispatcher. + * In Wayland mode, events are drained from the frame timer. */ + WMHookEventHandler(DispatchEvent); /* initialize defaults stuff */ w_global.domain.wmaker = wDefaultsInitDomain("WindowMaker", True);