Subject: FVWM: FvwmBacker

From: Richard Everson <[email-masked]>
Date: 29 Dec 1996 18:48:25 -0500

Hello,

Here is a patch for FvwmBacker.  Its principal function is to allow
different animated backgrounds (eg xearth, xsnow, xroach) on different
desks.  In addition sets the appropriate background for the current
desktop when FvwmBacker is invoked rather than next time the desk is
changed, and it fixes a small bug that stopped the -solid
option working for me.

Is this the right place for the patch to find its way into 2.0.44?

Happy New Year,
Richard Everson.

*** FvwmBacker.c.orig	Sun Dec 29 18:09:18 1996
--- FvwmBacker.c	Sun Dec 29 18:16:19 1996
***************
*** 25,30 ****
--- 25,43 ----
   * A. Davison
   * Septmber 1994.
   */
+ 
+ /*
+  * Modified to send a running command (eg xearth, xsnow) a SIGCONT when a
+  * particular desk is selected and a SIGSTOP when the desk is left.
+  * Also fork and exec commands rather than using system.
+  * FvwmBacker now sets the background for the current desk when it is invoked
+  * rather than waiting for a change of desks.
+  * Corrected a typo in root_bits.c which stopped the -solid option 
+  * working for me.
+  *
+  * Richard Everson  <[email-masked]>.  Sun Dec 29 14:08:47 1996 
+  */
+ 
  #include "../../configure.h"
  
  #include <stdio.h>
***************
*** 51,66 ****
  #include <X11/Xlib.h>
  
  unsigned long NameToPixel(char*, unsigned long);
  
  typedef struct 
  {
! 	int		type;		/* The command type. 			 */
! 						/* -1 = no command.              */
! 						/*  0 = command to be spawned 	 */
! 						/*  1 = a solid color to be set  */
! 	char*	cmdStr;		/* The command string (Type 0)   */
! 	unsigned long solidColor;
! 						/* A solid color after X parsing (Type 1) */
  } Command;
  
  Command *commands;
--- 64,83 ----
  #include <X11/Xlib.h>
  
  unsigned long NameToPixel(char*, unsigned long);
+ static char *stripwhite (char *);
+ 
  
  typedef struct 
  {
!   int type;			/* The command type. 			 */
! 				/* -1 = no command.              */
! 				/*  0 = command to be spawned 	 */
! 				/*  1 = a solid color to be set  */
!   char *cmdStr;			/* The command string (Type 0)   */
!   char *sscmd;			/* Command to be started and stopped */
!   unsigned long solidColor;	/* A solid color after X parsing (Type 1) */
!   pid_t pid;			/* Pid of StartStop command */
!   int running;			/* Is this pid running or is it stopped? */
  } Command;
  
  Command *commands;
***************
*** 81,87 ****
  
  /* Comment this out if you don't want a logfile. */
  
! /* #define LOGFILE "/tmp/FvwmBacker.log"*/

  void main(int argc, char **argv)
--- 98,106 ----
  
  /* Comment this out if you don't want a logfile. */
  
! /* #define LOGFILE "/tmp/FvwmBacker.log" */
! 
! 

  void main(int argc, char **argv)
***************
*** 105,140 ****
     exit(1);
    }
  
    Fvwm_fd[0] = atoi(argv[1]);
    Fvwm_fd[1] = atoi(argv[2]);
  
    /* Grab the X display information now. */
  
! 	dpy = XOpenDisplay(displayName);
! 	if (!dpy) 
! 	{
! 		fprintf(stderr, "%s:  unable to open display '%s'\n",
! 			Module, XDisplayName (displayName));
! 		exit (2);
! 	}
! 	screen = DefaultScreen(dpy);
! 	root = RootWindow(dpy, screen);
  
! 	/* Open a log file if necessary */
! #	ifdef LOGFILE
! 		logFile = fopen(LOGFILE,"a");
! 		fprintf(logFile,"Initialising FvwmBacker\n");
! #	endif
  
!   signal (SIGPIPE, DeadPipe);  
  
    /* Parse the config file */
    ParseConfig();
  
    fd_width = GetFdWidth();
  
!   SetMessageMask(Fvwm_fd,M_NEW_DESK|M_CONFIG_INFO|M_END_CONFIG_INFO);
! 
  
    /* Recieve all messages from Fvwm */
    EndLessLoop();
