The attached patch should fix the problems.  For some reason my CVS
connection hangs forever, so I cannot apply the patch myself.  :-/

Ciao

Dominik ^_^  ^_^

-- 

Dominik Vogt
>From d36cc99975d99dae7305ae49b8d1d19aab82028d Mon Sep 17 00:00:00 2001
From: Dominik Vogt <dominik.v...@gmx.de>
Date: Thu, 19 Dec 2013 01:23:41 +0100
Subject: [PATCH] * Fix removal of bindings.

---
 ChangeLog           |   16 +++++++++
 NEWS                |    3 ++
 fvwm/bindings.c     |   38 +++++++++------------
 fvwm/menubindings.c |    3 +-
 libs/Bindings.c     |   93 +++++++++++++++++++++++++++++++++------------------
 libs/Bindings.h     |   10 +++---
 6 files changed, 102 insertions(+), 61 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 03c3c9d..f82f854 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2013-12-19  Dominik Vogt  <dominik(dot)vogt(at)gmx(dot)de>
+
+	* fvwm/menubindings.c (menu_binding):
+	Use new signature of CollectBindingList
+	* fvwm/bindings.c (ParseBinding):
+	Cleaned up some code
+	Do not remove window specific bindings that are still needed for other
+	windows.
+	* libs/Bindings.h (CollectBindingList):
+	Added ret_are_similar_bindings_left
+	* libs/Bindings.c (CollectBindingList):
+	indicates whether similar bindings are left, i.e. bindings that differ
+	in window name only
+	(replacesBinding, compare_bindings):
+	Renamed function, returns 2 if bindings only differ in window name
+
 2013-11-09  Dan Espen  <despen(at)1verizon.net>
 
 	* fvwm/events.c (HandlePropertyNotify): Disable prior fix suspected of causing
diff --git a/NEWS b/NEWS
index 8e36864..7a7500c 100644
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,9 @@ Changes in release 2.6.6 (not released yet)
   - Windows no longer jump from one position to the other which
     could happen in some cases with SnapAttraction.  Windows now
     snap to the closest window (or screen edge).
+  - Removing bindings had several strange side effects that are
+    fixed now (removing too many bindings; old bindings showing up
+    again after another is removed; possibly other effects).
 
 -------------------------------------------------------------------
 Changes in release 2.6.5 (20-Apr-2012)
diff --git a/fvwm/bindings.c b/fvwm/bindings.c
index 4cde680..c1aa6af 100644
--- a/fvwm/bindings.c
+++ b/fvwm/bindings.c
@@ -262,7 +262,7 @@ static int ParseBinding(
 	KeySym keysym = NoSymbol;
 	Bool is_unbind_request = False;
 	Bool is_pass_through = False;
-	Bool is_binding_removed = False;
+	Bool are_similar_bindings_left;
 	Binding *b;
 	Binding *rmlist = NULL;
 	STROKE_CODE(char stroke[STROKE_MAX_SEQUENCE + 1] = "");
@@ -477,15 +477,17 @@ static int ParseBinding(
 		}
 	}
 
-	/*
-	** strip leading whitespace from action if necessary
-	*/
-	while (*action && (*action == ' ' || *action == '\t'))
+	if (action != NULL)
 	{
-		action++;
+		action = SkipSpaces(action, NULL, 0);
 	}
-
-	if (action)
+	if (
+		action == NULL || *action == 0 ||
+		(action[0] == '-' && !is_pass_through))
+	{
+		is_unbind_request = True;
+	}
+	else
 	{
 		is_pass_through = is_pass_through_action(action);
 		if (is_pass_through)
@@ -508,11 +510,6 @@ static int ParseBinding(
 			}
 		}
 	}
-	/* see if it is an unbind request */
-	if (!action || (action[0] == '-' && !is_pass_through))
-	{
-		is_unbind_request = True;
-	}
 
 	/* short circuit menu bindings for now. */
 	if ((context & C_MENU) == C_MENU)
