Skip to content

Commit

Permalink
Fix for lock recusion in handle_all_expose()
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mherrb authored and ThomasAdam committed Aug 8, 2022
1 parent 4d646ca commit 5c17c83
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 1 deletion.
9 changes: 8 additions & 1 deletion fvwm/events.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,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)
{
Expand Down Expand Up @@ -4546,7 +4552,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;
Expand Down
22 changes: 22 additions & 0 deletions libs/FEvent.c
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,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) (
Expand Down
8 changes: 8 additions & 0 deletions libs/FEvent.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,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(
Expand Down

0 comments on commit 5c17c83

Please sign in to comment.