Subject: Idea for windowlist handling

From: Jochen Klenner <[email-masked]>
Date: Tue, 26 Mar 2002 02:14:30 +0100 (MET)

Hi,

recently I did some Fvwm (version 2.4.6) hacking concerning the
maintenance of the window order. The basic idea is: always keep the
windowlist in most recently focused order. This is already the case if you
only use the mouse and the FlipFocus command for focusing. But it is nice
to have a command to cycle through the windows. Something like:

Key F11 A M Next (*) Focus

Note that we can also make up functions that don't cycle through all
windows, but only through a certain subset. E. g. all xterms, all Netscape
windows and so on. See the description of AddToFunc in the Fvwm man page
for an example.

This doesn't work with FlipFocus, but the Focus command spoils the
most-recently-focused order of the windowlist. Ideally, the wm should know
when we cycled to a window that we want focused, and move it to the start
of the list, in contrast to the windows we only had to 'cycle over' to get
there.

The solution I came up with: use a timeout. If a window is focused longer
then a certain amount of time, consider it 'definitely focused' and put it
to the front of the windowlist. The FvwmAuto module is an obvious solution
for this task.

To make this work, I had to do the following changes to Fvwm:

1. The focusing command must have these effects:
Mouse and FlipFocus: put window to front of windowlist
    OK, it works already like this.
Focus: don't alter the internal windowlist at all
    This was not the case, instead the newly focused window was rotated to
    front of the list. I eliminated this rotation (in function DoSetFocus
    in focus.c). This doesn't seem to have any bad effects (The displayed
    windowlist starts with the focused window anyway).

2. I invented a new command "ReshuffleWindows". It puts the window to
the front of the internal window list, just as FlipFocus does. In
contrast to FlipFocus it works on already focused windows.

Now I can write into .fvwm2rc:

Module FvwmAuto 2500 "Silent Current (*) ReshuffleWindows"

and I can use a key combination to cycle through the windows (via a "Next
[...] Focus" command) without altering the window order. Only when I stay
at a window for more than 2.5 seconds it becomes No. 1 in the window list.

Attached, please, find the patch. It affects the files focus.c, command.h,
functions.c and functions.h.

Any comments are welcome. I'm not a Fvwm hacking expert, so I hope I
haven't screwed anything up. Feel free to use the code anyway you like.

Another idea: if we use MouseFocus (I don't), shouldn't we apply the same
strategy ? I. e., if we touch a window only briefly, it is not placed at
the top of the windowlist. But those are just some thoughts for future
develpments.

By the way, I also made a somewhat related, but independent patch for the
display of the windowlist. I'll put that into a separate mail.

Best regards

Jochen
diff -u -x *.o -x fvwm2 -x windowlist.c ../fvwm-2.4.6/fvwm/commands.h fvwm/commands.h
--- ../fvwm-2.4.6/fvwm/commands.h	Wed Mar  6 19:24:03 2002
+++ fvwm/commands.h	Tue Mar 12 20:01:47 2002
@@ -133,6 +133,7 @@
 void CMD_Refresh(F_CMD_ARGS);
 void CMD_RefreshWindow(F_CMD_ARGS);
 void CMD_Repeat(F_CMD_ARGS);
+void CMD_ReshuffleWindows(F_CMD_ARGS);
 void CMD_Resize(F_CMD_ARGS);
 void CMD_ResizeMove(F_CMD_ARGS);
 void CMD_Restart(F_CMD_ARGS);
diff -u -x *.o -x fvwm2 -x windowlist.c ../fvwm-2.4.6/fvwm/focus.c fvwm/focus.c
--- ../fvwm-2.4.6/fvwm/focus.c	Tue Jan  1 16:16:15 2002
+++ fvwm/focus.c	Tue Mar 12 22:15:38 2002
@@ -58,6 +58,28 @@
 	  !(tmp_win->wmhints->flags & InputHint) || tmp_win->wmhints->input);
 }
 
+/*****************************************************************
+ *
+ * Puts the window to the start of the windowlist.
+ *
+ *****************************************************************/ 
+static void Reshuffle_windows(FvwmWindow *Fw) {
+  /* Watch out: Fw may not be on the windowlist and the windowlist may be
+   * empty */
+  /* remove Fw from list */
+  if (Fw->prev)
+    Fw->prev->next = Fw->next;
+  if (Fw->next)
+    Fw->next->prev = Fw->prev;
+  
+  /* insert Fw at start */
+  Fw->next = Scr.FvwmRoot.next;
+  if (Scr.FvwmRoot.next)
+    Scr.FvwmRoot.next->prev = Fw;
+  Scr.FvwmRoot.next = Fw;
+  Fw->prev = &Scr.FvwmRoot;
+}
+
 /********************************************************************
  *
  * Sets the input focus to the indicated window.
@@ -94,51 +116,11 @@
   }
   /* ClickToFocus focus queue manipulation - only performed for
    * Focus-by-mouse type focus events */