--- 124,161 ----
     exit(1);
    }
  
+   signal (SIGPIPE, DeadPipe);  
    Fvwm_fd[0] = atoi(argv[1]);
    Fvwm_fd[1] = atoi(argv[2]);
  
    /* Grab the X display information now. */
  
!   dpy = XOpenDisplay(displayName);
!   if (!dpy) 
!     {
!       fprintf(stderr, "%s:  unable to open display '%s'\n",
! 	      Module, XDisplayName (displayName));
!       exit (2);
!     }
!   screen = DefaultScreen(dpy);
!   root = RootWindow(dpy, screen);
  
!   /* Open a log file if necessary */
! #ifdef LOGFILE
!   logFile = fopen(LOGFILE,"a");
!   fprintf(logFile,"Initialising FvwmBacker\n");
!   fflush(logFile);
! #endif
  
!  SetMessageMask(Fvwm_fd,  M_NEW_DESK|M_CONFIG_INFO|M_END_CONFIG_INFO);
  
    /* Parse the config file */
    ParseConfig();
  
    fd_width = GetFdWidth();
  
!   /* This will elicit a M_NEW_DESK message specifying the current desk */
!   SendInfo(Fvwm_fd, "Send_WindowList", 0);
  
    /* Recieve all messages from Fvwm */
    EndLessLoop();
***************
*** 201,206 ****
--- 222,233 ----
  {
    char* color;
    char* tmp;
+   Command *c;
+ 
+ #ifdef LOGFILE
+   fprintf(logFile, "Message %d\n", type);
+   fflush(logFile);
+ #endif
  
    if (type==M_NEW_DESK) 
      {
***************
*** 208,253 ****
  	{
  	  return;
  	}
  #ifdef LOGFILE
!       fprintf(logFile,"Desk: %d\n",body[0]);
!       fprintf(logFile,"Command type: %d\n",commands[body[0]].type);
!       if (commands[body[0]].type == 0)
! 	fprintf(logFile,"Command String: %s\n",commands[body[0]].cmdStr);
!       else if (commands[body[0]].type == 1)
! 	fprintf(logFile,"Color Number: %d\n",commands[body[0]].solidColor);
!       else if (commands[body[0]].type == -1)
  	fprintf(logFile,"No Command\n");
!       else
! 	{
! 	  fprintf(logFile,"Illegal command type !\n");
! 	  exit(1);
! 	}
        fflush(logFile);
! #	endif

!       if (commands[body[0]].type == 1)
  	{
  	  /* Process a solid color request */
! 	  
! 	  XSetWindowBackground(dpy, root, commands[body[0]].solidColor);
  	  XClearWindow(dpy, root);
  	  XFlush(dpy);
- 	  /*	XSetWindowBackground(dpy, root, commands[body[0]].solidColor);
- 	   */
  	  
! #		ifdef LOGFILE
  	  fprintf(logFile,"Color set.\n");
  	  fflush(logFile);
! #		endif
  	}
!       else if(commands[body[0]].cmdStr != NULL)
! 	{
! 	  system(commands[body[0]].cmdStr);
  	}
      }
  }
  
  /******************************************************************************
    SendFvwmPipe - Send a message back to fvwm 
      Based on SendInfo() from FvwmIdent:
--- 235,300 ----
  	{
  	  return;
  	}
+       c = commands+body[0];
+       
  #ifdef LOGFILE
!       fprintf(logFile, "Desk: %d\n", body[0]);
!       fprintf(logFile, "Command type: %d\n", c->type);
!       if (c->type == 0)
! 	fprintf(logFile,"Command String: %s\n", 
! 		(c->cmdStr) ? c->cmdStr : "(none)");
!       else if (c->type == 1)
! 	fprintf(logFile,"Color Number: %d\n", c->solidColor);
!       else if (c->type == -1)
  	fprintf(logFile,"No Command\n");
!       else {
! 	fprintf(logFile,"Illegal command type!\n");
! 	exit(1);
!       }
!       if (c->sscmd)
! 	fprintf(logFile,"StartStop command: %s\n", c->sscmd);
        fflush(logFile);
! #endif
  
+       StopBackgrounds(); /* Send SIGSTOP to any running backgrounds */
        
