Emacs window navigation stumpsom integration

This commit is contained in:
Ian Keane 2026-09-05 20:54:09 -04:00
parent 20bcc0d97f
commit a64efec920
2 changed files with 56 additions and 4 deletions

View file

@ -462,10 +462,23 @@ If PERSISTENT is t, smart-kill will hide the window instead of killing it."
;;; Top-level bindings
(define-key *top-map* (kbd "s-d") "rofi-run")
(define-key *top-map* (kbd "s-w") "rofi-pull-window")
(define-key *top-map* (kbd "s-h") "move-focus left")
(define-key *top-map* (kbd "s-j") "move-focus down")
(define-key *top-map* (kbd "s-k") "move-focus up")
(define-key *top-map* (kbd "s-l") "move-focus right")
(defun emacs-window-p (win)
(and win (string= (window-class win) "Emacs")))
(defcommand smart-move-focus (direction) ((:direction "Direction: "))
"If the focused window is Emacs and it has a window in DIRECTION, move
focus there via windmove. Otherwise move focus to the next StumpWM frame."
(if (and (emacs-window-p (current-window))
(search "t" (run-shell-command
(format nil "emacsclient -e '(if (ignore-errors (windmove-~(~a~) nil) t) t nil)'" direction)
t)))
nil
(move-focus direction)))
(define-key *top-map* (kbd "s-h") "smart-move-focus left")
(define-key *top-map* (kbd "s-j") "smart-move-focus down")
(define-key *top-map* (kbd "s-k") "smart-move-focus up")
(define-key *top-map* (kbd "s-l") "smart-move-focus right")
(define-key *top-map* (kbd "s-p") "next-in-frame")
(define-key *top-map* (kbd "s-n") "prev-in-frame")
(define-key *top-map* (kbd "s-q") "smart-kill")

View file

@ -428,6 +428,45 @@ at the tab level rather than with a dedicated workspace package.
(ace-window arg)
))
#+end_src
*** StumpWM-aware window navigation
=s-h/j/k/l= (mod+hjkl) move between Emacs windows using =windmove=. When
there's no further Emacs window in that direction (i.e. we're at the edge of
Emacs's frame), the command instead shells out to StumpWM via =stumpish= to
move focus to the next tiled frame in that direction — so navigation flows
seamlessly out of Emacs and into the rest of the WM using the same keys
StumpWM itself binds to =s-h/j/k/l=.
#+begin_src emacs-lisp
(defvar stumpwm-stumpish-path
(expand-file-name "~/.stumpwm.d/modules/util/stumpish/stumpish")
"Path to the stumpish binary used to talk to a running StumpWM.")
(defun stumpwm-move-focus (direction)
"Ask StumpWM to move focus to the frame in DIRECTION (\"left\" \"right\" \"up\" \"down\").
No-op on macOS (or anywhere StumpWM isn't running/available)."
(when (and (not IS-MACOS)
(file-executable-p stumpwm-stumpish-path))
(call-process stumpwm-stumpish-path nil nil nil
(concat "move-focus " direction))))
(defun stumpwm-windmove-or-escape (windmove-fn direction)
"Call WINDMOVE-FN; if it errors (no Emacs window in DIRECTION),
fall through to StumpWM and move focus to the next tiled frame there."
(condition-case nil
(funcall windmove-fn)
(error (stumpwm-move-focus direction))))
(defun stumpwm-windmove-left () (interactive) (stumpwm-windmove-or-escape #'windmove-left "left"))
(defun stumpwm-windmove-right () (interactive) (stumpwm-windmove-or-escape #'windmove-right "right"))
(defun stumpwm-windmove-up () (interactive) (stumpwm-windmove-or-escape #'windmove-up "up"))
(defun stumpwm-windmove-down () (interactive) (stumpwm-windmove-or-escape #'windmove-down "down"))
(global-set-key (kbd "s-h") #'stumpwm-windmove-left)
(global-set-key (kbd "s-j") #'stumpwm-windmove-down)
(global-set-key (kbd "s-k") #'stumpwm-windmove-up)
(global-set-key (kbd "s-l") #'stumpwm-windmove-right)
#+end_src
** Popper
Transient/popup buffers — terminals, help, compilation, messages — are managed
by popper, which tracks them as a group and lets you cycle or dismiss them