Posframe Multi-head Awareness in EXWM

Hello, all! I’ve finally found a good reason to create my first post! Recently, I’ve decided to plunge into EXWM because I can’t handle being out of Emacs, even for a second… Lol.

Initially, I felt pretty good until I saw my corfu auto-completion appear on my primary monitor, regardless of which monitor was selected. Additionally, I use a package, vertico-posframe, which moves Vertico completion to a posframe in the center of your screen. After putting the dots together that the posframe wasn’t correctly aligned based on the selected monitor, I decided to fix that.

Below are the fruits of my effort:

Helper function:

(defun get-focused-monitor-geometry ()

"Get the geometry of the monitor displaying the selected frame in EXWM."

(let* ((monitor-attrs (frame-monitor-attributes))

(workarea (assoc 'workarea monitor-attrs))

(geometry (cdr workarea)))

(list (nth 0 geometry) ; X

(nth 1 geometry) ; Y

(nth 2 geometry) ; Width

(nth 3 geometry) ; Height

)))

Corfu:

(defun advise-corfu-make-frame-with-monitor-awareness (orig-fun frame x y width height buffer)

"Advise `corfu--make-frame` to be monitor-aware, adjusting X and Y according to the focused monitor."

;; Get the geometry of the currently focused monitor

(let* ((monitor-geometry (get-focused-monitor-geometry))

(monitor-x (nth 0 monitor-geometry))

(monitor-y (nth 1 monitor-geometry))

;; You may want to adjust the logic below if you have specific preferences

;; on where on the monitor the posframe should appear.

;; Currently, it places the posframe at its intended X and Y, but ensures

;; it's within the bounds of the focused monitor.

(new-x (+ monitor-x x))

(new-y (+ monitor-y y)))

;; Call the original function with potentially adjusted coordinates

(funcall orig-fun frame new-x new-y width height buffer)))

(advice-add 'corfu--make-frame :around #'advise-corfu-make-frame-with-monitor-awareness)

Vertico Posframe:

(defun advise-vertico-posframe-show-with-monitor-awareness (orig-fun buffer window-point &rest args)

"Advise `vertico-posframe--show` to position the posframe according to the focused monitor."

;; Extract the focused monitor's geometry

(let* ((monitor-geometry (get-focused-monitor-geometry))

(monitor-x (nth 0 monitor-geometry))

(monitor-y (nth 1 monitor-geometry)))

;; Override poshandler buffer-local variable to use monitor-aware positioning

(let ((vertico-posframe-poshandler

(lambda (info)

(let* ((parent-frame-width (plist-get info :parent-frame-width))

(parent-frame-height (plist-get info :parent-frame-height))

(posframe-width (plist-get info :posframe-width))

(posframe-height (plist-get info :posframe-height))

;; Calculate center position on the focused monitor

(x (+ monitor-x (/ (- parent-frame-width posframe-width) 2)))

(y (+ monitor-y (/ (- parent-frame-height posframe-height) 2))))

(cons x y)))))

;; Call the original function with potentially adjusted poshandler

(apply orig-fun buffer window-point args))))

(advice-add 'vertico-posframe--show :around #'advise-vertico-posframe-show-with-monitor-awareness)

Hopefully, my code is self-explanatory and as helpful for everyone else, as it is for me; I haven’t been writing Elisp for more than three months, so any critiques on anything would be welcome!

1 Like