feat(tazjin/emacs): dynamically assign EXWM workspaces to monitors

Adds an `exwm-assign-workspaces` function that automatically creates
and assigns workspaces to each currently connected monitor. The first
workspace (index 0) is always on the primary monitor.

This function should be idempotent and can be called at any point to
synchronise X outputs and what EXWM is displaying on them.

This works because tabs are disconnected from workspaces completely,
so I don't have to care about what's going on on other workspaces
anymore.

Still missing:

* functions to connect/disconnect outputs
* switching to other outputs from within emacs commands (i.e. without
  the mouse)

Change-Id: I7c24aa1b45218fe35de6939e799852b5d11d1272
Reviewed-on: https://cl.tvl.fyi/c/depot/+/10119
Reviewed-by: tazjin <tazjin@tvl.su>
Autosubmit: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
This commit is contained in:
Vincent Ambo 2023-11-25 16:01:31 +03:00 committed by clbot
parent b457217844
commit 683c8bade3

View file

@ -4,7 +4,6 @@
;; window-management (EXWM) as well as additional system-wide
;; commands.
(require 'dash)
(require 'exwm)
(require 'exwm-config)
(require 'exwm-randr)
@ -13,6 +12,7 @@
(require 'f)
(require 'ring)
(require 's)
(require 'seq)
(defcustom tazjin--screen-lock-command "tazjin-screen-lock"
"Command to execute for locking the screen."
@ -109,6 +109,7 @@
(fringe-mode 3)
(exwm-enable)
(exwm-randr-enable)
;; Create 10 EXWM workspaces
(setq exwm-workspace-number 10)
@ -251,7 +252,41 @@ ring."
;; enable display of X11 system tray within Emacs
(exwm-systemtray-enable)
;; Configure xrandr (multi-monitor setup).
;; Multi-monitor configuration.
;;
;; With tab-bar-mode, each monitor only displays at most one
;; workspace. Workspaces are only created, never deleted, meaning that
;; the number of workspaces will be equivalent to the maximum number
;; of displays that were connected during a session.
;;
;; The first workspace is special: It is kept on the primary monitor.
(defun exwm-assign-workspaces ()
"Assigns workspaces to the currently existing monitors, putting
the first one on the primary display and allocating the others
dynamically if needed in no particular order."
(interactive)
(let* ((randr-monitors (exwm-randr--get-monitors))
(primary (car randr-monitors))
(all-monitors (seq-map #'car (cadr randr-monitors)))
(sorted-primary-first (seq-sort (lambda (a b)
(or (equal a primary)
(< a b)))
all-monitors))
;; assign workspace numbers to each monitor ...
(workspace-assignments
(flatten-list (seq-map-indexed (lambda (monitor idx)
(list idx monitor))
sorted-primary-first))))
;; ensure that the required workspaces exist
(exwm-workspace-switch-create (- (seq-length all-monitors) 1))
;; update randr config
(setq exwm-randr-workspace-monitor-plist workspace-assignments)
(exwm-randr-refresh)
;; leave focus on primary workspace
(exwm-workspace-switch 0)))
(defun set-randr-config (screens)
(setq exwm-randr-workspace-monitor-plist