!       if (c->type == 1)
  	{
  	  /* Process a solid color request */
! 	  XSetWindowBackground(dpy, root, c->solidColor);
  	  XClearWindow(dpy, root);
  	  XFlush(dpy);
  	  
! #ifdef LOGFILE
  	  fprintf(logFile,"Color set.\n");
  	  fflush(logFile);
! #endif
  	}
!       else if (c->type == 0) {
! 	  if(c->cmdStr != NULL)	/* Just fire it up */	  
! 	    Spawn(c->cmdStr);
!       }
! 
!       if (c->sscmd) {	/* StartStop */
! 	  
! 	  if (!c->pid) {
! 	    c->pid = Spawn(c->sscmd); /* Start a new process */
! 	    c->running = 1;
! 	  }
! 	  else {
! 	    kill(c->pid, SIGCONT); /* Ask it to continue */
! 	    c->running = 1;
! #ifdef LOGFILE
! 	    fprintf(logFile,"Sent SIGCONT to %s (pid %d)\n", c->sscmd, c->pid);
! 	    fflush(logFile);
! #endif
! 	  }
  	}
      }
+   return;
  }
  
+   
  /******************************************************************************
    SendFvwmPipe - Send a message back to fvwm 
      Based on SendInfo() from FvwmIdent:
***************
*** 290,295 ****
--- 337,357 ----
   **********************************************************************/
  void DeadPipe(int nonsense)
  {
+   int d;
+   Command *cp;
+   
+   /* Try to clean up by killing all the running children */
+   
+   for (d = 0, cp = commands; d < DeskCount; d++, cp++)
+     if (cp->sscmd && cp->pid > 0) {
+ #ifdef LOGFILE
+       fprintf(logFile, "Sending SIGKILL to %s (pid %d)\n",
+ 	      cp->sscmd, cp->pid);
+       fflush(logFile);
+ #endif
+       kill(cp->pid, SIGKILL);
+     }
+   
    exit(1);
  }
  
***************
*** 304,309 ****
--- 366,376 ----
    char *tline;
    
    sprintf(line2,"*%sDesk",Module);
+ 
+ #ifdef LOGFILE  
+   fprintf(logFile, "Parsing config\n");
+   fflush(logFile);
+ #endif
    
    GetConfigLine(Fvwm_fd,&tline);
  
***************
*** 323,330 ****
  ******************************************************************************/
  void AddCommand(char *string)
  {
! char *temp;
! int num;
    temp=string;
    while(isspace(*temp)) temp++;
    num=atoi(temp);
--- 390,399 ----
  ******************************************************************************/
  void AddCommand(char *string)
  {
!   char *temp, *t, *color;
!   int num;
!   Command *c;
!   
    temp=string;
    while(isspace(*temp)) temp++;
    num=atoi(temp);
***************
*** 340,381 ****
        while(DeskCount<num+1) commands[DeskCount++].type= -1;
      }
    }
- /*  commands[num]=(Command*)safemalloc(sizeof(Command));
- */
  
!     /* Now check the type of command... */
!     /* strcpy(commands[num],temp);*/
  
- 	if (strncmp(temp,"-solid",6)==0)
- 	{
- 		char* color;
- 		char* tmp;
- 		/* Process a solid color request */
- 
- 		color = &temp[7];
- 		while (isspace(*color))
- 			color++;
- 		tmp= color;
- 		while (!isspace(*tmp))
- 			tmp++;
- 		*tmp = 0;
- 		commands[num].type = 1;
- 		commands[num].solidColor = NameToPixel(color, BlackPixel(dpy, screen));
  #ifdef LOGFILE
! 		fprintf(logFile,"Adding color: %s as number %d to desk %d\n",
! 			color,commands[num].solidColor, num);
! 		fflush(logFile);
  #endif
! 	}
! 	else
! 	{
  #ifdef LOGFILE
! 		fprintf(logFile,"Adding command: %s to desk %d\n",temp, num);
! 		fflush(logFile);
  #endif
- 		commands[num].type = 0;
- 		commands[num].cmdStr = (char *)safemalloc(strlen(temp)+1);
- 		strcpy(commands[num].cmdStr,temp);
- 	}
  
  }
--- 409,572 ----
        while(DeskCount<num+1) commands[DeskCount++].type= -1;
      }
    }
  
!   /* Now check the type of command... */
! 
!   c = commands+num;
!   c->cmdStr = c->sscmd = NULL;
!   c->solidColor = 0;
!   
  
  #ifdef LOGFILE
