Subject: CoolNext Patch and misc...

From: Sean Reifschneider <[email-masked]>
Date: Thu, 10 Sep 1998 03:34:21 -0600

I don't know if my last message made it here (I don't see it on the
archive), but the short of it was that I was asking about how I could
receive metakey up events in the FVWM source.

After spending several hours and not being able to track down where/how
I might be able to get the modifier-up events, I decided to work within
what I had.  The result is the CoolNext patch I'm including below (also
available at "ftp.tummy.com:/pub/tummy/fvwm-2.0.46-coolnext.patch").

It's similar to the MS Windows "Cool Switch".  Basicly, once you select
a window using CoolNext (I have it mapped to Alt-Tab), that window moves
to the top of the window stack.  It basicly organizes your windows into
an LRU stack.  In MS Windows, they determine the "end of the select" by
the release of the Alt key.  Since I didn't have this luxury, I used a
simple timer -- a "CoolNext" 2 (default) or more seconds after the last
indicates a new session.

I'm still looking for somone who knows the guts of FVWM a bit more than
I who might be able to give some pointers on where I could get Modifier-up
key events.

Add the following lines to your .fvwm2rc to get this behavior:

	#CoolNextSeconds 2		#  default of 2
	Key Tab     A  M     CoolNext [*] Focus

You may want to also have it raise in addition to doing focus.  I plan to
do something like "Alt-Tab" cycles with raise, "Ctrl-Tab" cycles without.
(That's why I love X :-).

I also made a few other changes, most related to warnings:

	Changed return-type of main() to "void" (warning)
	Changed "val1" type to long (warning)
	Removed "n" variables where they were dead code (maintainance)
	Added WinList(Append|Remove|Dump)() functions (used by CoolNext)
	Changed a couple of instances of Fvwm code to use WinListRemove().
	configure.h change to allow easy (un)commenting of debug statement.

I put "SMR" or my name in most of the changes I made, feel free to
remove them once you've had a look at them.  Of course, I would
appreciate being listed as doing the CoolNext changes.  :-)

Also, I put this patch under the MPL -- I didn't see that there was any
license information in the FVWM files.  I mention this because I figure
there should be some discussion on the issue, even if it results in
just a few lines in the README that say "There's no license, it's in
the public domain because X."

Any comments appreciated,
Sean
-- 
 Program *INTO* a language, not *IN* it.
                 -- David Gries
Sean Reifschneider, Inimitably Superfluous <[email-masked]>
URL: <http://www.tummy.com/xvscan> HP-UX/Linux/FreeBSD/BSDOS scanning software.

==================
diff -ru fvwm-2.0.46/configure.h fvwm-2.0.46j/configure.h
--- fvwm-2.0.46/configure.h	Wed Jan 15 12:07:35 1997
+++ fvwm-2.0.46j/configure.h	Thu Sep 10 01:00:12 1998
@@ -108,7 +108,7 @@
 ** if you would like to see lots of debug messages from fvwm, for debugging
 ** purposes, uncomment the next line
 */
-/* #define FVWM_DEBUG_MSGS */
+/* #define FVWM_DEBUG_MSGS /**/
 #ifdef FVWM_DEBUG_MSGS
 #define DBUG(x,y) fvwm_msg(DBG,x,y)
 #else
