Subject: Re: Patch to allow multiple window names in conditions

From: Mikhael Goikhman <[email-masked]>
Date: Tue, 6 Jul 2004 21:42:28 +0000

On 31 May 2004 21:53:51 -0400, Norman Yarvin wrote:
> 
> This is a small patch that allows multiple window names to be specified
> in conditions.  I've tried to write it with the same style used in the
> rest of the code, although some variable names may be a bit terse by your
> standards.  The patch keeps the window names in a linked list.  It
> includes updates to the man page and ChangeLog.  The patch is against the
> current CVS code.  What exactly it does is best described by the modified
> portion of the man page:
> 
[...]
> 
>        Examples:
> 
>                  Next (Netscape konqueror Mozilla*) WarpToWindow 99 90
> 
>        This  goes to the next web browser window, no matter which of
>        the three named web browsers is being used.

Like other posters, I don't quite like that names are sudently work
using logical OR while all other options in conditional commands work
using logical AND. And the nagations of names work using AND again.

Here is the proposal that should solve all these ambiguities, but it is
a bit backward incompatible in that one character is treated specially.
I don't think there is any fvwm user that has a conditional in his config
that will be broken however, so this is mostly the theoretical problem.

1) All condition options always work using logical AND, as usual.
2) Any option is either keyword or window name/resource/class, as usual.
3) Options (with possible argument) are separated by commas, as usual.
4) In the future we will have (Name "name1", Class "name2") syntax.
5) The leading character "!" means logical NOT of that option, as usual.
6) Any name may contain a spacial character "|" meaning logical OR.

Here are examples:

  Next ("Netscape|konqueror|Mozilla*") WarpToWindow 99 90  # go to browser

  All (CurrentPage, "xterm|rvxt", !Iconified) Iconify  # iconify terminals

  Next (!"FvwmPager|FvwmForm*|FvwmButtons") Raise  # raise next non-module

  Next (!FvwmPager, !FvwmForm*, !FvwmButtons) Raise

The last 2 commands are equivalent. So basically, we don't really need
to support more than one name options like in the last example. I am
not against to add such extended support though.

I think this syntax naturally extends the current syntax and allows most
of the logical expressions a user may want to have. This can't be said
about the original proposed syntax.

Regards,
Mikhael.
--
Visit the official FVWM web page at <URL:http://www.fvwm.org/>.
To unsubscribe from the list, send "unsubscribe fvwm-workers" in the
body of a message to [email-masked].
To report problems, send mail to [email-masked]

---

From: Norman Yarvin <[email-masked]>
Date: Sat, 10 Jul 2004 13:55:46 -0400

>about the original proposed syntax.

Thanks for the proposal.  I was contemplating adding full boolean
expressions, but looking at the code, that gets a bit complicated if
backwards compatibility is to be preserved.  The code change required by
your proposal is not much bigger than my original patch; and it doesn't
have the user interface weirdness that mine did.  So I implemented it.
Here's the patch:

Index: ChangeLog
===================================================================
RCS file: /home/cvs/fvwm/fvwm/ChangeLog,v
retrieving revision 1.2518
diff -u -u -r1.2518 ChangeLog
--- ChangeLog	10 Jul 2004 09:13:25 -0000	1.2518
+++ ChangeLog	10 Jul 2004 17:47:13 -0000
@@ -1,3 +1,11 @@
+2004-07-10  Norman Yarvin  <[email-masked]>
+
+	* fvwm/conditional.c:
+	* fvwm/fvwm.h:
+	* fvwm/fvwm.1.in:
+	modified the code for conditions so that multiple window names may
+	be specified in each condition
+
 2004-07-09  Dominik Vogt  <[email-masked]>
 
 	* fvwm/module_interface.c (CONFIGARGS):