!   fprintf(logFile, "Parsing %s\n", temp);
!   fprintf(logFile, "Desk %d\n", num);
!   fflush(logFile);
  #endif
! 
!   /* Look for a StartStop command */
!   if ((t = strstr(temp, "StartStop"))) {	
!     *t = '\0';
!     t = stripwhite(t+9);
!     c->sscmd = (char *)safemalloc(strlen(t)+1);
!     strcpy(c->sscmd, t);
!     c->pid = c->running = 0;
!   }
!     
!   temp = stripwhite(temp);
!     
!   if (strncmp(temp, "-solid", 6)==0)  {
!     char* tmp;
!     /* Process a solid color request */
!     c->type = 1;
!       
!     color = &temp[7];
!     while (isspace(*color))
!       color++;
!     tmp= color;
!     while (!isspace(*tmp))
!       tmp++;
!     *tmp = '\0';
!     fprintf(logFile, "  BlackPixel = %d\n", BlackPixel(dpy, screen));
!     c->solidColor = NameToPixel(color, BlackPixel(dpy, screen));
!   }
!   else {
!     c->type = 0;
!     if (strlen(temp) >   0) {
!       c->cmdStr = (char *)safemalloc(strlen(temp)+1);
!       strcpy(c->cmdStr,temp);
!     }
!     else 
!       c->cmdStr = NULL;
!   }
! 
  #ifdef LOGFILE
!   fprintf(logFile, "  Type %d\n", c->type);
!   if (c->type == 1)
!     fprintf(logFile,"  Solid color %s as number %d\n",color, c->solidColor);
!   if (c->cmdStr)
!     fprintf(logFile, "  Command: %s\n", c->cmdStr);
!   if (c->sscmd)
!     fprintf(logFile, "  StartStop command: %s\n", c->sscmd);
!   fprintf(logFile, "\n");
!   fflush(logFile);
  #endif
  
+   return;
+ }
+ 
+ 
+ void StopBackgrounds(void)
+ {
+   /* 
+    * Send SIGSTOP to any running background programs.  
+    * There should be at most one of them, but we try them all anyway.
+    */
+ 
+   int d;
+   Command *cp;
+   
+   
+   for (d = 0, cp = commands; d < DeskCount; d++, cp++)
+     if (cp->sscmd && cp->running && cp->pid > 0) {
+ #ifdef LOGFILE
+       fprintf(logFile, "Sending SIGSTOP to %s (pid %d) on desk %d\n",
+ 	      cp->sscmd, cp->pid, d);
+       fflush(logFile);
+ #endif
+       kill(cp->pid, SIGSTOP);
+       cp->running = 0;
+     }
+   return;
+ }
+ 
+ 
+ pid_t Spawn(char *c)
+ {
+   /*
+    * Fork and exec the command in c, returning the pid
+    */
+ 
+   
+   int j, n = 0;
+   pid_t pid = 0;
+   char **av, *s;
+  
+ 
+   if ((pid = fork()) != 0) {
+ #ifdef LOGFILE 
+     fprintf(logFile, "forked pid %d\n", pid);
+     fflush(logFile);
+ #endif  
+     return pid;
+   }
+   
+   /* Child */
+   for (n = 0, s = c; *s; )
+     n += isspace(*s++);		/* Count the number of words */
+   
+   av = (char **)safemalloc(n*sizeof(char *));
+   
+   s = strtok(c, " \t\n");
+ 
+   n = 0;
+   av[n++] = s;
+   while ((s = strtok(NULL, " \t\n")))
+     av[n++] = s;
+   av[n] = NULL;
+ 
+ #ifdef LOGFILE 
+   fprintf(logFile, "Spawning: ");
+   for (j = 0; j < n; j++)
+     fprintf(logFile, "%s ", av[j]);
+   fprintf(logFile, "\n");
+   fflush(logFile);
+ #endif
+   execvp(av[0], av);
+   /* NOTREACHED */
+   return -1;
+ }
+ 
+ 
+ #ifndef whitespace
+ #define whitespace(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n'))
+ #endif
+ 
+ 
+ static char *stripwhite (char *string)
+ {
+   register int i = 0;
+ 
+   while (whitespace (string[i]))
+     i++;
+ 
+   if (i)
+     strcpy (string, string + i);
+ 
+   i = strlen (string) - 1;
+ 
+   while (i > 0 && whitespace (string[i]))
+     i--;
+ 
+   string[++i] = '\0';
+   return(string);
  }