diff -ru fvwm-2.0.46/fvwm/builtins.c fvwm-2.0.46j/fvwm/builtins.c
--- fvwm-2.0.46/fvwm/builtins.c	Tue Aug 19 17:41:27 1997
+++ fvwm-2.0.46j/fvwm/builtins.c	Thu Sep 10 02:56:12 1998
@@ -671,7 +671,7 @@
 		      unsigned long context,char *action, int *Module)
 
 {
-  int val1;
+  long val1;
   int val1_unit,n;
 
   if (DeferExecution(eventp,&w,&tmp_win,&context, SELECT, 
@@ -992,16 +992,14 @@
 
   /* Reorder the window list */
   if( Scr.Focus ){
-    if( Scr.Focus->next ) Scr.Focus->next->prev = Scr.Focus->prev;
-    if( Scr.Focus->prev ) Scr.Focus->prev->next = Scr.Focus->next;
+    WinListRemove(Scr.Focus);	/*  SMR 1998-09  */
     Scr.Focus->next = Scr.FvwmRoot.next;
     Scr.Focus->prev = &Scr.FvwmRoot;
     if(Scr.FvwmRoot.next)Scr.FvwmRoot.next->prev = Scr.Focus;
     Scr.FvwmRoot.next = Scr.Focus;
   }
   if( tmp_win != Scr.Focus ){
-    if( tmp_win->next ) tmp_win->next->prev = tmp_win->prev;
-    if( tmp_win->prev ) tmp_win->prev->next = tmp_win->next;
+    WinListRemove(tmp_win);	/*  SMR 1998-09  */
     tmp_win->next = Scr.FvwmRoot.next;
     tmp_win->prev = &Scr.FvwmRoot;
     if(Scr.FvwmRoot.next)Scr.FvwmRoot.next->prev = tmp_win;
@@ -1240,12 +1238,10 @@
 void SetClick(XEvent *eventp,Window w,FvwmWindow *tmp_win,
               unsigned long context, char *action,int* Module)
 {
-  int val1;
+  long val1;	/*  SMR 1998-09  */
   int val1_unit,n;
 
-  n = GetOneArgument(action, &val1, &val1_unit);
-  if(n != 1)
-  {
+  if (GetOneArgument(action, &val1, &val1_unit) != 1) {	/*  SMR 1998-09  */
     fvwm_msg(ERR,"SetClick","ClickTime requires 1 argument");
     return;
   }
@@ -1256,14 +1252,12 @@
 void SetXOR(XEvent *eventp,Window w,FvwmWindow *tmp_win,
             unsigned long context, char *action,int* Module)
 {
-  int val1;
+  long val1;	/*  SMR 1998-09  */
   int val1_unit,n;
   XGCValues gcv;
   unsigned long gcm;
 
-  n = GetOneArgument(action, &val1, &val1_unit);
-  if(n != 1)
-  {
+  if (GetOneArgument(action, &val1, &val1_unit) != 1) {	/*  SMR 1998-09  */
     fvwm_msg(ERR,"SetXOR","XORValue requires 1 argument");
     return;
   }
@@ -1283,12 +1277,10 @@
 void SetOpaque(XEvent *eventp,Window w,FvwmWindow *tmp_win,
 	       unsigned long context, char *action,int* Module)
 {
-  int val1;
+  long val1;	/*  SMR 1998-09  */
   int val1_unit,n;
 
-  n = GetOneArgument(action, &val1, &val1_unit);
-  if(n != 1)
-  {
+  if (GetOneArgument(action, &val1, &val1_unit) != 1) {	/*  SMR 1998-09  */
     fvwm_msg(ERR,"SetOpaque","OpaqueMoveSize requires 1 argument");
     return;
   }
@@ -3165,6 +3157,65 @@
     free(name - 1);
   return found;
 
+}
+
+
+/****************************************************************************
+ *  Like NextFunc, but if more than Scr.CoolSecs seconds have gone by since
+ *  the last switch, move the current focus window to the top of the stack.
+ *  This acts like MS Windows "Cool Switching" (they've only had it a decade
+ *  now :-).  Unfortunately, there was no way to get the
+ *
+ *  Windows uses the release of the "Alt" key to signal end of switch.
+ *  I wasn't able to figure out how to do that, so I used a simple timing
+ *  mechanism.  Use the config directive "CoolNextSecs" to set.
+ *
+ *  CoolNext changes by Sean Reifschneider <[email-masked]>, 1998-09
+ *  Copyright (c) 1998, tummy.com, ltd.  All Rights Reserved.
+ *  Released under the Mozilla Public License
+ *  (http://www.mozilla.org/NPL/MPL-1.0.html), for inclusion in FVWM.
+ *
+ *  FVWM didn't seem to include any license, so I errored on the safe
+ *  side of using the MPL.  If this causes any problems, let's talk...
+ */
+
+void CoolNextFunc(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+              unsigned long context, char *action,int* Module)
+{
+FvwmWindow *found;
+char *restofline;
+static time_t lastSwitch = 0;
+time_t now = time(NULL);
+FvwmWindow *tmp, *fw;
+
+
+if (Scr.CoolSecs > 0 && now - lastSwitch > Scr.CoolSecs && Scr.Focus) {
+	WinListRemove(Scr.Focus);
+	WinListAppend(Scr.Focus);
+	}
+lastSwitch = now;
+
+NextFunc(eventp, junk, tmp_win, context, action, Module);
+}
+
+
+/******************************************************************************/
+/*  set the number of seconds before a Cool Next will re-arrange window list  */
+/*  Sean Reifschneider <[email-masked]> 1998-09                               */
+
+void CoolSetSecs(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+              unsigned long context, char *action,int* Module)
+{
+long val1;
+int val1_unit;
+
+
+if (GetOneArgument(action, &val1, &val1_unit) != 1) {
+	fvwm_msg(ERR, "CoolSetSecs", "Requires 1 argument");
+	return;
+	}
+
+Scr.CoolSecs = val1;
 }
 
 void PrevFunc(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
diff -ru fvwm-2.0.46/fvwm/functions.c fvwm-2.0.46j/fvwm/functions.c
--- fvwm-2.0.46/fvwm/functions.c	Mon Aug 11 14:09:29 1997
+++ fvwm-2.0.46j/fvwm/functions.c	Thu Sep 10 02:04:34 1998
@@ -64,6 +64,8 @@
   {"ClickTime",    SetClick,         F_CLICK,               FUNC_NO_WINDOW},
   {"Close",        close_function,   F_CLOSE,               FUNC_NEEDS_WINDOW},
   {"ColormapFocus",SetColormapFocus, F_COLORMAP_FOCUS,      FUNC_NO_WINDOW},
+  {"CoolNext",     CoolNextFunc,     F_COOLNEXT,            FUNC_NO_WINDOW},
+  {"CoolNextSeconds", CoolSetSecs, F_COOLSETSECS,         FUNC_NO_WINDOW},
   {"Current",      CurrentFunc,      F_CURRENT,             FUNC_NO_WINDOW},
   {"CursorMove",   movecursor,       F_MOVECURSOR,          FUNC_NO_WINDOW},
   {"CursorStyle",  CursorStyle,      F_CURSOR_STYLE,        FUNC_NO_WINDOW},
diff -ru fvwm-2.0.46/fvwm/fvwm.c fvwm-2.0.46j/fvwm/fvwm.c
--- fvwm-2.0.46/fvwm/fvwm.c	Mon Aug  4 14:53:32 1997
+++ fvwm-2.0.46j/fvwm/fvwm.c	Thu Sep 10 01:56:37 1998
@@ -120,7 +120,7 @@
  *
  ***********************************************************************
  */
-void main(int argc, char **argv)
+int main(int argc, char **argv)
 {
   unsigned long valuemask;	/* mask for create windows */
   XSetWindowAttributes attributes;	/* attributes for create windows */
@@ -1225,6 +1225,7 @@
   Scr.ScrollResistance = Scr.MoveResistance = 0;
   Scr.OpaqueSize = 5;
   Scr.ClickTime = 150;
+  Scr.CoolSecs = 2;
   Scr.ColormapFocus = COLORMAP_FOLLOWS_MOUSE;
 
   /* set major operating modes */
diff -ru fvwm-2.0.46/fvwm/misc.c fvwm-2.0.46j/fvwm/misc.c
--- fvwm-2.0.46/fvwm/misc.c	Tue Jun 24 08:01:39 1997
+++ fvwm-2.0.46j/fvwm/misc.c	Thu Sep 10 02:56:31 1998
@@ -764,3 +772,54 @@
 } /* fvwm_msg */

+/*************************************************/
+/*  remove the specified window from the list    */
+/*  Sean Reifschneider <[email-masked]> 1998-09  */
+
+void WinListRemove(FvwmWindow *win)
+{
+if (win->next) win->next->prev = win->prev;
+if (win->prev) win->prev->next = win->next;
+win->next = NULL;
+win->prev = NULL;
+}
+
+
+/*******************************************************************/
+/*  append the specified window to the end of the list             */
+/*  NOTE: "Next" walks through this list from the end (backwards)  */
+/*  Sean Reifschneider <[email-masked]> 1998-09                    */
+
+void WinListAppend(FvwmWindow *win)
+{
+FvwmWindow *fw;
+
+
+for (fw = &(Scr.FvwmRoot); fw && fw->next; fw = fw->next)
+	;
+if (fw) {
+	fw->next = win;
+	win->next = NULL;
+	win->prev = fw;
+	}
+else
+	fvwm_msg(ERR, "WinListAppend", "Scr.FvwmRoot == NULL?!?");
+}
+
+
+/**************************************************************/
+/*  dump a representation of the FvwmRoot window linked list  */
+/*  Sean Reifschneider <[email-masked]> 1998-09               */
+
+void WinListDump(void)
+{
+FvwmWindow *fw;
+
+
+#ifdef FVWM_DEBUG_MSGS
+fvwm_msg(DBG, "TreeDump", "Begining dump of tree:");
+for (fw = &(Scr.FvwmRoot); fw; fw = fw->next)
+	fvwm_msg(DBG, "TreeDump","--> %p %s", fw, (fw == Scr.Focus) ? "(Focus)" :
+			(fw == &(Scr.FvwmRoot)) ? "(Root)" : "");
+#endif
+}
diff -ru fvwm-2.0.46/fvwm/misc.h fvwm-2.0.46j/fvwm/misc.h
--- fvwm-2.0.46/fvwm/misc.h	Mon Aug 11 14:10:19 1997
+++ fvwm-2.0.46j/fvwm/misc.h	Thu Sep 10 02:28:00 1998
@@ -518,6 +518,10 @@
 	       unsigned long context, char *action,int* Module);
 void NextFunc(XEvent *eventp,Window w,FvwmWindow *tmp_win,
 	      unsigned long context, char *action,int* Module);
+void CoolNextFunc(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
+              unsigned long context, char *action,int* Module);
+void CoolSetSecs(XEvent *eventp,Window w,FvwmWindow *tmp_win,
+	       unsigned long context, char *action,int* Module);
 void PrevFunc(XEvent *eventp,Window w,FvwmWindow *tmp_win,
 	      unsigned long context, char *action,int* Module);
 void NoneFunc(XEvent *eventp,Window w,FvwmWindow *tmp_win,
@@ -540,6 +544,12 @@
                       unsigned long context, char *action,int* Module);
 void AddModConfig(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
                   unsigned long context, char *action,int* Module);
+
+/*  functions to manipulate FvwmRoot window list  */
+/*  Sean Reifschneider <[email-masked]> 1998-09  */
+void WinListDump(void);
+void WinListAppend(FvwmWindow *win);
+void WinListRemove(FvwmWindow *win);
 
 /*
 ** message levels for fvwm_msg:
diff -ru fvwm-2.0.46/fvwm/parse.h fvwm-2.0.46j/fvwm/parse.h
--- fvwm-2.0.46/fvwm/parse.h	Mon Aug 11 14:10:39 1997
+++ fvwm-2.0.46j/fvwm/parse.h	Thu Sep 10 01:52:42 1998
@@ -75,6 +75,8 @@
 #define F_EXEC_SETUP            57
 #define F_CURSOR_STYLE          58
 #define F_CURRENT               59
+#define F_COOLNEXT              60	/*  SMR 1998-09  */
+#define F_COOLSETSECS           61	/*  SMR 1998-09  */
 
 /* Functions which require a target window */
 #define F_RESIZE		100
diff -ru fvwm-2.0.46/fvwm/screen.h fvwm-2.0.46j/fvwm/screen.h
--- fvwm-2.0.46/fvwm/screen.h	Mon Aug  4 14:55:30 1997
+++ fvwm-2.0.46j/fvwm/screen.h	Thu Sep 10 01:55:42 1998
@@ -308,6 +308,7 @@
   int Vx;                       /* Current loc for top left of virt desk */
   int Vy;
 
+  int CoolSecs;                /*  seconds after which to "Cool Switch"  */
   int ClickTime;               /*Max button-click delay for Function built-in*/
   int ScrollResistance;        /* resistance to scrolling in desktop */
   int MoveResistance;          /* res to moving windows over viewport edge */
--
Visit the official FVWM web page at <URL:http://www.hpc.uh.edu/fvwm/>.
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: Tim Phipps <[email-masked]>
Date: Thu, 10 Sep 1998 13:46:40 +0100

Here's a little patch to 2.0.47d menus.c that changes two things:
1) The pointer is restored before menu actions are performed rather
   than after.  This is necessary for WindowList to be usable from
   a key press and I think it is correct behaviour anyway.

2) The keypad numbers can be used to select menu items if they have
   numbers as accelerators.

This lets me do

Key KP_Enter A N WindowList CurrentDesk, NoGeometry
DestroyFunc WindowListFunc
AddToFunc WindowListFunc "I" WindowId $0 FlipFocus
+                        "I" WindowId $0 Iconify -1
+                        "I" WindowId $0 Raise
+                        "I" WindowId $0 WarpToWindow 5p 5p

and I can doink the Enter key and a number to easily switch windows in a
Windows style e.g. the current window is Enter-1, the one used before is
Enter-2 etc.

This is related to but not mutually exclusive with Sean Reifschneider's
patch to give a CoolNext function. I haven't tried that patch but it
looks useful.  This patch will always doink up a menu and you must press
a key to get out, Sean's patch switches focus with just one key but
doesn't have a menu you can choose from.  I think they should both go
into 2.0.47e.

Cheers,
Tim.

PS nice things to do for someone with time:
1) Geometry specs for menus so that WindowList can pop up in the
   centre of the screen

2) FvwmIconMan to track the windowlist order either automatically or
   on receiving a message.

*** menus.c.orig	Thu Sep 10 10:24:41 1998
--- menus.c	Thu Sep 10 12:47:44 1998
***************
*** 170,182 ****
    menuFromFrameOrWindowOrTitlebar = FALSE;
    XFlush(dpy);
  
-   if(cmenuDeep == 0) {
-     UngrabEm();
-     WaitForButtonsUp();
-     if (retval == MENU_DONE || retval == MENU_DONE_BUTTON)
-       ExecuteFunction((*pmiExecuteAction)->action,ButtonWindow, &Event, Context,-1);
-   }
- 
    if (cmenuDeep == 0 &&
        x_start >= 0 && y_start >= 0 &&
        IS_MENU_BUTTON(retval)) {
--- 170,175 ----
***************
*** 188,193 ****
--- 181,193 ----
  		 x_start, y_start);
    }
  
+   if(cmenuDeep == 0) {
+     UngrabEm();
+     WaitForButtonsUp();
+     if (retval == MENU_DONE || retval == MENU_DONE_BUTTON)
+       ExecuteFunction((*pmiExecuteAction)->action,ButtonWindow, &Event, Context,-1);
+   }
+ 
    if(((lastTimestamp-t0) < 3*Scr.ClickTime)&&(mouse_moved==FALSE))
      retval = MENU_DOUBLE_CLICKED;
    return retval;
***************
*** 324,329 ****
--- 324,330 ----
   * it was the escape key then the menu processing is aborted.
   * If none of these conditions are true, then the default processing
   * routine is called.
+  * TKP - uses XLookupString so that keypad numbers work with windowlist
   ***********************************************************************/
  static
  MenuStatus menuShortcuts(MenuRoot *menu,XEvent *Event,MenuItem **pmiCurrent)
***************
*** 330,343 ****
  {
    int fControlKey = Event->xkey.state & ControlMask? TRUE : FALSE;
    int fShiftedKey = Event->xkey.state & ShiftMask? TRUE: FALSE;
!   KeySym keysym = XLookupKeysym(&Event->xkey,0);
    MenuItem *newItem;
    MenuItem *miCurrent = pmiCurrent?*pmiCurrent:NULL;
    int index;
    /* Is it okay to treat keysym-s as Ascii? */
! 
    /* Try to match hot keys */
!   if (isgraph(keysym) && fControlKey == FALSE) { 
      /* allow any printable character to be a keysym, but be sure control
         isn't pressed */
      MenuItem *mi;
--- 331,346 ----
  {
    int fControlKey = Event->xkey.state & ControlMask? TRUE : FALSE;
    int fShiftedKey = Event->xkey.state & ShiftMask? TRUE: FALSE;
!   KeySym keysym;
!   char keychar;
    MenuItem *newItem;
    MenuItem *miCurrent = pmiCurrent?*pmiCurrent:NULL;
    int index;
    /* Is it okay to treat keysym-s as Ascii? */
!   /* No, because the keypad numbers don't work. Use XlookupString */
!   index = XLookupString(Event, &keychar, 1, &keysym, NULL);
    /* Try to match hot keys */
!   if (index == 1 && isgraph((int)keychar) && fControlKey == FALSE) { 
      /* allow any printable character to be a keysym, but be sure control
         isn't pressed */
      MenuItem *mi;
***************
*** 345,351 ****
      /* Search menu for matching hotkey */
      for (mi = menu->first; mi; mi = mi->next) {
        key = tolower(mi->chHotkey);
!       if (keysym == key) {
  	*pmiCurrent = mi;
  	if (IS_POPUP_MENU_ITEM(mi))
  	  return MENU_POPUP;
--- 348,354 ----
      /* Search menu for matching hotkey */
      for (mi = menu->first; mi; mi = mi->next) {
        key = tolower(mi->chHotkey);
!       if (keychar == key) {
  	*pmiCurrent = mi;
  	if (IS_POPUP_MENU_ITEM(mi))
  	  return MENU_POPUP;

---

From: Greg Badros <[email-masked]>
Date: 10 Sep 1998 08:12:22 -0700

Tim Phipps <[email-masked]> writes:

> This is a multi-part message in MIME format.
> --------------8C22EAAB7BEA2E7E7C337A56
> Content-Type: text/plain; charset=us-ascii
> Content-Transfer-Encoding: 7bit
> 

Both of these changes are nice.  I should've done both of these things
as you now do.  Good!

Greg