-  /* Watch out: Fw may not be on the windowlist and the windowlist may be
-   * empty */
   if (Fw && Fw != get_focus_window() && Fw != &Scr.FvwmRoot)
   {
     if (FocusByMouse) /* pluck window from list and deposit at top */
     {
-      /* remove Fw from list */
-      if (Fw->prev)
-	Fw->prev->next = Fw->next;
-      if (Fw->next)
-	Fw->next->prev = Fw->prev;
-
-      /* insert Fw at start */
-      Fw->next = Scr.FvwmRoot.next;
-      if (Scr.FvwmRoot.next)
-	Scr.FvwmRoot.next->prev = Fw;
-      Scr.FvwmRoot.next = Fw;
-      Fw->prev = &Scr.FvwmRoot;
-    }
-    else
-    {
-      /* move the windowlist around so that Fw is at the top */
-      FvwmWindow *tmp_win;
-
-      /* find the window on the windowlist */
-      tmp_win = &Scr.FvwmRoot;
-      while (tmp_win && tmp_win != Fw)
-        tmp_win = tmp_win->next;
-
-      if (tmp_win) /* the window is on the (non-zero length) windowlist */
-      {
-        /* make tmp_win point to the last window on the list */
-        while (tmp_win->next)
-          tmp_win = tmp_win->next;
-
-        /* close the ends of the windowlist */
-        tmp_win->next = Scr.FvwmRoot.next;
-        Scr.FvwmRoot.next->prev = tmp_win;
-
-        /* make Fw the new start of the list */
-        Scr.FvwmRoot.next = Fw;
-        /* open the closed loop windowlist */
-        Fw->prev->next = NULL;
-        Fw->prev = &Scr.FvwmRoot;
-      }
+      Reshuffle_windows(Fw);
     }
   }
   lastFocusType = FocusByMouse;
@@ -554,6 +536,14 @@
     return;
 
   FocusOn(tmp_win, FALSE, action);
+}
+
+void CMD_ReshuffleWindows(F_CMD_ARGS)
+{
+  if (DeferExecution(eventp,&w,&tmp_win,&context,CRS_SELECT,ButtonRelease))
+    return;
+
+  Reshuffle_windows(tmp_win);
 }
 
 void CMD_WarpToWindow(F_CMD_ARGS)
diff -u -x *.o -x fvwm2 -x windowlist.c ../fvwm-2.4.6/fvwm/functions.c fvwm/functions.c
--- ../fvwm-2.4.6/fvwm/functions.c	Wed Mar  6 19:24:03 2002
+++ fvwm/functions.c	Tue Mar 12 20:01:45 2002
@@ -208,6 +208,8 @@
   CMD_ENTRY("refresh", CMD_Refresh, F_REFRESH, 0),
   CMD_ENTRY("refreshwindow", CMD_RefreshWindow, F_REFRESH, FUNC_NEEDS_WINDOW),
   CMD_ENTRY(PRE_REPEAT, CMD_Repeat, F_REPEAT, FUNC_DONT_REPEAT),
+  CMD_ENTRY("reshufflewindows", CMD_ReshuffleWindows, F_RESHUFFLE_WINDOWS,
+	    FUNC_NEEDS_WINDOW),
   CMD_ENTRY("resize", CMD_Resize, F_RESIZE, FUNC_NEEDS_WINDOW),
   CMD_ENTRY("resizemove", CMD_ResizeMove, F_RESIZEMOVE, FUNC_NEEDS_WINDOW),
   CMD_ENTRY("restart", CMD_Restart, F_RESTART, 0),
diff -u -x *.o -x fvwm2 -x windowlist.c ../fvwm-2.4.6/fvwm/functions.h fvwm/functions.h
--- ../fvwm-2.4.6/fvwm/functions.h	Wed Mar  6 19:24:03 2002
+++ fvwm/functions.h	Tue Mar 12 20:01:44 2002
@@ -217,6 +217,7 @@
   F_PLACEAGAIN,
   F_RAISE,
   F_RAISELOWER,
+  F_RESHUFFLE_WINDOWS,
   F_RESIZE,
   F_RESIZEMOVE,
   F_SEND_STRING,