*** FvwmBacker.h.orig	Sun Dec 29 18:09:18 1996
--- FvwmBacker.h	Mon Dec  9 23:14:52 1996
***************
*** 29,31 ****
--- 29,35 ----
  void DeadPipe(int nonsense);
  void ParseConfig(void);
  void AddCommand(char *string);
+ void StopBackgrounds(void);
+ pid_t Spawn(char *c);
+ 
+ 
*** FvwmBacker.man.orig	Sun Dec 29 18:09:18 1996
--- FvwmBacker.man	Sun Dec 29 17:54:41 1996
***************
*** 1,6 ****
  .\" t
  .\" @(#)FvwmBacker.1	11/8/94
! .TH FvwmBacker 0.1 "September 8th, 1994"
  .UC
  .SH NAME
  FvwmBacker \- the FVWM background changer module
--- 1,6 ----
  .\" t
  .\" @(#)FvwmBacker.1	11/8/94
! .TH FvwmBacker 0.1 "December 29th, 1996"
  .UC
  .SH NAME
  FvwmBacker \- the FVWM background changer module
***************
*** 10,18 ****
  .SH DESCRIPTION
  The FvwmBacker module provides functionality to change the background
  when changing desktops.  Any command can be executed to change the
! backgrounds.  The commands used to change the backgrounds must exit
! after changing the root window, (i.e. 'xv -root zzz.gif' does not,
! without the -quit option) otherwise FvwmBacker will hang.
  
  .SH COPYRIGHTS
  The FvwmBacker module is the original work of Mike Finger.
--- 10,17 ----
  .SH DESCRIPTION
  The FvwmBacker module provides functionality to change the background
  when changing desktops.  Any command can be executed to change the
! backgrounds.  In addition a command that continuously draws to the
! root window 
  
  .SH COPYRIGHTS
  The FvwmBacker module is the original work of Mike Finger.
***************
*** 37,43 ****
  .SH CONFIGURATION OPTIONS
  The following is the only supported option at present:
  
! .IP "*FvwmBackerDesk \fIDeskNumber command\fP"
  Specifies the \fIcommand\fP to execute when the specified
  \fIDeskNumber\fP becomes active.
  
--- 36,42 ----
  .SH CONFIGURATION OPTIONS
  The following is the only supported option at present:
  
! .IP "*FvwmBackerDesk \fIDeskNumber command \fP[StartStop \fIsscommand\fP]"
  Specifies the \fIcommand\fP to execute when the specified
  \fIDeskNumber\fP becomes active.
  
***************
*** 46,51 ****
--- 45,59 ----
  color without generating a system call to xsetroot. Only single word
  color names may be used.
  
+ If the optional keyword StartStop and an additional command
+ \fIsscommand\fP are specified, \fIsscommand\fP will be invoked the
+ first time \fIDeskNumber\fP becomes active; when it becomes inactive
+ \fIsscommand\fP will be stopped by sending it a STOP signal and it
+ will be restarted (with a SIGCONT) when the desk next becomes active.
+ This behaviour is designed to be used with programs such as xearth(1)
+ and xsnow(1) which continuously draw on the root window.  By using
+ StartStop commands you can have a different animation on each desktop.
+ 
  .SH SAMPLE CONFIGURATION
  The following are excepts from a .fvwmrc file which describe
  FvwmBacker initialization commands:
***************
*** 56,70 ****
  # Set Up Backgrounds for different desktops.
  ####
  *FvwmBackerDesk 0 -solid steelblue
! *FvwmBackerDesk 1 -solid midnightblue
! *FvwmBackerDesk 2 -solid yellow
! *FvwmBackerDesk 3 xpmroot /usr/include/X11/pixmaps/background2.xpm
  .sp
  .fi
