This is really what the routine needs, FForEachEvent, but it digs into the X internals to get the work done. I'm not expecting this to be applied, I'm just throwing it out for food for thought. As long as fvwm is doing an exponential traversal of the events in the queue such as flush_property_notify, it is going to be very inefficient when there are lots of entries in the event queue. I guess one solution would be to pull all the events from the X event system into an fvwm data structure which could be process efficiently by FForEachEvent.
FForEachEvent allows for going through all the events in one pass optionally removing any number of events the predicate indicates. The current XCheckIfEvent is limited to removing one event per pass through the events, which is very inefficient when you get 200,000 events and you're removing just some of them one pass at a time. /* Allows each entry to be processed in the event list in one pass removing * or leaving each entry. Note, this only looks through events already * in the queue. */ void FForEachEvent( Display *display, Bool (*predicate) (Display *display, XEvent *event, XPointer arg), XPointer arg) -- David Fries <da...@fries.net> http://fries.net/~david/ (PGP encryption key available) diff --git a/fvwm/events.c b/fvwm/events.c index 88ec40b..9f44e4d 100644 --- a/fvwm/events.c +++ b/fvwm/events.c @@ -265,15 +265,22 @@ Bool test_button_event( return False; } -Bool test_typed_window_event( +/* test window, type, atom */ +Bool test_xproperty_event( Display *display, XEvent *event, XPointer arg) { - test_typed_window_event_args *ta = (test_typed_window_event_args *)arg; + test_xproperty_event_args *ta = (test_xproperty_event_args *)arg; if (event->xany.window == ta->w && - event->xany.type == ta->event_type) + event->xany.type == ta->event_type && + event->xproperty.atom == ta->atom) { + ta->count++; +#if USE_FOR_EACH + return EventRemove; +#else return True; +#endif } return False; @@ -4137,6 +4144,8 @@ int My_XNextEvent(Display *dpy, XEvent *event) DBUG( "My_XNextEvent", "taking care of queued up events" " & returning (1)"); + printf("%u events queued\n", + FEventsQueued(dpy, QueuedAlready)); FNextEvent(dpy, event); return 1; } @@ -4570,28 +4579,25 @@ int discard_window_events(Window w, long event_mask) int flush_property_notify(Atom atom, Window w) { XEvent e; - int count; - test_typed_window_event_args args; + int count = 0; + test_xproperty_event_args args; XSync(dpy, 0); args.w = w; args.event_type = PropertyNotify; - for (count = 0; - FCheckPeekIfEvent( - dpy, &e, test_typed_window_event, (XPointer)&args); - count++) - { - Bool rc; - - if (e.xproperty.atom != atom) - { - break; - } - /* remove the event from the queue */ - rc = FCheckIfEvent( - dpy, &e, test_typed_window_event, (XPointer)&args); - } - + args.atom = atom; + args.count = 0; + /* remove all events that match window, type, and atom from the queue */ + #if USE_FOR_EACH + FForEachEvent(dpy, test_xproperty_event, (XPointer)&args); + count=args.count; + #else + while (FCheckIfEvent(dpy, &e, test_xproperty_event, (XPointer)&args)) + count++; + #endif + + printf("%s flushed %d for window 0x%x atom %d\n", __FUNCTION__, + count, (int)w, (int)atom); return count; } diff --git a/fvwm/events.h b/fvwm/events.h index 80d043b..35ed6e2 100644 --- a/fvwm/events.h +++ b/fvwm/events.h @@ -15,7 +15,10 @@ typedef struct { Window w; int event_type; -} test_typed_window_event_args; + Atom atom; +/* Just for debugging */ + int count; +} test_xproperty_event_args; /* ---------------------------- forward declarations ----------------------- */ @@ -45,6 +48,6 @@ void events_handle_configure_request( XConfigureRequestEvent cre, FvwmWindow *fw, Bool force_use_grav, int force_gravity); Bool test_button_event(Display *display, XEvent *event, char *arg); -Bool test_typed_window_event(Display *display, XEvent *event, char *arg); +Bool test_xproperty_event(Display *display, XEvent *event, char *arg); #endif /* EVENTS_H */ diff --git a/libs/FEvent.c b/libs/FEvent.c index b0eda1d..75cc5a4 100644 --- a/libs/FEvent.c +++ b/libs/FEvent.c @@ -21,6 +21,7 @@ #include "config.h" #include "libs/fvwmlib.h" #include <X11/Xlib.h> +#include <X11/Xlibint.h> #include "FEvent.h" #undef FEVENT_C #undef FEVENT_PRIVILEGED_ACCESS @@ -317,6 +318,46 @@ Bool FCheckIfEvent( return rc; } +/* Allows each entry to be processed in the event list in one pass removing + * or leaving each entry. Note, this only looks through events already + * in the queue. + */ +#if USE_FOR_EACH +void FForEachEvent( + Display *display, + Bool (*predicate) (Display *display, XEvent *event, XPointer arg), + XPointer arg) +{ + struct _XDisplay *dpy=(struct _XDisplay *)display; + register _XQEvent *prev = NULL, *qelt; + int r; + + XLockDisplay(display); + for (qelt = dpy->head; qelt; prev = qelt, qelt = qelt->next) { + /* 0 leave entry, abort the scan + * 1 leave entry, continue the scan + * 2 remove current event, continue scanning + * 3 remove current event, abort + */ + r = predicate(display, &qelt->event, arg); + if(r & EventRemove) + { + _XDeq(display, prev, qelt); + /* watch out for beginning and no event conditions */ + qelt = prev ? prev : dpy->head; + if(!qelt) + break; + } + if(r & EventAbortScan) + { + break; + } + } + + XUnlockDisplay(display); +} +#endif + Bool FCheckMaskEvent( Display *display, long event_mask, XEvent *event_return) { diff --git a/libs/FEvent.h b/libs/FEvent.h index 598d9d1..a4fbef6 100644 --- a/libs/FEvent.h +++ b/libs/FEvent.h @@ -53,6 +53,21 @@ void fev_make_null_event(XEvent *ev, Display *dpy); /* return a copy of the last XEVent in *ev */ void fev_get_last_event(XEvent *ev); +/* ---------------------------- local X event improvements ----------------- */ + +#define USE_FOR_EACH 1 +#if USE_FOR_EACH +/* bit mask, return the or of the requested operations, remove (leave) + * and abort (continue) scan + */ +#define EventRemove 1 +#define EventAbortScan 2 +void FForEachEvent( + Display *display, + Bool (*predicate) (Display *display, XEvent *event, XPointer arg), + XPointer arg); +#endif + /* ---------------------------- X event replacements ----------------------- */ /* Replacements for X functions */