I think I know hwat's happening and have committed a patch to cvs: When HandlePropertyNotify calls flush_property_notify, normally the queue is short, and the events it looks for are near the beginning. So it looks through the queue until it finds such an event, then removes it and restarts until no more events of that kind are in the queue. There is no way to weed out all unwanted events in one pass because Xlib gives us no direct access to the queue, and the interface functions do not allow direct access.
But now we have a queue that looks like this PropertyNotify(atom a) PropertyNotify(atom b) PropertyNotify(atom c) PropertyNotify(atom d) PropertyNotify(atom a) PropertyNotify(atom b) PropertyNotify(atom c) PropertyNotify(atom d) ... (repeat ad nauseum) So, HandlePropertyNotify() is called with the atom a and wants to flush the queue. So it skips the next three events, finds a matching one, removes it and starts over. The next matching event is now at position 7, the next ones at 10, 13, 16 and so on. On each pass it has to start at the beginning, so we have O(n^2) run time behaviour. This wouldn't happen if there was only *one* type of atom on the queue. Then each pass would just remove the first event. But the application here does something very difficult to handle. The patched code does the following: 1. Each handler for the atoms first calls the new function check_for_another_property_notify() (flush_property_notify is gone). That function first removes all events of the matching kind and removes them. Then it looks for a matching event in the remaining 200 events at the start of the queue (200 minus number of already removed event, that is). Then it returns and indicates to the caller whether it found such an event or not. If so, the calling PN atom handler just returns, leaves the events on the queue and lets later events determine what has to be done, i.e. it simply returns. 2. Call XGetGeometry only *after* flushing the queue to speed up the handler in case it does just weeds out events. The same problem also affects other events, but I have no patch for them at the moment. Can you please try out the latest cvs code wogether with the debug patch attached to this message? I need to see some stretch of the log again (only the part with the ..._NAME atoms, the rest is irrelevant). Ciao Dominik ^_^ ^_^ -- Dominik Vogt
>From 39f9db34c6c16c03fef46d27b0604011d0012124 Mon Sep 17 00:00:00 2001 From: Dominik Vogt <[email protected]> Date: Mon, 15 Sep 2014 18:47:47 +0100 Subject: [PATCH] !!!debug --- fvwm/events.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/fvwm/events.c b/fvwm/events.c index 8ccabc6..b14f9ae 100644 --- a/fvwm/events.c +++ b/fvwm/events.c @@ -3259,6 +3259,14 @@ void HandlePropertyNotify(const evh_args_t *ea) DBUG("HandlePropertyNotify", "Routine Entered"); +#if 1 /*!!!*/ + { + char *name; + + name = XGetAtomName(dpy, te->xproperty.atom); + fprintf(stderr, "%s: send_event %d, window 0x%lx, atom %lx '%s', time %ld, state %d\n", __func__, (int)te->xproperty.send_event, te->xproperty.window, te->xproperty.atom, name ? name : "(nil)", (long)te->xproperty.time, te->xproperty.state); + } +#endif if (te->xproperty.window == Scr.Root && te->xproperty.state == PropertyNewValue && (te->xproperty.atom == _XA_XSETROOT_ID || @@ -3275,6 +3283,9 @@ void HandlePropertyNotify(const evh_args_t *ea) /* update icon window with some alpha and tear-off menu */ FvwmWindow *t; +#if 1 /*!!!*/ +fprintf(stderr, "background change\n"); +#endif for (t = Scr.FvwmRoot.next; t != NULL; t = t->next) { int cs; @@ -3343,12 +3354,18 @@ void HandlePropertyNotify(const evh_args_t *ea) if (!fw) { +#if 1 /*!!!*/ +fprintf(stderr, "no fw\n"); +#endif return; } switch (te->xproperty.atom) { case XA_WM_TRANSIENT_FOR: { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_TRANSIENT_FOR\n"); +#endif if (setup_transientfor(fw) == True) { RaiseWindow(fw, False); @@ -3357,6 +3374,9 @@ void HandlePropertyNotify(const evh_args_t *ea) } case XA_WM_NAME: { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_NAME\n"); +#endif int n; int pos; @@ -3380,26 +3400,41 @@ void HandlePropertyNotify(const evh_args_t *ea) } if (HAS_EWMH_WM_NAME(fw)) { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_NAME A\n"); +#endif return; } FlocaleGetNameProperty(XGetWMName, dpy, FW_W(fw), &new_name); if (new_name.name == NULL) { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_NAME B\n"); +#endif FlocaleFreeNameProperty(&new_name); return; } if (strlen(new_name.name) > MAX_WINDOW_NAME_LEN) { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_NAME C\n"); +#endif /* limit to prevent hanging X server */ (new_name.name)[MAX_WINDOW_NAME_LEN] = 0; } if (fw->name.name && strcmp(new_name.name, fw->name.name) == 0) { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_NAME D\n"); +#endif /* migo: some apps update their names every second */ /* griph: make sure we don't free the property if it is THE same name */ if (new_name.name != fw->name.name) { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_NAME E\n"); +#endif FlocaleFreeNameProperty(&new_name); } return; @@ -3410,6 +3445,9 @@ void HandlePropertyNotify(const evh_args_t *ea) SET_NAME_CHANGED(fw, 1); if (fw->name.name == NULL) { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_NAME F\n"); +#endif fw->name.name = NoName; /* must not happen */ } setup_visible_name(fw, False); @@ -3418,6 +3456,9 @@ void HandlePropertyNotify(const evh_args_t *ea) /* fix the name in the title bar */ if (!IS_ICONIFIED(fw)) { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_NAME G\n"); +#endif border_draw_decorations( fw, PART_TITLE, (Scr.Hilite == fw), True, CLEAR_ALL, NULL, NULL); @@ -3437,16 +3478,26 @@ void HandlePropertyNotify(const evh_args_t *ea) #endif ) { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_NAME H\n"); +#endif fw->icon_name = fw->name; setup_visible_name(fw, True); BroadcastWindowIconNames(fw, False, True); RedoIconName(fw); } +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_NAME I\n"); +#endif break; } case XA_WM_ICON_NAME: { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_ICON_NAME\n"); +#endif int n; + int pos; pos = check_for_another_property_notify( @@ -3469,28 +3520,43 @@ void HandlePropertyNotify(const evh_args_t *ea) } if (HAS_EWMH_WM_ICON_NAME(fw)) { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_ICON_NAME A\n"); +#endif return; } FlocaleGetNameProperty( XGetWMIconName, dpy, FW_W(fw), &new_name); if (new_name.name == NULL) { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_ICON_NAME B\n"); +#endif FlocaleFreeNameProperty(&new_name); return; } if (new_name.name && strlen(new_name.name) > MAX_ICON_NAME_LEN) { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_ICON_NAME C\n"); +#endif /* limit to prevent hanging X server */ (new_name.name)[MAX_ICON_NAME_LEN] = 0; } if (fw->icon_name.name && strcmp(new_name.name, fw->icon_name.name) == 0) { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_ICON_NAME D\n"); +#endif /* migo: some apps update their names every second */ /* griph: make sure we don't free the property if it is THE same name */ if (new_name.name != fw->icon_name.name) { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_ICON_NAME E\n"); +#endif FlocaleFreeNameProperty(&new_name); } return; @@ -3501,6 +3567,9 @@ void HandlePropertyNotify(const evh_args_t *ea) SET_WAS_ICON_NAME_PROVIDED(fw, 1); if (fw->icon_name.name == NULL) { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_ICON_NAME F\n"); +#endif /* currently never happens */ fw->icon_name.name = fw->name.name; SET_WAS_ICON_NAME_PROVIDED(fw, 0); @@ -3509,10 +3578,16 @@ void HandlePropertyNotify(const evh_args_t *ea) BroadcastWindowIconNames(fw, False, True); RedoIconName(fw); EWMH_SetVisibleName(fw, True); +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_ICON_NAME G\n"); +#endif break; } case XA_WM_HINTS: { +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_HINTS \n"); +#endif int n; int pos; @@ -3682,6 +3757,9 @@ ICON_DBG((stderr, "hpn: icon changed '%s'\n", fw->name.name)); break; } case XA_WM_NORMAL_HINTS: +#if 1 /*!!!*/ +fprintf(stderr, "XA_WM_NORMAL_HINTS \n"); +#endif /* just mark wm normal hints as changed and look them up when * the next ConfigureRequest w/ x, y, width or height set * arrives. */ @@ -3701,10 +3779,16 @@ ICON_DBG((stderr, "hpn: icon changed '%s'\n", fw->name.name)); default: if (te->xproperty.atom == _XA_WM_PROTOCOLS) { +#if 1 /*!!!*/ +fprintf(stderr, "_XA_WM_PROTOCOLS \n"); +#endif FetchWmProtocols (fw); } else if (te->xproperty.atom == _XA_WM_COLORMAP_WINDOWS) { +#if 1 /*!!!*/ +fprintf(stderr, "_XA_WM_COLORMAP_WINDOWS\n"); +#endif FetchWmColormapWindows (fw); /* frees old data */ ReInstallActiveColormap(); } @@ -3716,6 +3800,9 @@ ICON_DBG((stderr, "hpn: icon changed '%s'\n", fw->name.name)); */ Bool is_on_this_page; +#if 1 /*!!!*/ +fprintf(stderr, "_XA_WM_STATE\n"); +#endif is_on_this_page = IsRectangleOnThisPage( &(fw->g.frame), fw->Desk); if (fw && is_on_this_page == True && @@ -3728,6 +3815,9 @@ ICON_DBG((stderr, "hpn: icon changed '%s'\n", fw->name.name)); } else { +#if 1 /*!!!*/ +fprintf(stderr, "EWMH property notify?\n"); +#endif EWMH_ProcessPropertyNotify(ea->exc); } break; @@ -4235,6 +4325,9 @@ void dispatch_event(XEvent *e) ea.exc = exc_create_context( &ecc, ECC_TYPE | ECC_ETRIGGER | ECC_FW | ECC_W | ECC_WCONTEXT); +#if 1 /*!!!*/ + fprintf(stderr, "%s: event %d\n", __func__, e->type); +#endif (*event_group->jump_table[e->type - event_group->base])(&ea); exc_destroy_context(ea.exc); } @@ -4789,6 +4882,15 @@ int check_for_another_property_notify( break; } } +#if 1 /*!!!*/ + { + char *name; + + name = XGetAtomName(dpy, atom); + fprintf(stderr, "%s: flushed %d duplicate PropertyNotify of atom %ld '%s'\n", __func__, *num_events_removed, atom, name ? name : "(nil)"); + } + fprintf(stderr, "%s: pos %d\n", __func__, pos); +#endif return pos; } -- 1.7.10.4
