‘The half minute which we daily devote to the winding-up of our watches is an exertion of labour almost insensible; yet, by the aid of a few wheels, its effect is spread over the whole twenty-four hours.’

Group-agnostic previous-focussed-window memory in StumpWM

Benjamin Slade

I’ve started using StumpWM’s groups (like “workspaces” in other window managers) more extensively, but this broke a behaviour I like: the ability to easily switch back to the last focussed window, because StumpWM’s “last focussed” is group-specific. So I wasn’t easily about to switch quickly back and forth between two windows that were inb different groups, which turns out to be something I frequently want to do (e.g. switch back and forth between an emacsclient frame in my “emacs” group and a Firefox instance in my “web” group).

Here’s my fix [updated with some fixes on [2025-01-27 Mon]]:

;; Global 'last focussed window'
(setf *global-ante-earlier-focussed-window* 'nil)
(setf *global-earlier-focussed-window* 'nil)
(setf *global-prev-focussed-window* 'nil)
(setf *global-cur-focussed-window* 'nil)

(defun panrecord-of-last-focussed-window (currwin lastwin)
  "Record last visited windows and their group."
  (unless (or (search "*EQUAKE*[" (window-name currwin)) ;; don't record Equake
              (equal (cons (current-window) (current-group)) *global-cur-focussed-window*))
    (when (find-window-globally
           (car *global-earlier-focussed-window*) (screen-groups (current-screen)))
      (setf *global-ante-earlier-focussed-window* *global-earlier-focussed-window*))
    (when (find-window-globally
           (car *global-prev-focussed-window*) (screen-groups (current-screen)))
      (setf *global-earlier-focussed-window* *global-prev-focussed-window*))
    (when (find-window-globally
           (car *global-cur-focussed-window*) (screen-groups (current-screen)))
      (setf *global-prev-focussed-window* *global-cur-focussed-window*))
    (setf *global-cur-focussed-window* (cons currwin (current-group)))))

(defun find-window-globally (window group-list)
  "Check for presence of window in all groups."
  (if (equal (car group-list) 'nil)
      'nil
      (if (member window (group-windows (car group-list)))
          window
          (find-window-globally window (cdr group-list)))))

(defcommand switch-to-last-focussed-window () ()
  "Switch to last focussed window, irrespective of which group it is in and what group we're currently in."
  (progn
    (if
     (and
      (not (equal *global-cur-focussed-window* *global-prev-focussed-window*))
      (or
       ;; we're in the same group [same logic below]
       (equal (car (screen-groups (current-screen)))
              (cdr *global-prev-focussed-window*))
       ;; or we can switch to the previous group
       *global-prev-focussed-window*))
     (progn
       (switch-to-group (cdr *global-prev-focussed-window*))
       (focus-window (car *global-prev-focussed-window*) t))
     (if
      (and
       (not (equal *global-cur-focussed-window* *global-earlier-focussed-window*))
       (or
        (equal (car (screen-groups (current-screen)))
               (cdr *global-earlier-focussed-window*))
        *global-earlier-focussed-window*))
      (progn
        (switch-to-group (cdr *global-earlier-focussed-window*))
        (focus-window (car *global-earlier-focussed-window*) t))
      (if
       (and
        (not (equal *global-cur-focussed-window* *global-ante-earlier-focussed-window*))
        (or
         (equal (car (screen-groups (current-screen)))
                (cdr *global-ante-earlier-focussed-window*))
         *global-ante-earlier-focussed-window*))
       (progn
         (switch-to-group (cdr *global-ante-earlier-focussed-window*))
         (focus-window (car *global-ante-earlier-focussed-window*) t))
       (message "No window to switch to."))))))

(add-hook *focus-window-hook* 'panrecord-of-last-focussed-window)

;; my binding; set as you will
(define-key *root-map* (kbd "s-f") "switch-to-last-focussed-window")

The unless statement in panrecord-of-last-focussed-window prevents my drop-down terminal Equake “window” from “counting” for history tracking purposes.

The switch-to-last-focussed-window function essentially just switches to the last focussed window, after making sure it still exists. (If not, switch to the window which was focussed before that one, or the one before that one, or else don’t switch and display message indicating this to the user.)

The last line, (define-key *root-map* (kbd "s-f") "switch-to-last-focussed-window"), means that I can double tap s-f (since my StumpWM prefix key is set to s-f with (set-prefix-key (kbd "s-f"))) to switch to the last focussed window, no matter which group it belongs to.

I continue to really enjoy the power that StumpWM’s Common Lisp underpinnings provides the user!