From 58cc099368de9b0dd8bf5d2daa0f31d5c373f812 Mon Sep 17 00:00:00 2001 From: Thomas Adam Date: Tue, 2 May 2023 16:53:10 +0100 Subject: [PATCH] debian bug 1034054: backport fvwm3 xthreadlock() Backport this fix from fvwm3 to fvwm2: https://github.com/fvwmorg/fvwm3/commit/5c17c83df4605d2d97999740cf180af983298896 XCheckIfEvent() holds the X display lock and the predicate function it calls is not allowed to call any Xlib function that would re-enter the lock. libX11 1.8.1 enables X display locks unconditionnaly (it was only enabled by XInitThreads() when called explicitely before) and thus exposes the issue. So don't process events in the FCheckPeekIfEvent() predicate, but instead use a separate handler that is called for the returned event out of the lock. --- fvwm/events.c | 9 ++++++++- libs/FEvent.c | 22 ++++++++++++++++++++++ libs/FEvent.h | 8 ++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/fvwm/events.c b/fvwm/events.c index a2d024068..7a3d06c3b 100644 --- fvwm/events.c +++ fvwm/events.c @@ -258,6 +258,12 @@ static int _pred_weed_accumulate_expose( return 1; } +static int _pred_weed_is_expose( + Display *display, XEvent *event, XPointer arg) +{ + return (event->type == Expose); +} + static int _pred_weed_handle_expose( Display *display, XEvent *event, XPointer arg) { @@ -4542,7 +4548,8 @@ void handle_all_expose(void) saved_event = fev_save_event(); FPending(dpy); - FWeedIfEvents(dpy, _pred_weed_handle_expose, NULL); + FWeedAndHandleIfEvents(dpy, _pred_weed_is_expose, + _pred_weed_handle_expose, NULL); fev_restore_event(saved_event); return; diff --git a/libs/FEvent.c b/libs/FEvent.c index 24d019dd1..ec31728a9 100644 --- libs/FEvent.c +++ libs/FEvent.c @@ -532,6 +532,28 @@ int FWeedIfEvents( return weed_args.count; } +int FWeedAndHandleIfEvents( + Display *display, + int (*weed_predicate) (Display *display, XEvent *event, XPointer arg), + int (*handler) (Display *display, XEvent *event, XPointer arg), + XPointer arg) +{ + _fev_weed_args weed_args; + XEvent e; + + assert(fev_is_invalid_event_type_set); + memset(&weed_args, 0, sizeof(weed_args)); + weed_args.weed_predicate = weed_predicate; + weed_args.arg = arg; + if (FCheckPeekIfEvent(display, &e, _fev_pred_weed_if, + (XPointer)&weed_args)) { + handler(display, &e, arg); + } + _fev_pred_weed_if_finish(&weed_args); + + return weed_args.count; +} + int FWeedIfWindowEvents( Display *display, Window window, int (*weed_predicate) ( diff --git a/libs/FEvent.h b/libs/FEvent.h index 821aef51a..2622f4474 100644 --- libs/FEvent.h +++ libs/FEvent.h @@ -113,6 +113,14 @@ int FWeedIfEvents( Display *display, XEvent *current_event, XPointer arg), XPointer arg); +/* Same as FWeedIfEvents but with a second callback out of XLockDisplay() + * to handle events in a lock-safe manner */ +int FWeedAndHandleIfEvents( + Display *display, + int (*weed_predicate) (Display *display, XEvent *event, XPointer arg), + int (*handler) (Display *display, XEvent *event, XPointer arg), + XPointer arg); + /* Same as FWeedIfEvents but weeds only events for the given window. The * weed_predicate is only called for events with a matching window. */ int FWeedIfWindowEvents(