Index: fvwm/conditional.c
===================================================================
RCS file: /home/cvs/fvwm/fvwm/fvwm/conditional.c,v
retrieving revision 1.95
diff -u -u -r1.95 conditional.c
--- fvwm/conditional.c	8 Jul 2004 10:08:09 -0000	1.95
+++ fvwm/conditional.c	10 Jul 2004 17:47:14 -0000
@@ -376,22 +376,31 @@
 }
 
 /*
- * The name field of the mask is allocated in CreateConditionMask.
+ * The name_condition field of the mask is allocated in CreateConditionMask.
  * It must be freed.
  * NOTE - exported via .h
  */
 void FreeConditionMask(WindowConditionMask *mask)
 {
-	if (mask->my_flags.needs_name)
-	{
-		free(mask->name);
-	}
-	else if (mask->my_flags.needs_not_name)
+	struct name_condition *pp,*pp2;
+	struct namelist *p,*p2;
+
+	for (pp=mask->name_condition; pp; )
 	{
-		free(mask->name - 1);
+		for (p=pp->namelist; p; )
+		{
+			p2=p->next;
+			if(!p2)
+			{
+				free(p->name - (pp->invert ? 1 : 0));
+			}
+			free(p);
+			p=p2;
+		}
+		pp2=pp->next;
+		free(pp);
+		pp=pp2;
 	}
-
-	return;
 }
 
 /* Assign the default values for the window mask
@@ -614,21 +623,36 @@
 			}
 			mask->my_flags.needs_same_layer = on;
 		}
-		else if (!mask->my_flags.needs_name &&
-			 !mask->my_flags.needs_not_name)
-		{
-			/* only 1st name to avoid mem leak */
-			mask->name = condition;
-			condition = NULL;
-			if (on == 0)
-			{
-				mask->my_flags.needs_not_name = 1;
-				mask->name++;
-			}
-			else
-			{
-				mask->my_flags.needs_name = 1;
+		else
+		{ 
+			struct name_condition *pp;
+			struct namelist *p;
+			char *condp;
+
+			pp = (struct name_condition *)
+				safemalloc(sizeof(struct name_condition));
+			pp->invert = !on;
+			pp->namelist = NULL;
+			pp->next = mask->name_condition;
+			mask->name_condition = pp;
+			for(condp=cond; ; )
+			{
+				p = (struct namelist *)
+					safemalloc(sizeof(struct namelist));
+				p->name=condp;
+				p->next=pp->namelist;
+				pp->namelist=p;
+				while(*condp && *condp != '|')
+				{
+					condp++;
+				}
+				if(!*condp)
+				{
+					break;
+				}
+				*condp++='\0';
 			}
+			condition = NULL; 	/* so it won't be freed */
 		}
 
 		if (prev_condition)
@@ -654,15 +678,14 @@
  */
 Bool MatchesConditionMask(FvwmWindow *fw, WindowConditionMask *mask)
 {
-	int does_name_match;
-	int does_icon_name_match;
-	int does_class_match;
-	int does_resource_match;
 	int does_match;
 	int is_on_desk;
 	int is_on_page;
 	int is_on_global_page;
 	FvwmWindow *sf = get_focus_window();
+	struct name_condition *pp;
+	struct namelist *p;
+	char *name;
 
 	/* match FixedSize conditional */
 	/* special treatment for FixedSize, because more than just
@@ -822,27 +845,28 @@
 		}
 	}
 
-	/* Yes, I know this could be shorter, but it's hard to understand then
-	 */
-	does_name_match = matchWildcards(mask->name, fw->name.name);
-	does_icon_name_match = matchWildcards(mask->name, fw->icon_name.name);
-	does_class_match =
-		(fw->class.res_class && matchWildcards(
-			mask->name,fw->class.res_class));
-	does_resource_match =
-		(fw->class.res_name && matchWildcards(
-			mask->name, fw->class.res_name));
-	does_match =
-		(does_name_match || does_icon_name_match || does_class_match ||
-		 does_resource_match);
-	if (mask->my_flags.needs_name && !does_match)
-	{
-		return False;
-	}
-	if (mask->my_flags.needs_not_name && does_match)
+	for(pp=mask->name_condition; pp; pp=pp->next)
 	{
-		return False;
-	}
+		does_match = 0;
+		for(p=pp->namelist; p; p=p->next)
+		{
+			name=p->name;
+			does_match |= matchWildcards(name, fw->name.name);
+			does_match |= matchWildcards(name, fw->icon_name.name);
+			if(fw->class.res_class)
+				does_match |= matchWildcards(name,
+							fw->class.res_class);
+			if(fw->class.res_name)
+				does_match |= matchWildcards(name,
+							fw->class.res_name);
+		}
+		if(( pp->invert &&  does_match) ||
+		   (!pp->invert && !does_match))
+		{
+			return False;
+		}
+	} 
+		
 	if (mask->layer == -1 && sf)
 	{
 		int is_same_layer;
Index: fvwm/fvwm.1.in
===================================================================
RCS file: /home/cvs/fvwm/fvwm/fvwm/fvwm.1.in,v
retrieving revision 1.143
diff -u -u -r1.143 fvwm.1.in
--- fvwm/fvwm.1.in	6 Jul 2004 13:05:04 -0000	1.143
+++ fvwm/fvwm.1.in	10 Jul 2004 17:47:28 -0000
@@ -10384,12 +10384,42 @@
 
 In addition, the
 .I conditions
-may include one window name to match to.  The window name may
-include the wildcards '*' and '?'.  The window name, icon name,
-class, and resource are considered when attempting to find a
-match.  The window name can begin with '!' which prevents
+may include one or more window names to match to.  If more than one
+window name is given, all of them must match.  The window name, icon
+name, class, and resource are considered when attempting to find a match.
+Each name may include the wildcards '*' and '?', and may consist
+of two or more alternatives, separated by the character '|', which acts
+as an OR operator.  (If OR operators are used, they must not be separated
+by spaces from the names.)  Each window name can begin with '!', which prevents
 .I command
-if any of the window name, icon name, class or resource match.
+if any of the window name, icon name, class or resource match.  However,
+'!' must not be applied to individual names in a group separated by OR
+operators; it may only be applied to the beginning of the group, and
+then it operates on the whole group.
+
+Examples:
+.EX
+ Next ("Netscape|konqueror|Mozilla*") WarpToWindow 99 90
+.EE
+This goes to the next web browser window, no matter which of the three
+named web browsers is being used.
+.EX
+ Next ("Mozilla*" "Bookmark*") WarpToWindow 99 90
+.EE
+This goes to Mozilla's bookmark manager window, ignoring other Mozilla
+windows and other browsers' bookmark windows.
+.EX
+ All ("XTerm|rxvt" !console) Iconify
+.EE
+This iconifies all the xterm and rxvt windows on the current page,
+except that the one named "console" (with the -name option to xterm)
+is excluded.
+.EX
+ Next (!"FvwmPager|FvwmForm*|FvwmButtons") Raise
+ Next (!FvwmPager, !FvwmForm*, !FvwmButtons) Raise
+.EE
+These two commands are equivalent; either one raises the next window
+which is not one of the named fvwm modules.
 
 Any condition can be negated by using a an exclamation mark ('!')
 directly in front of its name.
Index: fvwm/fvwm.h
===================================================================
RCS file: /home/cvs/fvwm/fvwm/fvwm/fvwm.h,v
retrieving revision 1.231
diff -u -u -r1.231 fvwm.h
--- fvwm/fvwm.h	30 May 2004 14:05:48 -0000	1.231
+++ fvwm/fvwm.h	10 Jul 2004 17:47:29 -0000
@@ -399,6 +399,23 @@
 	unsigned has_ewmh_init_wm_desktop : 2;
 } window_flags;
 
+/* Window name data structure for window conditions: a list of lists
+   of names to match, the boolean operation on the matches being an
+   AND of ORs. */
+struct namelist			/* matches to names in this list are ORed */
+{
+	char *name;
+	struct namelist *next;
+};
+
+struct name_condition		/* matches to namelists in this list are
+				   ANDed, after possibly inverting each */
+{
+	Bool invert;
+	struct namelist *namelist;
+	struct name_condition *next;
+};
+
 /* Window mask for Circulate and Direction functions */
 typedef struct WindowConditionMask
 {
@@ -419,8 +436,6 @@
 #define NEEDS_TRUE  1
 #define NEEDS_FALSE 2
 		unsigned needs_focus : 2;
-		unsigned needs_name : 1;
-		unsigned needs_not_name : 1;
 		unsigned needs_pointer : 2;
 		unsigned needs_same_layer : 1;
 		unsigned use_circulate_hit : 1;
@@ -430,7 +445,7 @@
 	} my_flags;
 	window_flags flags;
 	window_flags flag_mask;
-	char *name;
+	struct name_condition *name_condition;
 	int layer;
 } WindowConditionMask;