diff --git a/WINGs/WINGs/WINGsP.h.in b/WINGs/WINGs/WINGsP.h.in index ede002a..7ec546a 100644 --- a/WINGs/WINGs/WINGsP.h.in +++ b/WINGs/WINGs/WINGsP.h.in @@ -480,7 +480,10 @@ typedef struct W_EventBackend { extern const W_EventBackend W_EventBackendX11; extern const W_EventBackend W_EventBackendWL; +Bool W_IsValidView(struct W_View *view); + void W_WL_EnqueueEvent(struct W_Screen *scr, const WMEvent *ev, struct W_View *target); +void W_WL_InvalidateView(struct W_Screen *scr, struct W_View *target); void W_WL_SetLoopDispatch(struct W_Screen *scr, int loop_fd, void (*dispatch_fn)(int timeout_ms, void *ud), diff --git a/WINGs/wevent.c b/WINGs/wevent.c index 5a0ee87..5f98d8e 100644 --- a/WINGs/wevent.c +++ b/WINGs/wevent.c @@ -206,6 +206,9 @@ int WMHandleEvent(WMEvent * event) return False; } + if (!view->screen || view->flags.alreadyDead) /* view was destroyed between queue and dispatch */ + return True; + view->screen->lastEventTime = getEventTime(view->screen, event); toplevel = W_TopLevelOfView(view); diff --git a/WINGs/wevent_wl.c b/WINGs/wevent_wl.c index c800f4c..97fe8a1 100644 --- a/WINGs/wevent_wl.c +++ b/WINGs/wevent_wl.c @@ -67,6 +67,8 @@ wl_fetch(void *ectx, WMEvent *ev) WLQEntry *e = &ctx->buf[ctx->head]; *ev = e->ev; ev->_view_target = e->target; + if (e->target && !W_IsValidView(e->target)) + ev->_view_target = NULL; if (e->target) { W_Screen *scr = e->target->screen; if (scr) @@ -110,6 +112,8 @@ wl_check_mask(void *ectx, long mask, WMEvent *ev) unsigned long emask = wme_mask(ctx->buf[i].ev.type); if (emask & (unsigned long)mask) { *ev = ctx->buf[i].ev; + if (ev->_view_target && !W_IsValidView(ev->_view_target)) + ev->_view_target = NULL; /* Remove entry by shifting */ int next = (i + 1) % WL_EVENT_QUEUE_CAP; while (next != ctx->tail) { @@ -134,6 +138,8 @@ wl_check_typed_window(void *ectx, WNativeWindow w, int type, WMEvent *ev) if (ctx->buf[i].ev.type == type && ctx->buf[i].ev.window == w) { *ev = ctx->buf[i].ev; + if (ev->_view_target && !W_IsValidView(ev->_view_target)) + ev->_view_target = NULL; int next = (i + 1) % WL_EVENT_QUEUE_CAP; while (next != ctx->tail) { ctx->buf[i] = ctx->buf[next]; @@ -224,6 +230,21 @@ W_WL_SetLoopDispatch(W_Screen *scr, } /* Tick the Wayland compositor event loop once (used by modal loops). */ +void +W_WL_InvalidateView(W_Screen *scr, W_View *target) +{ + if (!scr || !scr->eventBackendCtx) + return; + WLEventCtx *ctx = scr->eventBackendCtx; + int i = ctx->head; + while (i != ctx->tail) { + if (ctx->buf[i].target == target) { + ctx->buf[i].target = NULL; + } + i = (i + 1) % WL_EVENT_QUEUE_CAP; + } +} + void W_WL_DispatchLoop(W_Screen *scr, int timeout_ms) { diff --git a/WINGs/wview.c b/WINGs/wview.c index f19ec6a..033359b 100644 --- a/WINGs/wview.c +++ b/WINGs/wview.c @@ -374,6 +374,8 @@ static void destroyView(W_View * view) if (view->backColor) WMReleaseColor(view->backColor); + view->screen = NULL; /* invalidate for in-flight events */ + wfree(view); } diff --git a/WINGs/wview_wl.c b/WINGs/wview_wl.c index e75965b..5c08eea 100644 --- a/WINGs/wview_wl.c +++ b/WINGs/wview_wl.c @@ -91,6 +91,20 @@ static void view_table_remove(Window id) } } +Bool W_IsValidView(W_View *view) +{ + if (!view) return False; + unsigned idx = ((unsigned)view->window) % VIEW_TABLE_SIZE; + for (int i = 0; i < VIEW_TABLE_SIZE; i++) { + unsigned slot = (idx + i) % VIEW_TABLE_SIZE; + if (view_table[slot].view == view) + return True; + if (view_table[slot].id == 0) + return False; + } + return False; +} + /* * W_RegisterBacking - register a pixman_image_t backing for any synthetic * window ID (WINGs views OR WM frame_buf windows). Used by wl_backend.c so @@ -231,7 +245,7 @@ static void wl_noop_reparent(void *vctx, W_View *view, W_View *newParent, int x, static void wl_destroy(void *vctx, W_View *view) { (void)vctx; - (void)view; + W_WL_InvalidateView(view->screen, view); /* Nothing to free — synthetic ID only */ }