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

Reply via email to