about summary refs log tree commit diff
path: root/emacs/.emacs.d/wpc/display.el
blob: 3507f11915f6d67c0b6e08c24b0a9f60c2e7a23e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
;;; display.el --- Working with single or multiple displays -*- lexical-binding: t -*-

;; Author: William Carroll <wpcarro@gmail.com>
;; Version: 0.0.1
;; URL: https://git.wpcarro.dev/wpcarro/briefcase
;; Package-Requires: ((emacs "24"))

;;; Commentary:
;; Mostly wrappers around xrandr.
;;
;; Troubleshooting:
;; The following commands help me when I (infrequently) interact with xrandr.
;; - xrandr --listmonitors
;; - xrandr --query

;;; Code:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Dependencies
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(require 'prelude)
(require 'dash)
(require 's)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Library
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(cl-defmacro display-register (name &key
                                    output
                                    primary
                                    coords
                                    size
                                    rate
                                    dpi
                                    rotate)
  "Macro to define constants and two functions for {en,dis}abling a display.

NAME    - the human-readable identifier for the display
OUTPUT  - the xrandr identifier for the display
PRIMARY - if true, send --primary flag to xrandr
COORDS  - X and Y offsets
SIZE    - the pixel resolution of the display
RATE    - the refresh rate
DPI     - the pixel density in dots per square inch
rotate  - one of {normal,left,right,inverted}

See the man-page for xrandr for more details."
  `(progn
     (defconst ,(intern (format "display-%s" name)) ,output
       ,(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)) ()
       ,(format "Attempt to enable my %s monitor" name)
       (interactive)
       (prelude-start-process
        :name ,(format "display-enable-%s" name)
        :command ,(intern (format "display-%s-command" name))))
     (defun ,(intern (format "display-disable-%s" name)) ()
       ,(format "Attempt to disable my %s monitor." name)
       (interactive)
       (prelude-start-process
        :name ,(format "display-disable-%s" name)
        :command ,(format
                   "xrandr --output %s --off"
                   output)))))

(defmacro display-arrangement (name &key displays)
  "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
                  :output "eDP1"
                  :primary nil
                  :size (3840 2160)
                  :rate 30.0
                  :dpi 144
                  :rotate normal)

(display-register 4k-horizontal
                  :output "HDMI1"
                  :primary t
                  :coords (0 1062)
                  :size (3840 2160)
                  :rate 30.0
                  :dpi 144
                  :rotate normal)

(display-register 4k-vertical
                  :output "DP2"
                  :primary nil
                  :coords (3840 0)
                  :size (3840 2160)
                  :rate 30.0
                  :dpi 144
                  :rotate right)

(display-arrangement primary
                     :displays (4k-horizontal 4k-vertical))

(provide 'display)
;;; display.el ends here