! 
  .SH AUTHOR
  Mike Finger ([email-masked])
              ([email-masked])
              (doodman on IRC, check the #linux channel)
  .SH Modified by
! Andrew Davison ([email-masked])
--- 64,96 ----
  # Set Up Backgrounds for different desktops.
  ####
  *FvwmBackerDesk 0 -solid steelblue
! *FvwmBackerDesk 1 StartStop xearth -wait 30
! *FvwmBackerDesk 2 -solid MidnightBlue StartStop xsnow
! *FvwmBackerDesk 3 xpmroot /usr/include/X11/pixmaps/background2.xpm StartStop xroach
  .sp
  .fi
! Desk 0 is plain steel-blue.  Xearth(1) runs on desk 1 and xsnow(1)
! runs on desk 2.  Each time desk 2 becomes active the background is
! reset to midnight-blue because xsnow does not redraw the background
! when it is restarted.  Similarly desk 3 has roaches running around on
! a background of background2.xpm pixmaps; xpmroot is rerun each time
! the desk is selected to redraw the background.
! .SH NOTES
! Version 1.0 of xearth redraws the root window every five minutes by
! default.  Thus you might have to wait five minutes after selecting a
! desk before the background is redrawn.  One solution to this problem
! is to ask xearth to update itself every few seconds (eg xearth -wait
! 5), but this is clearly wasteful and will chew up noticable amounts of
! CPU time.   An alternative is to apply a patch to xearth (supplied
! with FvwmBacker) so that xearth updates itself each time it is sent a
! SIGCONT.  The patch has been sent to Kirk Lauritz Johnson and I hope
! will find its way into later releases of the xearth.
! .SH SEE ALSO
! xearth(1), xsnow(1), xroach(1), xpmroot(1), signal(2).
  .SH AUTHOR
  Mike Finger ([email-masked])
              ([email-masked])
              (doodman on IRC, check the #linux channel)
  .SH Modified by
! Andrew Davison ([email-masked]) (September 1994) and Richard
! Everson ([email-masked]) (December 1996).
*** root_bits.c.orig	Sun Dec 29 18:09:18 1996
--- root_bits.c	Sun Dec 29 14:15:56 1996
***************
*** 66,73 ****
  	exit(1);
  	/*NOTREACHED*/
      }
!     if ((ecolor.pixel != BlackPixel(dpy, screen)) &&
! 	(ecolor.pixel != WhitePixel(dpy, screen)) &&
! 	(DefaultVisual(dpy, screen)->class & Dynamic))
      return(ecolor.pixel);
  }
--- 66,71 ----
  	exit(1);
  	/*NOTREACHED*/
      }
!     
      return(ecolor.pixel);
  }
*** /dev/null	Mon Dec 31 23:00:00 1979
--- xearth.patch	Sun Dec 29 18:07:32 1996
***************
*** 0 ****
--- 1,56 ----
+ *** x11.c.orig	Sun Sep 24 21:12:44 1995
+ --- x11.c	Thu Dec 26 18:58:53 1996
+ ***************
+ *** 46,51 ****
+ --- 46,53 ----
+    */
+   
+   #include "xearth.h"
+ + #include <signal.h>
+ + 
+   #include <X11/Xlib.h>
+   #include <X11/Intrinsic.h>
+   #include <X11/Xatom.h>
+ ***************
+ *** 470,475 ****
+ --- 472,481 ----
+     /* preserveResource(dsply, vroot); */
+   }
+   
+ + static void wakeup(int s)
+ + {
+ +   /* Catch SIGALRM and SIGCONT, but don't do anything */
+ + }
+   
+   void x11_output()
+   {
+ ***************
+ *** 499,507 ****
+         return;
+       }
+   
+ !     /* sleep for designated wait_time
+        */
+ !     sleep((unsigned) wait_time);
+     }
+   }
+   
+ --- 505,522 ----
+         return;
+       }
+   
+ !     /*
+ !      * Schedule an alarm for wait_time seconds and pause.  Alarm and pause are
+ !      * used instead of sleep, so that if xearth is sent a SIGSTOP and SIGCONT
+ !      * separated by more that wait_time, it will refreash the screen as 
+ !      * soon as the SIGCONT is received.   This facilitates interaction 
+ !      * with FvwmBacker.
+        */
+ ! 
+ !     signal(SIGALRM, wakeup);
+ !     signal(SIGCONT, wakeup);
+ !     alarm(wait_time);
+ !     pause();
+     }
+   }
+   

-- 
Laboratory for Applied Mathematics,       Telephone: +1 212 241 4033
CUNY/Mount Sinai School of Medicine,            Fax: +1 212 425 5037
Box 1012, One Gustave Levy Place,
NY, NY, 10029-6574.                      Email: [email-masked]

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