Support display-arrangement macro

I was tired of using `arandr` to manually configure my monitor positions, so I
encoded the settings in Elisp in the `display.el` module.

TL;DR:
- Drop support for `position` kwarg in `display-register` macro
- Support `coords` kwarg in `display-register`.
- `defconst` the `xrandr` arguments and command in `display-register`.
- Define `display-arrangement` macro that consumes the `xrandr` arguments that
  `display-register` defines to create an interactive function,
  `display-arrange-<NAME>`, which -- when invoked -- runs one xrandr command to
  configure a display "arrangement".
This commit is contained in:
William Carroll 2020-10-04 16:20:16 +01:00
parent 4187e888c8
commit f3ee628a4c

View file

@ -20,6 +20,8 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(require 'prelude) (require 'prelude)
(require 'dash)
(require 's)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Library ;; Library
@ -28,17 +30,17 @@
(cl-defmacro display-register (name &key (cl-defmacro display-register (name &key
output output
primary primary
position coords
size size
rate rate
dpi dpi
rotate) rotate)
"Macro to define a constant and two functions for {en,dis}abling a display. "Macro to define constants and two functions for {en,dis}abling a display.
NAME - the human-readable identifier for the display NAME - the human-readable identifier for the display
OUTPUT - the xrandr identifier for the display OUTPUT - the xrandr identifier for the display
PRIMARY - if true, send --primary flag to xrandr PRIMARY - if true, send --primary flag to xrandr
POSITION - one of {left-of,right-of,above,below,same-as} COORDS - X and Y offsets
SIZE - the pixel resolution of the display SIZE - the pixel resolution of the display
RATE - the refresh rate RATE - the refresh rate
DPI - the pixel density in dots per square inch DPI - the pixel density in dots per square inch
@ -48,24 +50,35 @@ See the man-page for xrandr for more details."
`(progn `(progn
(defconst ,(intern (format "display-%s" name)) ,output (defconst ,(intern (format "display-%s" name)) ,output
,(format "The xrandr identifier for %s" name)) ,(format "The xrandr identifier for %s" name))
(defconst ,(intern (format "display-%s-args" name))
,(replace-regexp-in-string
"\s+" " "
(s-format "--output ${output} ${primary-flag} --auto \
--size ${size-x}x${size-y} --rate ${rate} --dpi ${dpi} \
--rotate ${rotate} ${pos-flag}"
#'aget
`(("output" . ,output)
("primary-flag" . ,(if primary "--primary" "--noprimary"))
("pos-flag" . ,(if coords
(format "--pos %dx%d"
(car coords)
(cadr coords))
""))
("size-x" . ,(car size))
("size-y" . ,(cadr size))
("rate" . ,rate)
("dpi" . ,dpi)
("rotate" . ,rotate))))
,(format "The arguments we pass to xrandr for display-%s." name))
(defconst ,(intern (format "display-%s-command" name))
(format "xrandr %s" ,(intern (format "display-%s-args" name)))
,(format "The command we run to configure %s" name))
(defun ,(intern (format "display-enable-%s" name)) () (defun ,(intern (format "display-enable-%s" name)) ()
,(format "Attempt to enable my %s monitor" name) ,(format "Attempt to enable my %s monitor" name)
(interactive) (interactive)
(prelude-start-process (prelude-start-process
:name ,(format "display-enable-%s" name) :name ,(format "display-enable-%s" name)
:command ,(format :command ,(intern (format "display-%s-command" name))))
"xrandr --output %s --%s %s --auto --size %dx%d --rate %0.2f --dpi %d --rotate %s"
output
(if primary "primary" "noprimary")
(if position
(format "--%s %s"
(car position)
(eval (cadr position)))
"")
(car size) (cadr size)
rate
dpi
rotate)))
(defun ,(intern (format "display-disable-%s" name)) () (defun ,(intern (format "display-disable-%s" name)) ()
,(format "Attempt to disable my %s monitor." name) ,(format "Attempt to disable my %s monitor." name)
(interactive) (interactive)
@ -75,8 +88,22 @@ See the man-page for xrandr for more details."
"xrandr --output %s --off" "xrandr --output %s --off"
output))))) output)))))
;; I'm omitting the position argument to avoid a circular dependency between (defmacro display-arrangement (name &key displays)
;; laptop and 4k-horizontal. "Create a function, display-arrange-<NAME>, to enable all your DISPLAYS."
`(defun ,(intern (format "display-arrange-%s" name)) ()
(interactive)
(prelude-start-process
:name ,(format "display-configure-%s" name)
:command ,(format "xrandr %s"
(->> displays
(-map (lambda (x)
(eval (intern (format "display-%s-args" x)))))
(s-join " "))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Configuration
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(display-register laptop (display-register laptop
:output "eDP1" :output "eDP1"
:primary nil :primary nil
@ -88,7 +115,7 @@ See the man-page for xrandr for more details."
(display-register 4k-horizontal (display-register 4k-horizontal
:output "HDMI1" :output "HDMI1"
:primary t :primary t
:position (above display-laptop) :coords (0 1062)
:size (3840 2160) :size (3840 2160)
:rate 30.0 :rate 30.0
:dpi 144 :dpi 144
@ -97,11 +124,14 @@ See the man-page for xrandr for more details."
(display-register 4k-vertical (display-register 4k-vertical
:output "DP2" :output "DP2"
:primary nil :primary nil
:position (right-of display-4k-horizontal) :coords (3840 0)
:size (3840 2160) :size (3840 2160)
:rate 30.0 :rate 30.0
:dpi 144 :dpi 144
:rotate right) :rotate right)
(display-arrangement primary
:displays (4k-horizontal 4k-vertical))
(provide 'display) (provide 'display)
;;; display.el ends here ;;; display.el ends here