@@ -540,17 +537,17 @@ static int ParseBinding(
 	*/
 	/* BEGIN remove */
 	CollectBindingList(
-		dpy, pblist, &rmlist, type, STROKE_ARG((void *)stroke)
+		dpy, pblist, &rmlist, &are_similar_bindings_left, type,
+		STROKE_ARG((void *)stroke)
 		button, keysym, modifier, context, window_name);
 	if (rmlist != NULL)
 	{
-		is_binding_removed = True;
-		if (is_unbind_request)
+		int bcontext;
+
+		if (is_unbind_request && are_similar_bindings_left == False)
 		{
 			int rc = 0;
 
-			/* remove the grabs for the key for unbind
-			 * requests */
 			for (b = rmlist; b != NULL; b = b->NextBinding)
 			{
 				/* release the grab */
@@ -563,11 +560,6 @@ static int ParseBinding(
 			}
 		}
 		FreeBindingList(rmlist);
-	}
-	if (is_binding_removed)
-	{
-		int bcontext;
-
 		bcontext = bind_get_bound_button_contexts(
 			pblist, buttons_grabbed);
 		update_nr_buttons(
diff --git a/fvwm/menubindings.c b/fvwm/menubindings.c
index c45c449..3b422c2 100644
--- a/fvwm/menubindings.c
+++ b/fvwm/menubindings.c
@@ -402,6 +402,7 @@ int menu_binding(
 {
 	Binding *rmlist;
 	int rc;
+	Bool dummy;
 
 	if (menu_bindings == NULL)
 	{
@@ -430,7 +431,7 @@ int menu_binding(
 	 */
 	/* BEGIN remove */
 	CollectBindingList(
-		dpy, menu_bindings, &rmlist, type, STROKE_ARG(NULL)
+		dpy, menu_bindings, &rmlist, &dummy, type, STROKE_ARG(NULL)
 		button, keysym, modifier, context, menu_style);
 	if (rmlist != NULL)
 	{
diff --git a/libs/Bindings.c b/libs/Bindings.c
index d7f76e6..ab2fb08 100644
--- a/libs/Bindings.c
+++ b/libs/Bindings.c
@@ -269,27 +269,28 @@ int AddBinding(
 	return count;
 }
 
-/*
- * replacesBinding() - does the new binding, b1, replace a current
- * binding, b2?
+/* returns 1 if binding b1 is identical to binding b2 (except action)
+ * returns 2 if b1 and b2 are identical except that b1 has a different window
+ * name than b2 and both are not NULL
+ * returns 0 otherwise
  */
-static Bool replacesBinding(Binding *b1, Binding *b2)
+static int compare_bindings(Binding *b1, Binding *b2)
 {
 	if (b1->type != b2->type)
 	{
-		return False;
+		return 0;
 	}
 	if (b1->Context != b2->Context)
 	{
-		return False;
+		return 0;
 	}
 	if (b1->Modifier != b2->Modifier)
 	{
-		return False;
+		return 0;
 	}
 	if (b1->Button_Key != b2->Button_Key)
 	{
-		return False;
+		return 0;
 	}
 
 	/* definition: "global binding" => b->windowName == NULL
@@ -300,26 +301,28 @@ static Bool replacesBinding(Binding *b1, Binding *b2)
 		/* Both bindings are window-specific. The existing binding, b2,
 		 * is only replaced (by b1) if it applies to the same window */
 		if (strcmp(b1->windowName, b2->windowName) != 0)
-			return False;
+		{
+			return 2;
+		}
 	}
 	else if (b1->windowName || b2->windowName)
 	{
 		/* 1 binding is window-specific, the other is global - no need
 		 * to replace this binding. */
-		return False;
+		return 0;
 	}
 
 	if (BIND_IS_KEY_BINDING(b1->type) || BIND_IS_MOUSE_BINDING(b1->type))
 	{
-		return True;
+		return 1;
 	}
 	if (1 STROKE_CODE(&& BIND_IS_STROKE_BINDING(b1->type) &&
 			  strcmp(b1->Stroke_Seq, b2->Stroke_Seq) == 0))
 	{
-		return True;
+		return 1;
 	}
 
-	return False;
+	return 0;
 }
 
 /*
@@ -330,16 +333,15 @@ static Bool replacesBinding(Binding *b1, Binding *b2)
  */
 void CollectBindingList(
 	Display *dpy, Binding **pblist_src, Binding **pblist_dest,
-	binding_t type, STROKE_ARG(void *stroke)
-	int button, KeySym keysym, int modifiers, int contexts,
-	char *windowName)
+	Bool *ret_are_similar_bindings_left, binding_t type,
+	STROKE_ARG(void *stroke) int button, KeySym keysym,
+	int modifiers, int contexts, char *windowName)
 {
 	Binding *tmplist = NULL;
-	Binding *btmp;
 	Binding *bold;
-	Binding *tmpprev;
 	Binding *oldprev;
 
+	*ret_are_similar_bindings_left = False;
 	/* generate a private list of bindings to be removed */
 	AddBinding(
 		dpy, &tmplist, type, STROKE_ARG(stroke)
@@ -347,26 +349,51 @@ void CollectBindingList(
 		windowName);
 	/* now find equivalent bindings in the given binding list and move
 	 * them to the new clist */
-	for (bold = *pblist_src, oldprev = NULL; bold != NULL;
-	     oldprev = bold, bold = bold->NextBinding)
+	for (bold = *pblist_src, oldprev = NULL; bold != NULL; )
 	{
-		for (btmp = tmplist, tmpprev = NULL; btmp != NULL;
-		     tmpprev = btmp, btmp = btmp->NextBinding)
+		Binding *btmp;
+		Binding *bfound;
+
+		bfound = NULL;
+		for (btmp = tmplist;
+		     btmp != NULL && (
+			     bfound == NULL ||
+			     *ret_are_similar_bindings_left == False);
+		     btmp = btmp->NextBinding)
 		{
-			if (replacesBinding(btmp, bold))
+			int rc;
+
+			rc = compare_bindings(btmp, bold);
+			if (rc == 1)
 			{
-				/* move matched binding from src list to dest
-				 * list */
-				UnlinkBinding(pblist_src, bold, oldprev);
-				bold->NextBinding = *pblist_dest;
-				*pblist_dest = bold;
-				/* throw away the tmp binding */
-				UnlinkBinding(&tmplist, btmp, tmpprev);
-				FreeBindingStruct(btmp);
-				/* stop searching for this binding */
-				break;
+				bfound = btmp;
+			}
+			else if (rc == 2)
+			{
+				*ret_are_similar_bindings_left = True;
+				if (bfound != NULL)
+				{
+					break;
+				}
 			}
 		}
+		if (bfound != NULL)
+		{
+			Binding *next;
+
+			/* move matched binding from src list to dest list */
+			UnlinkBinding(pblist_src, bold, oldprev);
+			next = bold->NextBinding;
+			bold->NextBinding = *pblist_dest;
+			*pblist_dest = bold;
+			/* oldprev is unchanged */
+			bold = next;
+		}
+		else
+		{
+			oldprev = bold;
+			bold = bold->NextBinding;
+		}
 	}
 	/* throw away the temporary list */
 	FreeBindingList(tmplist);
diff --git a/libs/Bindings.h b/libs/Bindings.h
index 7269933..1ae2600 100644
--- a/libs/Bindings.h
+++ b/libs/Bindings.h
@@ -40,8 +40,8 @@ typedef struct Binding
 	int Modifier;           /* Modifiers for keyboard state */
 	void *Action;           /* What to do? */
 	void *Action2;          /* This one can be used too */
-	char *windowName;		/* Name of window (regex pattern) this binding
-							   applies to. NULL means all windows. */
+	char *windowName;	/* Name of window (regex pattern) this binding
+				   applies to. NULL means all windows. */
 	struct Binding *NextBinding;
 } Binding;
 
@@ -49,12 +49,14 @@ typedef struct Binding
 
 void CollectBindingList(
 	Display *dpy, Binding **pblist_src, Binding **pblist_dest,
-	binding_t type, STROKE_ARG(void *stroke) int button, KeySym keysym,
+	Bool *ret_are_similar_bindings_left, binding_t type,
+	STROKE_ARG(void *stroke) int button, KeySym keysym,
 	int modifiers, int contexts, char *windowName);
 int AddBinding(
 	Display *dpy, Binding **pblist, binding_t type,
 	STROKE_ARG(void *stroke) int button, KeySym keysym, char *key_name,
-	int modifiers, int contexts, void *action, void *action2, char *windowName);
+	int modifiers, int contexts, void *action, void *action2,
+	char *windowName);
 void FreeBindingStruct(Binding *b);
 void FreeBindingList(Binding *b);
 void RemoveBinding(Binding **pblist, Binding *b, Binding *prev);
-- 
1.7.10.4

Reply via email to