├── .Xmodmap.exwm ├── .emacs.d ├── config.org ├── early-init.el └── init.el ├── .profile ├── .xinitrc.exwm ├── .xinitrc.exwm_gnome ├── COPYING ├── README.org ├── announcement.txt ├── exwm_screen_layout ├── exwm_xrandr.bash └── set_xmodmap.sh /.Xmodmap.exwm: -------------------------------------------------------------------------------- 1 | keycode 66 = Hyper_R 2 | clear Lock 3 | add mod3 = Hyper_R 4 | -------------------------------------------------------------------------------- /.emacs.d/config.org: -------------------------------------------------------------------------------- 1 | #+STARTUP: overview 2 | #+TITLE: An emacs init that supports EXWM 3 | #+CREATOR: Johan Widén 4 | #+LANGUAGE: en 5 | #+OPTIONS: num:nil 6 | #+ATTR_HTML: :style margin-left: auto; margin-right: auto; 7 | 8 | * Bootstrap 9 | :PROPERTIES: 10 | :ID: 1752e376-1433-45b1-9506-a0824d22974b 11 | :END: 12 | ** Emacs lisp preferences 13 | :PROPERTIES: 14 | :ID: b4e0f009-f406-463d-a6cb-e88ac9aa3cb0 15 | :END: 16 | If a .el file is newer than a .elc file, then use the .el file. 17 | Also try to ensure that .elc files are up to date. 18 | #+BEGIN_SRC emacs-lisp 19 | (setq load-prefer-newer t) 20 | (use-package auto-compile 21 | :ensure t 22 | :config 23 | (auto-compile-on-load-mode 1) 24 | (auto-compile-on-save-mode 1)) 25 | #+END_SRC 26 | ** Use better defaults, also see lolsmacs below 27 | :PROPERTIES: 28 | :ID: f28e55e3-89b4-4fb8-859b-1e64d4dc8077 29 | :END: 30 | Always, always, prefer UTF-8 31 | #+BEGIN_SRC emacs-lisp 32 | (set-charset-priority 'unicode) 33 | (set-default-coding-systems 'utf-8) 34 | (set-terminal-coding-system 'utf-8) 35 | (set-keyboard-coding-system 'utf-8) 36 | (set-selection-coding-system 'utf-8) 37 | (set-language-environment "UTF-8") 38 | (prefer-coding-system 'utf-8) 39 | (setq default-process-coding-system '(utf-8-unix . utf-8-unix)) 40 | ;; Treat clipboard input as UTF-8 string first; compound text next, etc. 41 | (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING)) 42 | #+END_SRC 43 | 44 | Inhibit startup message. 45 | Do not ask for confirmation about killing processes, when exiting emacs. 46 | #+BEGIN_SRC emacs-lisp 47 | (setq inhibit-startup-message t) 48 | (setq confirm-kill-processes nil) 49 | (setq-default 50 | help-window-select t ;; Focus new help windows when opened 51 | debug-on-error t 52 | indent-tabs-mode nil ;; Adjust indent using 'space', not 'tab' 53 | jit-lock-defer-time 0 ;; Defer fontification while there is input pending 54 | window-combination-resize t ;; Resize windows proportionally 55 | history-delete-duplicates t 56 | ) 57 | #+END_SRC 58 | 59 | Save recent files list periodically, when emacs has been idle for a while, 60 | because it will otherwise not be saved when emacs runs in server mode. 61 | #+BEGIN_SRC emacs-lisp 62 | (run-with-idle-timer 600 t (lambda () 63 | (let ((save-silently t)) 64 | (recentf-save-list)))) 65 | #+END_SRC 66 | 67 | Some UI elements are rather invasive. 68 | #+BEGIN_SRC emacs-lisp :results silent 69 | (when window-system 70 | (blink-cursor-mode 0) ;; Disable the cursor blinking 71 | (scroll-bar-mode 0) ;; Disable the scroll bar 72 | (tool-bar-mode 0) ;; Disable the tool bar 73 | ;; (tooltip-mode 0) ;; Disable the tooltips 74 | ) 75 | #+END_SRC 76 | 77 | ** Enable emacs server 78 | :PROPERTIES: 79 | :ID: b00ca6e7-4444-4a1e-9e51-7ecfed4dc150 80 | :END: 81 | #+BEGIN_SRC emacs-lisp 82 | (server-start) 83 | #+END_SRC 84 | ** Load =.custom.el= 85 | :PROPERTIES: 86 | :ID: 3e99756d-1e4a-4d9f-9fad-fd49a3b18496 87 | :END: 88 | One is able to use the customization interface that is bundled within Emacs. It 89 | is meant to help people who are not familiar with Emacs Lisp in the 90 | configuration of Emacs itself. By default, changes in the customization will be 91 | automatically detected and appended at the end of the configuration file, 92 | =init.el=. 93 | 94 | Since that in my case, the actual configuration file is a new one, crafted by 95 | =org-mode=, adding code at the end of =init.el= might mess things up. The 96 | following tells Emacs to add extra code in another file that would then be 97 | loaded, if existing. 98 | 99 | #+BEGIN_SRC emacs-lisp :results silent 100 | (setq-default custom-file (expand-file-name ".custom.el" user-emacs-directory)) 101 | (when (file-exists-p custom-file) 102 | (load custom-file)) 103 | #+END_SRC 104 | 105 | ** Load =.secret.el= 106 | :PROPERTIES: 107 | :ID: 87374bd4-ba9c-4fb5-ba5f-9ffbde7ca88e 108 | :END: 109 | 110 | I load =~/.emacs.d/.secret.el= to keep sensible things out of version control. 111 | For instance, you could set your identity by customizing both =user-full-name= 112 | and =user-mail-address=. This is also where you want your API tokens to live. 113 | 114 | #+BEGIN_SRC emacs-lisp :results silent 115 | (defvar me/erc-nick nil "The ERC nick to use.") 116 | (defvar me/erc-password nil "The ERC password to use.") 117 | (defvar me/erc-port nil "The ERC port to use.") 118 | (defvar me/erc-server nil "The ERC server to use.") 119 | (defvar me/font-family "Courier" "The font to use.") 120 | (defvar me/font-size-default 110 "The font size to use for default text.") 121 | (defvar me/font-size-large 1.2 "The font size to use for larger text.") 122 | (defvar me/font-size-small 0.8 "The font size to use for smaller text.") 123 | 124 | (let ((secret.el (expand-file-name ".secret.el" user-emacs-directory))) 125 | (when (file-exists-p secret.el) 126 | (load secret.el))) 127 | #+END_SRC 128 | ** Packages that are needed later on 129 | :PROPERTIES: 130 | :ID: 61f8b23a-9253-47fb-94eb-dca7e5a59a90 131 | :END: 132 | *** bind-key 133 | :PROPERTIES: 134 | :ID: b0ebcd29-5dac-4806-ab26-55975b513478 135 | :END: 136 | Key binding support 137 | #+BEGIN_SRC emacs-lisp 138 | (use-package bind-key 139 | :ensure t) 140 | #+END_SRC 141 | *** straight package manager 142 | :PROPERTIES: 143 | :ID: 5375a4d2-a4df-48fb-a656-c98cf1ef217a 144 | :END: 145 | straight will be used to load some elisp packages from github. 146 | #+BEGIN_SRC emacs-lisp 147 | (defvar bootstrap-version) 148 | (let ((bootstrap-file 149 | (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) 150 | (bootstrap-version 5)) 151 | (unless (file-exists-p bootstrap-file) 152 | (with-current-buffer 153 | (url-retrieve-synchronously 154 | "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" 155 | 'silent 'inhibit-cookies) 156 | (goto-char (point-max)) 157 | (eval-print-last-sexp))) 158 | (load bootstrap-file nil 'nomessage)) 159 | #+END_SRC 160 | 161 | ** lolsmacs (Law Of Least Surprise), better emacs defaults 162 | :PROPERTIES: 163 | :ID: 44ccc326-1a58-4fab-a205-97db41a51eec 164 | :END: 165 | #+BEGIN_SRC emacs-lisp 166 | (use-package lolsmacs 167 | :straight (:host github 168 | :repo "grettke/lolsmacs" 169 | :files ("*.el")) 170 | ) 171 | (require 'lolsmacs) 172 | (lolsmacs-init) 173 | #+END_SRC 174 | 175 | ** cl 176 | :PROPERTIES: 177 | :ID: 6d5cb1dc-8428-4c29-aff6-13c9dbd6a576 178 | :END: 179 | Used by some package below. 180 | #+BEGIN_SRC emacs-lisp 181 | (require 'cl-seq) 182 | #+END_SRC 183 | * Theme 184 | :PROPERTIES: 185 | :ID: 81a815d6-cfca-4851-a440-4d79887be6cb 186 | :END: 187 | Load the theme 188 | #+BEGIN_SRC emacs-lisp 189 | (use-package modus-vivendi-theme 190 | :ensure t) 191 | (load-theme 'modus-vivendi t) ;; Dark theme 192 | #+END_SRC 193 | * helpful 194 | :PROPERTIES: 195 | :ID: 721bd336-078f-4914-b46f-c3f718542df5 196 | :END: 197 | #+BEGIN_SRC emacs-lisp 198 | (use-package helpful 199 | :ensure t 200 | :config 201 | ;; Note that the built-in `describe-function' includes both functions 202 | ;; and macros. `helpful-function' is functions only, so we provide 203 | ;; `helpful-callable' as a drop-in replacement. 204 | (global-set-key (kbd "C-h f") #'helpful-callable) 205 | 206 | (global-set-key (kbd "C-h v") #'helpful-variable) 207 | (global-set-key (kbd "C-h k") #'helpful-key) 208 | 209 | ;; Lookup the current symbol at point. C-c C-d is a common keybinding 210 | ;; for this in lisp modes. 211 | (global-set-key (kbd "C-c C-d") #'helpful-at-point) 212 | 213 | ;; Look up *F*unctions (excludes macros). 214 | ;; 215 | ;; By default, C-h F is bound to `Info-goto-emacs-command-node'. Helpful 216 | ;; already links to the manual, if a function is referenced there. 217 | (global-set-key (kbd "C-h F") #'helpful-function) 218 | 219 | ;; Look up *C*ommands. 220 | ;; 221 | ;; By default, C-h C is bound to describe `describe-coding-system'. I 222 | ;; don't find this very useful, but it's frequently useful to only 223 | ;; look at interactive functions. 224 | (global-set-key (kbd "C-h C") #'helpful-command) 225 | ) 226 | #+END_SRC 227 | * Ivy, swiper 228 | :PROPERTIES: 229 | :ID: f13d136b-74a0-4813-a537-40efdb664b30 230 | :END: 231 | Note that when searching with swiper, the following work: 232 | C-s C-s redo last search 233 | M-n ivy-next-history-element 234 | M-j ivy-yank-word 235 | #+BEGIN_SRC emacs-lisp 236 | (require 'shell) 237 | (use-package swiper 238 | :ensure t) 239 | (use-package ivy 240 | :ensure t 241 | :init 242 | (progn 243 | (ivy-mode 1) 244 | (setq ivy-use-virtual-buffers t) 245 | (global-set-key (kbd "C-s") 'swiper) 246 | (define-key minibuffer-local-map (kbd "C-r") 'counsel-minibuffer-history) 247 | (define-key shell-mode-map (kbd "C-r") 'counsel-shell-history))) 248 | (use-package ivy-hydra 249 | :ensure t 250 | ) 251 | #+END_SRC 252 | * Helm 253 | :PROPERTIES: 254 | :ID: 1063bbed-cf80-477c-bda5-b3f5d8862e8c 255 | :END: 256 | Use helm for completion. 257 | Note that the key bindings for and C-z are switched. Comment out if you do not like that. 258 | #+BEGIN_SRC emacs-lisp 259 | (use-package helm 260 | :ensure t 261 | :init 262 | (progn 263 | (require 'helm-config) 264 | (require 'helm-grep) 265 | ;; To fix error at compile: 266 | ;; Error (bytecomp): Forgot to expand macro with-helm-buffer in 267 | ;; (with-helm-buffer helm-echo-input-in-header-line) 268 | (if (version< "26.0.50" emacs-version) 269 | (eval-when-compile (require 'helm-lib))) 270 | (global-set-key (kbd "C-x b") 'helm-mini) 271 | 272 | (define-key helm-map (kbd "") 'helm-execute-persistent-action) ;; rebind tab to do persistent action 273 | (define-key helm-map (kbd "C-i") 'helm-execute-persistent-action) ;; make TAB work in terminal 274 | (define-key helm-map (kbd "C-z") 'helm-select-action) ;; list actions using C-z 275 | 276 | (setq helm-candidate-number-limit 150 277 | helm-split-window-in-side-p t ;; Open helm buffer inside current window, not occupy whole other window 278 | helm-ff-file-name-history-use-recentf t 279 | helm-ff-auto-update-initial-value t 280 | helm-move-to-line-cycle-in-source t ;; Move to end or beginning of source when reaching top or bottom of source. 281 | helm-buffer-skip-remote-checking t 282 | 283 | helm-mode-fuzzy-match t 284 | helm-buffers-fuzzy-matching t ;; Fuzzy matching buffer names when non-nil 285 | ;; Useful in helm-mini that lists buffers 286 | helm-M-x-fuzzy-match t 287 | helm-imenu-fuzzy-match t 288 | helm-lisp-fuzzy-completion t 289 | ;; helm-apropos-fuzzy-match t 290 | helm-buffer-skip-remote-checking t 291 | helm-locate-fuzzy-match t) 292 | 293 | (add-to-list 'helm-sources-using-default-as-input 'helm-source-man-pages) 294 | 295 | (global-set-key (kbd "C-h b") 'helm-descbinds) 296 | (global-set-key (kbd "M-x") 'helm-M-x) 297 | (global-set-key (kbd "M-y") 'helm-show-kill-ring) 298 | (global-set-key (kbd "C-x C-f") 'helm-find-files) 299 | (global-set-key (kbd "C-c r") 'helm-recentf) 300 | (global-set-key (kbd "C-h SPC") 'helm-all-mark-rings) 301 | (global-set-key (kbd "C-c h o") 'helm-occur) 302 | 303 | (global-set-key (kbd "C-c h w") 'helm-wikipedia-suggest) 304 | (global-set-key (kbd "C-c h g") 'helm-google-suggest) 305 | 306 | (global-set-key (kbd "C-c h x") 'helm-register) 307 | 308 | (define-key 'help-command (kbd "C-f") 'helm-apropos) 309 | (define-key 'help-command (kbd "r") 'helm-info-emacs) 310 | (define-key 'help-command (kbd "C-l") 'helm-locate-library) 311 | 312 | ;; use helm to list eshell history 313 | (add-hook 'eshell-mode-hook 314 | #'(lambda () 315 | (define-key eshell-mode-map (kbd "M-l") 'helm-eshell-history))) 316 | 317 | ;; Save current position to mark ring 318 | (add-hook 'helm-goto-line-before-hook 'helm-save-current-pos-to-mark-ring) 319 | 320 | ;; show minibuffer history with Helm 321 | (define-key minibuffer-local-map (kbd "M-p") 'helm-minibuffer-history) 322 | (define-key minibuffer-local-map (kbd "M-n") 'helm-minibuffer-history) 323 | 324 | (define-key global-map [remap find-tag] 'helm-etags-select) 325 | 326 | (define-key global-map [remap list-buffers] 'helm-buffers-list) 327 | 328 | (helm-mode 1) 329 | 330 | )) 331 | #+END_SRC 332 | * epg Let emacs query for gpg passwords 333 | :PROPERTIES: 334 | :ID: 6e1c784d-012c-4c85-a6c3-efcf4f96ffdb 335 | :END: 336 | Make emacs handle queries for gpg passwords. 337 | 338 | #+BEGIN_SRC emacs-lisp 339 | (setf epg-pinentry-mode 'loopback) 340 | (defun pinentry-emacs (desc prompt ok error) 341 | (let ((str (read-passwd 342 | (concat (replace-regexp-in-string "%22" "\"" 343 | (replace-regexp-in-string "%0A" "\n" desc)) prompt ": ")))) 344 | str)) 345 | #+END_SRC 346 | * exwm-randr 347 | :PROPERTIES: 348 | :ID: 0aabe0ee-8493-478f-a3c8-b638a35dd1f1 349 | :END: 350 | Support for multiple monitors, and plugging and unplugging of monitors. 351 | 352 | If you have a static setup, i.e. you will not change the screen configuration 353 | while emacs is running, then you do not need to 354 | define jw/exwm-change-screen-hook. 355 | 356 | If you are going to use more than one screen at the same time, you need to 357 | define exwm-randr-workspace-monitor-plist, and call "(exwm-randr-enable)". 358 | "(exwm-randr-enable)" must also be called if you use 359 | exwm-randr-screen-change-hook. 360 | 361 | #+BEGIN_SRC emacs-lisp 362 | (use-package exwm 363 | :ensure t) 364 | (require 'exwm-randr) 365 | (defun jw/env-list (env-string) 366 | "Return list of strings in environment variable env-string. 367 | nil if empty or undefined." 368 | (let ((env-var (getenv env-string))) 369 | (if env-var 370 | (split-string env-var) 371 | nil))) 372 | (defun jw/env-str (env-string) 373 | "Return string in environment variable env-string. 374 | nil if empty or undefined." 375 | (let ((env-var (getenv env-string))) 376 | (if (> (length env-var) 0) 377 | env-var 378 | nil))) 379 | 380 | (defun jw/build-workspace-monitor-plist (list) 381 | (let (transformed-list first second (rev-list (reverse list))) 382 | (while rev-list 383 | (setq second (car rev-list)) 384 | (setq first (string-to-number (car (cdr rev-list)))) 385 | (setq transformed-list (cons first (cons second transformed-list))) 386 | (setq rev-list (cdr (cdr rev-list))) 387 | ) 388 | transformed-list)) 389 | 390 | (defun jw/xrandr-output-list () 391 | "Return list of connected X11 screens, according to xrandr." 392 | (interactive) 393 | (let* ((xrandr-output-regexp "\n\\([^ ]+\\) connected ") 394 | (find-outputs 395 | (lambda () 396 | (let (output-list) 397 | (call-process "/usr/bin/xrandr" nil t nil) 398 | (goto-char (point-min)) 399 | (while (re-search-forward xrandr-output-regexp nil 'noerror) 400 | (setq output-list (cons (match-string 1) output-list)) 401 | (forward-line)) 402 | (reverse output-list)))) 403 | (output-list (with-temp-buffer 404 | (funcall find-outputs)))) 405 | output-list)) 406 | 407 | (setq jw/x11-screen-list (jw/env-list "X11_SCREEN_LIST")) 408 | (setq jw/x11-screen-order-list (jw/env-list "X11_SCREEN_ORDER_LIST")) 409 | (setq jw/x11-screen-mode-list (jw/env-list "X11_SCREEN_MODE_LIST")) 410 | (setq jw/x11-screen-rate-list (jw/env-list "X11_SCREEN_RATE_LIST")) 411 | (setq jw/x11-screen-disabled-list (jw/env-list "X11_SCREEN_DISABLED_LIST")) 412 | (setq jw/exwm-workspace-list (jw/env-list "EXWM_WORKSPACE_LIST")) 413 | (setq jw/x11-screen-preferred (jw/env-str "X11_SCREEN_PREFERRED")) 414 | (setq jw/x11-display-dpi (jw/env-str "X11_DISPLAY_DPI")) 415 | (let ((env-var (getenv "X11_SCREEN_USE_ALL_AVAILABLE"))) 416 | (setq jw/x11-screen-use-all-available 417 | (if (and (> (length env-var) 0) (string= "yes" env-var)) 418 | t 419 | nil))) 420 | 421 | (setq exwm-randr-workspace-monitor-plist (jw/build-workspace-monitor-plist jw/exwm-workspace-list)) 422 | 423 | (defun jw/exwm-change-screen-hook () 424 | "Execute xrandr to select and position available screens according to X11_SCREEN_* environment variables." 425 | (let* ((output-list (jw/xrandr-output-list)) 426 | (available-screens (seq-intersection jw/x11-screen-list output-list)) 427 | (available-order-screens (seq-intersection jw/x11-screen-order-list output-list)) 428 | ;; See "--auto" in xrandr(1) and https://github.com/ch11ng/exwm/issues/529. 429 | (unavailable-screens (seq-difference jw/x11-screen-list output-list)) 430 | (available-disabled-screens (seq-intersection jw/x11-screen-disabled-list output-list)) 431 | (available-screen-modes 432 | (let (mode-list 433 | mode screen 434 | (x-screen-list jw/x11-screen-list) 435 | (x-mode-list jw/x11-screen-mode-list)) 436 | (while x-screen-list 437 | (setq screen (car x-screen-list)) 438 | (setq x-screen-list (cdr x-screen-list)) 439 | (setq mode (car x-mode-list)) 440 | (setq x-mode-list (cdr x-mode-list)) 441 | (if (seq-contains available-screens screen) 442 | (setq mode-list (cons mode mode-list)))) 443 | (reverse mode-list))) 444 | (available-screen-rates 445 | (let (rate-list 446 | rate screen 447 | (x-screen-list jw/x11-screen-list) 448 | (x-rate-list jw/x11-screen-rate-list)) 449 | (while x-screen-list 450 | (setq screen (car x-screen-list)) 451 | (setq x-screen-list (cdr x-screen-list)) 452 | (setq rate (car x-rate-list)) 453 | (setq x-rate-list (cdr x-rate-list)) 454 | (if (seq-contains available-screens screen) 455 | (setq rate-list (cons rate rate-list)))) 456 | (reverse rate-list)))) 457 | (if available-screens 458 | ;; Start building xrandr command line 459 | (let* ((x-primary-screen 460 | (if (and jw/x11-screen-preferred (seq-contains available-screens jw/x11-screen-preferred)) 461 | jw/x11-screen-preferred 462 | (car available-screens))) 463 | (screen-pos (seq-position available-screens x-primary-screen)) 464 | (x-primary-mode (elt available-screen-modes screen-pos)) 465 | (x-primary-rate (elt available-screen-rates screen-pos)) 466 | (xrandr-dpi-args 467 | (if jw/x11-display-dpi 468 | (list jw/x11-display-dpi "--dpi"))) 469 | (xrandr-primary-args (list x-primary-rate "--rate" x-primary-mode "--mode" "--primary" x-primary-screen "--output")) 470 | screen 471 | disabled-list 472 | (xrandr-disabled-args 473 | (progn 474 | (while available-disabled-screens 475 | (setq screen (car available-disabled-screens)) 476 | (setq available-disabled-screens (cdr available-disabled-screens)) 477 | (setq disabled-list (cons "--output" disabled-list)) 478 | (setq disabled-list (cons screen disabled-list)) 479 | (setq disabled-list (cons "--off" disabled-list))) 480 | disabled-list)) 481 | (unavailable-screen-list unavailable-screens) 482 | u-s-list 483 | (xrandr-unavailable-screen-args 484 | (progn 485 | (while unavailable-screen-list 486 | (setq screen (car unavailable-screen-list)) 487 | (setq unavailable-screen-list (cdr unavailable-screen-list)) 488 | (setq u-s-list (cons "--output" u-s-list)) 489 | (setq u-s-list (cons screen u-s-list)) 490 | ;; (setq u-s-list (cons "--auto" u-s-list)) 491 | (setq u-s-list (cons "--off" u-s-list))) 492 | u-s-list)) 493 | (screen-list available-screens) 494 | rest-list 495 | (xrandr-rest-available-screen-args 496 | (if jw/x11-screen-use-all-available 497 | ;; Add remaining available screens, except the primary screen 498 | (progn 499 | (while screen-list 500 | (setq screen (car screen-list)) 501 | (setq screen-list (cdr screen-list)) 502 | (if (not (string= screen x-primary-screen)) 503 | (progn 504 | (setq rest-list (cons "--output" rest-list)) 505 | (setq rest-list (cons screen rest-list)) 506 | (setq rest-list (cons "--mode" rest-list)) 507 | (setq rest-list (cons (elt available-screen-modes (seq-position available-screens screen)) rest-list)) 508 | (setq rest-list (cons "--rate" rest-list)) 509 | (setq rest-list (cons (elt available-screen-rates (seq-position available-screens screen)) rest-list))))) 510 | rest-list) 511 | ;; Disable remaining available screens, except the primary screen 512 | (progn 513 | (while screen-list 514 | (setq screen (car screen-list)) 515 | (setq screen-list (cdr screen-list)) 516 | (if (not (string= screen x-primary-screen)) 517 | (progn 518 | (setq rest-list (cons "--output" rest-list)) 519 | (setq rest-list (cons screen rest-list)) 520 | (setq rest-list (cons "--off" rest-list))))) 521 | rest-list))) 522 | (screen-order-list available-order-screens) 523 | order-list 524 | left-screen 525 | (xrandr-screen-order-args 526 | (if (and jw/x11-screen-use-all-available 527 | (> (length screen-order-list) 1)) 528 | (progn 529 | (setq left-screen (car screen-order-list)) 530 | (setq screen-order-list (cdr screen-order-list)) 531 | (while screen-order-list 532 | (setq screen (car screen-order-list)) 533 | (setq screen-order-list (cdr screen-order-list)) 534 | (setq order-list (cons "--output" order-list)) 535 | (setq order-list (cons screen order-list)) 536 | (setq order-list (cons "--right-of" order-list)) 537 | (setq order-list (cons left-screen order-list)) 538 | (setq left-screen screen)) 539 | (reverse order-list)))) 540 | (xrandr-args (reverse (append xrandr-rest-available-screen-args xrandr-unavailable-screen-args 541 | xrandr-disabled-args xrandr-primary-args xrandr-dpi-args)))) 542 | (progn 543 | (setq jw/debug-output-list output-list) 544 | (setq jw/debug-xrandr-args xrandr-args) 545 | (setq jw/debug-xrandr-order-args xrandr-screen-order-args) 546 | (apply #'call-process 547 | "/usr/bin/xrandr" nil nil nil 548 | xrandr-args) 549 | (if xrandr-screen-order-args 550 | (apply #'call-process 551 | "/usr/bin/xrandr" nil nil nil 552 | xrandr-screen-order-args))) 553 | ) 554 | ) 555 | ) 556 | ) 557 | 558 | (add-hook 'exwm-randr-screen-change-hook 'jw/exwm-change-screen-hook) 559 | (exwm-randr-enable) 560 | #+END_SRC 561 | * exwm-config 562 | :PROPERTIES: 563 | :ID: 0f7da169-9bb9-4bad-a7b2-6c6a5db9b6ce 564 | :END: 565 | Code has been copied from 566 | [[https://github.com/ch11ng/exwm/blob/master/exwm-config.el]], changing the names 567 | so they can not collide with exwm proper. 568 | The code has then been modified, mainly with settings from the [[https://gitlab.com/ambrevar/dotfiles/-/blob/master/.emacs.d/lisp/init-exwm.el][ambrevar]] 569 | configuration. 570 | 571 | A hook function that executes [[https://wiki.archlinux.org/index.php/Xmodmap][xmodmap]] is defined and added to 572 | exwm-manage-finish-hook. 573 | 574 | browse-url-generic-program is redefined to use google-chrome, if not overridden 575 | by the "BROWSER" environment variable, or it is defined via xdg-mime. 576 | 577 | EXWM buffer names are changed to be much more human readable. 578 | For example, the buffer for a google-chrome window, will get its name from the 579 | title of the currently selected tab in that window. 580 | 581 | The EXWM keybindings are all defined as one element sequences. This is 582 | required, except for some special cases such as "C-c C-q". To avoid collisions 583 | with other emacs keybindings the exwm-input-global-keys use the "Super" 584 | modifier key, and the simulation keys use the "Hyper" modifier key. 585 | 586 | The key bindings under 587 | 588 | ;; 'S-s-N': Move window to, and switch to, a certain workspace. 589 | 590 | are keyboard layout specific. The provided configuration is for an ascii 591 | keyboard. 592 | 593 | To support a mode-line indicator for EXWM "line-mode"/"char-mode" a hook is set 594 | to force a redisplay of the current buffers mode line. 595 | 596 | Support for resizing windows, using the mouse. 597 | Position the mouse on the divider line between two windows, the mouse pointer 598 | should then change to a double arrow. 599 | Press the left mouse button, and move the mouse. 600 | 601 | #+BEGIN_SRC emacs-lisp 602 | (require 'ido) 603 | (use-package windower 604 | :ensure t) 605 | (require 'browse-url) 606 | (require 'exwm-manage) 607 | 608 | (defun ambrevar/call-process-to-string (program &rest args) 609 | "Call PROGRAM with ARGS and return output. 610 | See also `process-lines'." 611 | ;; Or equivalently: 612 | ;; (with-temp-buffer 613 | ;; (apply 'process-file program nil t nil args) 614 | ;; (buffer-string)) 615 | (with-output-to-string 616 | (with-current-buffer standard-output 617 | (apply 'process-file program nil t nil args)))) 618 | 619 | (defun jw/xmodmap () 620 | "Execute xmodmap" 621 | (progn 622 | ;; (remove-hook 'exwm-manage-finish-hook 'jw/xmodmap) 623 | (ambrevar/call-process-to-string "/home/jw/set_xmodmap.sh"))) 624 | 625 | (setq browse-url-generic-program 626 | (or 627 | (executable-find (or (getenv "BROWSER") "")) 628 | (when (executable-find "xdg-mime") 629 | (let ((desktop-browser (ambrevar/call-process-to-string "xdg-mime" "query" "default" "text/html"))) 630 | (substring desktop-browser 0 (string-match "\\.desktop" desktop-browser)))) 631 | (executable-find browse-url-chrome-program))) 632 | 633 | (defun my-exwm-config-setup () 634 | "My modified configuration for EXWM. Based on exwm-config.el" 635 | ;; Set the initial workspace number. 636 | (unless (get 'exwm-workspace-number 'saved-value) 637 | (setq exwm-workspace-number 4)) 638 | ;; Make class name the buffer name 639 | (add-hook 'exwm-update-class-hook 640 | (lambda () 641 | (exwm-workspace-rename-buffer exwm-class-name))) 642 | ;; Global keybindings. 0-9 bcDfFgGhHijJkKlLmoOQrRwW !@#$%^&*() tab f2 backspace 643 | (unless (get 'exwm-input-global-keys 'saved-value) 644 | (setq exwm-input-global-keys 645 | `( 646 | ;; (,(kbd "s-b") . exwm-workspace-switch-to-buffer) 647 | (,(kbd "s-b") . helm-mini) ;; list and select buffers 648 | (,(kbd "s-c") . helm-resume) ;; Continue in latest helm selection buffer 649 | (,(kbd "s-G") . helm-locate) ;; locate file, based in Linux locate command 650 | ;; (,(kbd "s-g") . mu-helm-file-search) ;; Grep search in files, see https://www.manueluberti.eu/emacs/2020/02/22/ripgrepping-with-helm/ 651 | ;; (,(kbd "s-g") . ambrevar/helm-grep-git-or-ag) ;; Grep search in files, see https://gitlab.com/ambrevar/dotfiles/-/blob/master/.emacs.d/lisp/init-helm.el 652 | (,(kbd "s-g") . helm-do-grep-ag) ;; Grep search in files 653 | (,(kbd "s-r") . helm-run-external-command) ;; Start an application, such as google-chrome 654 | (,(kbd "s-W") . helm-exwm-switch-browser) ;; Switch to some browser windows 655 | (,(kbd "s-m") . (lambda () ;; Toggle display of mode-line and minibuffer, in an EXWM window 656 | (interactive) 657 | (exwm-layout-toggle-mode-line) 658 | (exwm-workspace-toggle-minibuffer))) 659 | (,(kbd "s-i") . exwm-input-toggle-keyboard) ;; Toggle between "line-mode" and "char-mode" in an EXWM window 660 | ;; 's-r': Reset (to line-mode). 661 | (,(kbd "s-R") . exwm-reset) ;; Try to reset EXWM to a sane mode. Panic key 662 | ;; Interactively select, and switch to, a workspace. Only works in non EXWM windows. 663 | (,(kbd "s-w") . exwm-workspace-switch) 664 | ;; 's-a': Launch application. 665 | ;; (,(kbd "s-a") . (lambda (command) 666 | ;; (interactive (list (read-shell-command "$ "))) 667 | ;; (start-process-shell-command command nil command))) 668 | ;; 's-N': Switch to a certain workspace. 669 | ,@(mapcar (lambda (i) 670 | `(,(kbd (format "s-%d" i)) . 671 | (lambda () 672 | (interactive) 673 | (exwm-workspace-switch-create ,i)))) 674 | (number-sequence 0 9)) 675 | ;; 'S-s-N': Move window to, and switch to, a certain workspace. 676 | ,@(cl-mapcar (lambda (c n) 677 | `(,(kbd (format "s-%c" c)) . 678 | (lambda () 679 | (interactive) 680 | (exwm-workspace-move-window ,n) 681 | (exwm-workspace-switch ,n)))) 682 | '(?\) ?! ?@ ?# ?$ ?% ?^ ?& ?* ?\() 683 | ;; '(?\= ?! ?\" ?# ?¤ ?% ?& ?/ ?\( ?\)) 684 | (number-sequence 0 9)) 685 | 686 | ;; Bind "s-" to "slock", a simple X display locker. 687 | (,(kbd "s-") . (lambda () 688 | (interactive) 689 | (start-process "" nil "/usr/bin/slock"))) 690 | (,(kbd "s-h") . windmove-left) ;; Move to window to the left of current one. Uses universal arg 691 | (,(kbd "s-j") . windmove-down) ;; Move to window below current one. Uses universal arg 692 | (,(kbd "s-k") . windmove-up) ;; Move to window above current one. Uses universal arg 693 | (,(kbd "s-l") . windmove-right) ;; Move to window to the right of current one. Uses universal arg 694 | ;; (,(kbd "s-f") . find-file) 695 | (,(kbd "s-f") . helm-find-files) 696 | (,(kbd "s-") . windower-switch-to-last-buffer) ;; Switch to last open buffer in current window 697 | (,(kbd "s-o") . windower-toggle-single) ;; Toggle between multiple windows, and a single window 698 | (,(kbd "s-O") . windower-toggle-split) ;; Toggle between vertical and horizontal split. Only works with exactly two windows. 699 | (,(kbd "s-H") . windower-swap-left) ;; Swap current window with the window to the left 700 | (,(kbd "s-J") . windower-swap-below) ;; Swap current window with the window below 701 | (,(kbd "s-K") . windower-swap-above) ;; Swap current window with the window above 702 | (,(kbd "s-L") . windower-swap-right) ;; Swap current window with the window to the right 703 | (,(kbd "s-F") . exwm-floating-toggle-floating) ;; Toggle the current window between floating and non-floating states 704 | (,(kbd "s-Q") . exwm-layout-toggle-fullscreen) ;; Toggle fullscreen mode, when in an EXWM window. 705 | (,(kbd "s-D") . kill-this-buffer) 706 | (,(kbd "s-") . kill-this-buffer) 707 | ))) 708 | ;; Line-editing shortcuts: abBcdefFknpqsvwx 709 | (unless (get 'exwm-input-simulation-keys 'saved-value) 710 | (setq exwm-input-simulation-keys 711 | `((,(kbd "H-b") . ,(kbd "")) 712 | (,(kbd "H-B") . ,(kbd "C-")) 713 | (,(kbd "H-f") . ,(kbd "")) 714 | (,(kbd "H-F") . ,(kbd "C-")) 715 | (,(kbd "H-p") . ,(kbd "")) 716 | (,(kbd "H-n") . ,(kbd "")) 717 | (,(kbd "H-a") . ,(kbd "")) 718 | (,(kbd "H-e") . ,(kbd "")) 719 | ;; q and w are convenient if Caps Lock key is Hyper key 720 | (,(kbd "H-q") . ,(kbd "")) 721 | (,(kbd "H-w") . ,(kbd "")) 722 | (,(kbd "H-d") . ,(kbd "")) 723 | (,(kbd "H-k") . ,(kbd "S- ")) 724 | ;; cut/paste. 725 | (,(kbd "H-x") . ,(kbd "C-x")) 726 | (,(kbd "H-c") . ,(kbd "C-c")) 727 | (,(kbd "H-v") . ,(kbd "C-v")) 728 | ;; search 729 | (,(kbd "H-s") . ,(kbd "C-f")) 730 | ))) 731 | ;; Default is save-buffers-kill-terminal, but that may kill daemon before its finished 732 | (global-set-key (kbd "C-x C-c") 'save-buffers-kill-emacs) 733 | (add-hook 'exwm-update-title-hook 'ambrevar/exwm-rename-buffer-to-title) 734 | ;; Ensure that EXWM input mode is displayed in mode line 735 | (add-hook 'exwm-input--input-mode-change-hook 736 | 'force-mode-line-update) 737 | ;; Called once, to configure X11 keyboard layout 738 | (add-hook 'exwm-manage-finish-hook 739 | 'jw/xmodmap t) 740 | ;; Allow resizing of non-floating windows, with mouse. 741 | (setq window-divider-default-bottom-width 2 742 | window-divider-default-right-width 2) 743 | (window-divider-mode) 744 | ;; Allow switching to EXWM buffers not belonging to current workspace. 745 | ;; This behaviour takes some getting used to, I guess thats why its not default 746 | (setq exwm-layout-show-all-buffers t) 747 | ;; Configure Ido 748 | (my-exwm-config-ido) 749 | ;; Other configurations 750 | (my-exwm-config-misc)) 751 | 752 | ;; This is copied from exwm-config.el 753 | (defun my-exwm-config--fix/ido-buffer-window-other-frame () 754 | "Fix `ido-buffer-window-other-frame'." 755 | (defalias 'exwm-config-ido-buffer-window-other-frame 756 | (symbol-function #'ido-buffer-window-other-frame)) 757 | (defun ido-buffer-window-other-frame (buffer) 758 | "This is a version redefined by EXWM. 759 | 760 | You can find the original one at `exwm-config-ido-buffer-window-other-frame'." 761 | (with-current-buffer (window-buffer (selected-window)) 762 | (if (and (derived-mode-p 'exwm-mode) 763 | exwm--floating-frame) 764 | ;; Switch from a floating frame. 765 | (with-current-buffer buffer 766 | (if (and (derived-mode-p 'exwm-mode) 767 | exwm--floating-frame 768 | (eq exwm--frame exwm-workspace--current)) 769 | ;; Switch to another floating frame. 770 | (frame-root-window exwm--floating-frame) 771 | ;; Do not switch if the buffer is not on the current workspace. 772 | (or (get-buffer-window buffer exwm-workspace--current) 773 | (selected-window)))) 774 | (with-current-buffer buffer 775 | (when (derived-mode-p 'exwm-mode) 776 | (if (eq exwm--frame exwm-workspace--current) 777 | (when exwm--floating-frame 778 | ;; Switch to a floating frame on the current workspace. 779 | (frame-selected-window exwm--floating-frame)) 780 | ;; Do not switch to exwm-mode buffers on other workspace (which 781 | ;; won't work unless `exwm-layout-show-all-buffers' is set) 782 | (unless exwm-layout-show-all-buffers 783 | (selected-window))))))))) 784 | 785 | (defun my-exwm-config-ido () 786 | "Configure Ido to work with EXWM." 787 | ;; (ido-mode 1) 788 | (add-hook 'exwm-init-hook #'my-exwm-config--fix/ido-buffer-window-other-frame)) 789 | 790 | (defun my-exwm-config-misc () 791 | "Other configurations." 792 | ;; Make more room 793 | (menu-bar-mode -1) 794 | (tool-bar-mode -1) 795 | (scroll-bar-mode -1)) 796 | 797 | ;; Rename buffer to window title. 798 | (defun ambrevar/exwm-rename-buffer-to-title () (exwm-workspace-rename-buffer exwm-title)) 799 | 800 | (my-exwm-config-setup) ;; Does not start X11 or EXWM. Start should be done from commandline. 801 | #+END_SRC 802 | * telephone-line 803 | :PROPERTIES: 804 | :ID: 1fd4aca5-d623-49d5-9be4-54c0e96e5daf 805 | :END: 806 | An indicator is added to the mode line of left-most, bottom-most window in each 807 | workspace, to display that workspaces number. 808 | An indicator is added to the mode line of each EXWM window to display the EXWM 809 | input mode: "line-mode" or "char-mode". 810 | 811 | Note that a hook to redisplay the modeline is set in [[*exwm-config]]. 812 | #+BEGIN_SRC emacs-lisp 813 | (use-package telephone-line 814 | :ensure t) 815 | (require 'telephone-line) 816 | (defun ambrevar/bottom-right-window-p () 817 | "Determines whether the last (i.e. bottom-right) window of the 818 | active frame is showing the buffer in which this function is 819 | executed." 820 | (let* ((frame (selected-frame)) 821 | (right-windows (window-at-side-list frame 'right)) 822 | (bottom-windows (window-at-side-list frame 'bottom)) 823 | (last-window (car (seq-intersection right-windows bottom-windows)))) 824 | (eq (current-buffer) (window-buffer last-window)))) 825 | 826 | (defun jw/telephone-misc-if-exwm-or-last-window () 827 | "Renders the mode-line-misc-info string for display in the 828 | mode-line if the currently active window is the last one in the 829 | frame, or an exwm window. 830 | 831 | The idea is to not display information like the current time, 832 | load, battery levels on all buffers. 833 | And to display input mode only in exwm windows." 834 | 835 | (when (or (ambrevar/bottom-right-window-p) 836 | exwm-window-type) 837 | (telephone-line-raw mode-line-misc-info t)) 838 | ) 839 | 840 | (defun jw/input-mode-str () 841 | "Return string representing input mode, if window is of type EXWM" 842 | (if exwm-window-type 843 | (if (eq exwm--input-mode 'line-mode) 844 | (format "l") 845 | (format "c")) 846 | (format ""))) 847 | 848 | (defun jw/workspace-index () 849 | "Return string representing current EXWM workspace index" 850 | (if (ambrevar/bottom-right-window-p) 851 | (format "[%s]" (exwm-workspace--position (selected-frame))) 852 | (format ""))) 853 | 854 | (defun jw/format-workspace-index-and-input-mode () 855 | "Return string [workspace_index]input-mode depending on exwm-window or bottom-right window" 856 | (format "%s%s" (jw/workspace-index) (jw/input-mode-str)) 857 | ) 858 | 859 | (defun ambrevar/telephone-line-setup () 860 | (telephone-line-defsegment telephone-line-last-window-segment () 861 | (jw/telephone-misc-if-exwm-or-last-window)) 862 | 863 | ;; Display the current EXWM workspace index in the mode-line 864 | (telephone-line-defsegment telephone-line-exwm-workspace-index () 865 | (jw/format-workspace-index-and-input-mode)) 866 | 867 | ;; Define a highlight font for ~ important ~ information in the last 868 | ;; window. 869 | (defface special-highlight '((t (:foreground "white" :background "#5f627f"))) "") 870 | (add-to-list 'telephone-line-faces 871 | '(highlight . (special-highlight . special-highlight))) 872 | 873 | (setq telephone-line-lhs 874 | '((nil . (telephone-line-position-segment)) 875 | (accent . (telephone-line-buffer-segment)))) 876 | 877 | (setq telephone-line-rhs 878 | '((accent . (telephone-line-major-mode-segment)) 879 | (nil . (telephone-line-last-window-segment 880 | telephone-line-exwm-workspace-index)) 881 | )) 882 | 883 | (setq telephone-line-primary-left-separator 'telephone-line-tan-left 884 | telephone-line-primary-right-separator 'telephone-line-tan-right 885 | telephone-line-secondary-left-separator 'telephone-line-tan-hollow-left 886 | telephone-line-secondary-right-separator 'telephone-line-tan-hollow-right) 887 | 888 | (telephone-line-mode 1)) 889 | 890 | (ambrevar/telephone-line-setup) 891 | #+END_SRC 892 | 893 | * helm-exwm 894 | :PROPERTIES: 895 | :ID: 941ba943-b27f-47dd-b0fd-1fa655b3928a 896 | :END: 897 | When a buffer list is displayed, we want a separate section for EXWM buffers. 898 | EXWM buffers that do not belong to the current workspace, are listed with an 899 | indent. 900 | #+BEGIN_SRC emacs-lisp 901 | (use-package helm-exwm 902 | :ensure t 903 | :config 904 | (setq helm-exwm-emacs-buffers-source (helm-exwm-build-emacs-buffers-source)) 905 | (setq helm-exwm-source (helm-exwm-build-source)) 906 | (setq helm-mini-default-sources `(helm-exwm-emacs-buffers-source 907 | helm-exwm-source 908 | helm-source-recentf))) 909 | (require 'helm-exwm) 910 | #+END_SRC 911 | 912 | * desktop 913 | :PROPERTIES: 914 | :ID: b72ada4e-7b5f-4c63-b04e-3a2feec8222c 915 | :END: 916 | When saving emacs desktop, also save Helm find-file-history. 917 | That way we also save dired paths. 918 | #+BEGIN_SRC emacs-lisp 919 | (add-to-list 'desktop-globals-to-save 'helm-ff-history) 920 | #+END_SRC 921 | -------------------------------------------------------------------------------- /.emacs.d/early-init.el: -------------------------------------------------------------------------------- 1 | ;;; early-init.el --- Emacs 27+ pre-initialisation config 2 | 3 | ;;; Commentary: 4 | 5 | ;; Emacs 27+ loads this file before (normally) calling 6 | ;; `package-initialize'. We use this file to suppress that automatic 7 | ;; behaviour so that startup is consistent across Emacs versions. 8 | 9 | ;;; Code: 10 | 11 | (setq package-enable-at-startup nil) 12 | 13 | ;; So we can detect this having been loaded 14 | (provide 'early-init) 15 | 16 | ;;; early-init.el ends here 17 | -------------------------------------------------------------------------------- /.emacs.d/init.el: -------------------------------------------------------------------------------- 1 | ;;; init.el --- EXWM configuration -*- lexical-binding: t; -*- 2 | 3 | ;; The following lines load an Org file and build the configuration code out of it. 4 | 5 | ;;; Code: 6 | 7 | (let ((gc-cons-percentage .6) 8 | (gc-cons-threshold most-positive-fixnum) 9 | (read-process-output-max (* 1024 1024))) 10 | 11 | ;; Disable that pesky echo message 12 | (setq-default inhibit-startup-echo-area-message (user-login-name)) 13 | 14 | ;; Set repositories 15 | (require 'package) 16 | (setq-default 17 | load-prefer-newer t 18 | package-enable-at-startup nil) 19 | (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t) 20 | (add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/") t) 21 | (package-initialize) 22 | 23 | ;; Install dependencies 24 | (unless (package-installed-p 'use-package) 25 | (package-refresh-contents) 26 | (package-install 'use-package t)) 27 | (setq-default 28 | use-package-always-defer t 29 | use-package-always-ensure t) 30 | 31 | ;; Use latest Org 32 | (use-package org :ensure org-plus-contrib) 33 | 34 | ;; Tangle configuration 35 | (org-babel-load-file (expand-file-name "config.org" user-emacs-directory)) 36 | (garbage-collect)) 37 | 38 | ;;; init.el ends here 39 | -------------------------------------------------------------------------------- /.profile: -------------------------------------------------------------------------------- 1 | # ~/.profile: executed by the command interpreter for login shells. 2 | # This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login 3 | # exists. 4 | # see /usr/share/doc/bash/examples/startup-files for examples. 5 | # the files are located in the bash-doc package. 6 | 7 | # the default umask is set in /etc/profile; for setting the umask 8 | # for ssh logins, install and configure the libpam-umask package. 9 | #umask 022 10 | 11 | # gpg has to be started here (or in .xinitrc.exwm), if we want to have encryption in exwm 12 | gpg-connect-agent /bye 13 | SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) 14 | export SSH_AUTH_SOCK 15 | if [ -z "$DISPLAY" -a "$(tty)" = '/dev/tty5' ]; then 16 | exec /usr/bin/startx ~/.xinitrc.exwm >/tmp/startx.log 2>&1 17 | fi 18 | -------------------------------------------------------------------------------- /.xinitrc.exwm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Very important: Avoid spawning daemons here. 3 | # They will not exit with this process, so we will no longer have a clean X11 shutdown. 4 | 5 | # Disable access control for the current user. 6 | xhost +SI:localuser:$USER 7 | 8 | # Make Java applications aware this is a non-reparenting window manager. 9 | export _JAVA_AWT_WM_NONREPARENTING=1 10 | 11 | ## Run site init scripts. Usually not necessary. 12 | if [ -d /etc/X11/xinit/xinitrc.d ] ; then 13 | for f in /etc/X11/xinit/xinitrc.d/?*.sh ; do 14 | [ -x "$f" ] && . "$f" 15 | done 16 | unset f 17 | fi 18 | 19 | . ~/exwm_screen_layout 20 | ~/exwm_xrandr.bash 21 | 22 | # Set themes, etc. 23 | # xrdb -override ~/exwm_x11_resources.xrdb 24 | # Note: xsettingsd just publishes settings. You must ensure that it has settings to publish. 25 | # /usr/bin/xsettingsd & 26 | # Try to control screen blanking 27 | xset s off dpms 1200 1400 1600 28 | # Set keyboard repeat rate. Default is 660 25 ("xset q") 29 | # xset r rate 200 30 30 | 31 | # Set default cursor. 32 | xsetroot -cursor_name left_ptr 33 | 34 | # Hide the mouse pointer if unused for a duration 35 | # /usr/bin/unclutter & 36 | 37 | # One can also start processes unrelated to X11, just ensure that they will exit when this process exits. 38 | 39 | # Enable "Num Lock" mode, on keyboard keypad 40 | # /usr/bin/numlockx on & 41 | 42 | # Uncomment the following block to use the exwm-xim module. Not something I use. 43 | #export XMODIFIERS=@im=exwm-xim 44 | #export GTK_IM_MODULE=xim 45 | #export QT_IM_MODULE=xim 46 | #export CLUTTER_IM_MODULE=xim 47 | 48 | # If Emacs is started in server mode, `emacsclient` is a convenient way to 49 | # edit files in place (used by e.g. `git commit`). 50 | export VISUAL=emacsclient 51 | export EDITOR="$VISUAL" 52 | 53 | # Finally start Emacs 54 | # Scrolling gtk3 apps won't work, unless GDK_CORE_DEVICE_EVENTS is defined 55 | export GDK_CORE_DEVICE_EVENTS=1 56 | # exec dbus-launch --exit-with-session /usr/local/bin/emacs --eval "(progn (require 'exwm) (exwm-enable))" 57 | # "exwm-enable" has to be called before the frame is spawned. 58 | /usr/local/bin/emacs --daemon --eval "(require 'exwm)" -f exwm-enable 59 | exec /usr/local/bin/emacsclient -c 60 | -------------------------------------------------------------------------------- /.xinitrc.exwm_gnome: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | . ~/exwm_screen_layout 3 | ~/exwm_xrandr.bash 4 | 5 | # Try to control screen blanking 6 | xset s off dpms 1200 1400 1600 7 | 8 | # If Emacs is started in server mode, `emacsclient` is a convenient way to 9 | # edit files in place (used by e.g. `git commit`). 10 | export VISUAL=emacsclient 11 | export EDITOR="$VISUAL" 12 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | #+TITLE: A complete configuration for the EXWM X11 window manager 2 | #+CREATOR: Johan Widén 3 | 4 | * Table of Contents :TOC: 5 | :PROPERTIES: 6 | :ID: bad55575-cc19-4d0e-9e50-4e89fc834c38 7 | :TOC: :include all :ignore this 8 | :END: 9 | 10 | :CONTENTS: 11 | - [[#introduction][Introduction]] 12 | - [[#why-use-exwm-will-it-fit-my-workflow][Why use EXWM? Will it fit my workflow?]] 13 | - [[#bugs-and-deficiencies][Bugs and deficiencies]] 14 | - [[#overview-of-the-setup][Overview of the setup]] 15 | - [[#log-in-on-a-tty-and-run-startx-from-profile][Log in on a tty and run startx from .profile]] 16 | - [[#xinitrcexwm][.xinitrc.exwm]] 17 | - [[#xmodmapexwm][.Xmodmap.exwm]] 18 | - [[#exwm-configuration-in-the-emacs-init-file][EXWM configuration in the emacs init file]] 19 | - [[#support-for-encryption-gpg][Support for encryption (gpg)]] 20 | - [[#exwm-randr-configuration][exwm-randr configuration]] 21 | - [[#exwm-configuration][exwm configuration]] 22 | - [[#exwm-proper-configuration][exwm proper configuration]] 23 | - [[#mode-line-configuration][mode line configuration]] 24 | - [[#helm-exwm-specific-configuration][Helm exwm specific configuration]] 25 | - [[#a-tip-about-browser-interaction][A tip about browser interaction]] 26 | - [[#a-tip-about-monitoring-memory-cpu-etc][A tip about monitoring memory, cpu etc]] 27 | - [[#x11-screen-and-workspace-configuration][X11 screen and workspace configuration]] 28 | - [[#environment-variables-x11_-and-exwm_][environment variables X11_* and EXWM_*]] 29 | - [[#script-exwm_xrandrbash][script ~/exwm_xrandr.bash]] 30 | - [[#jwexwm-change-screen-hook][jw/exwm-change-screen-hook()]] 31 | - [[#emacs-init-loads-files-from-melpa-and-github][Emacs init loads files from melpa and github]] 32 | - [[#how-to-try-the-provided-configuration][How to try the provided configuration]] 33 | :END: 34 | 35 | - [[#introduction][Introduction]] 36 | - [[#why-use-exwm-will-it-fit-my-workflow][Why use EXWM? Will it fit my workflow?]] 37 | - [[#bugs-and-deficiencies][Bugs and deficiencies]] 38 | - [[#overview-of-the-setup][Overview of the setup]] 39 | - [[#log-in-on-a-tty-and-run-startx-from-profile][Log in on a tty and run startx from .profile]] 40 | - [[#xinitrcexwm][.xinitrc.exwm]] 41 | - [[#xinitrcexwm_gnome][.xinitrc.exwm_gnome]] 42 | - [[#exwm_screen_layout][exwm_screen_layout]] 43 | - [[#xmodmapexwm][.Xmodmap.exwm]] 44 | - [[#exwm-configuration-in-the-emacs-init-file][EXWM configuration in the emacs init file]] 45 | - [[#x11-screen-and-workspace-configuration][X11 screen and workspace configuration]] 46 | - [[#environment-variables-x11_-and-exwm_][environment variables X11_* and EXWM_*]] 47 | - [[#script-exwm_xrandrbash][script ~/exwm_xrandr.bash]] 48 | - [[#jwexwm-change-screen-hook][jw/exwm-change-screen-hook()]] 49 | - [[#emacs-init-loads-files-from-melpa-and-github][Emacs init loads files from melpa and github]] 50 | - [[#how-to-run-exwm-under-gnome][How to run EXWM under Gnome]] 51 | - [[#how-to-try-the-provided-configuration][How to try the provided configuration]] 52 | 53 | * Introduction 54 | :PROPERTIES: 55 | :ID: f98598ef-0b02-40d1-80e6-55cdd128867b 56 | :TOC: :include descendants 57 | :END: 58 | Below I describe how, and why, I set up and configured the EXWM X11 59 | [[https://wiki.archlinux.org/index.php/Window_manager][window manager]], on Ubuntu 20.4. I used EXWM version 0.24, and emacs 60 | version 27.1. For more info on X11 see [[https://en.wikipedia.org/wiki/X_Window_System][X Window System]] and [[https://wiki.archlinux.org/index.php/Xorg][Xorg]]. 61 | 62 | [[https://github.com/ch11ng/exwm][EXWM]] (Emacs X Window Manager) is a full-featured tiling X window manager for 63 | Emacs built on top of [[https://github.com/ch11ng/xelb][XELB]]. 64 | 65 | The code used in the setup is rather lengthy, so in this document I include 66 | only fragments that help explain why and how I did something. A complete 67 | working, setup can be found [[https://github.com/johanwiden/exwm-setup][here]]. The emacs configuration is fairly bare 68 | bones, just what is needed for a complete EXWM setup. 69 | 70 | Features: 71 | - Support for multiple monitors, and plugging and unplugging of monitors. 72 | - Uses xmodmap to configure the keyboard. 73 | - Many convenient key bindings related to EXWM. 74 | - A mode line indicator that shows the workspace number. Only one 75 | indicator per workspace. 76 | - A mode line indicator in EXWM windows that shows "line mode" or 77 | "character mode" 78 | - The EXWM buffers have meaningful names. 79 | - The buffer list has a section for EXWM buffers. Indented buffer names 80 | belong to a different workspace. 81 | - Hide the mouse pointer when not in use. 82 | - Some tips about how to get a more pleasant interaction with Google Chrome. 83 | 84 | Also: 85 | - [[How to run EXWM under Gnome]] 86 | 87 | If you read this document on github, then internal links in the document 88 | will not work, you will get a 404. It is unfortunately a longstanding problem 89 | that github and gitlab do not handle org mode internal links. 90 | Use the Table of Contents instead. 91 | 92 | Bugs and deficiencies: See a separate section [[Bugs and deficiencies][below]]. 93 | 94 | When you look at the code, remember: 95 | - This is an example of how it can be done. The mechanisms and the whys are 96 | important, not the details. 97 | - You do not have to do it this way, for example: 98 | - I use Helm for completions, perhaps you want something else 99 | - What key bindings do you want for EXWM? 100 | - How do you want to configure your keyboard? 101 | - Do you want emacs to handle everything, as is done here, or instead let 102 | EXWM run under another window environment such as [[https://wiki.archlinux.org/index.php/EXWM][LXDE]] or Gnome, 103 | or [[https://github.com/ch11ng/exwm/wiki/Installation-on-macOS][XQuartz under macOS]]? 104 | - At present I have felt no need for a composite manager, such as Compton. 105 | Again see the [[https://wiki.archlinux.org/index.php/EXWM][archlinux exwm]] page. 106 | - This setup supports multiple monitors, and plugging and unplugging of 107 | monitors. But perhaps you have a static setup? 108 | In that case you can get by with just a hardcoded call to xrandr in your 109 | init files, and no need to hook into exwm-randr.el. 110 | 111 | I am publishing this because it took me a long time to get to the point where 112 | I had something that I would want for daily use. 113 | I had to google a lot, and try various things that did no work out well. 114 | Much of the configuration is based on what people have published on reddit, 115 | github and gitlab. I want to mention especially the [[https://gitlab.com/ambrevar/dotfiles/-/blob/master/.emacs.d/lisp/init-exwm.el][ambrevar]] configuration. 116 | There are pieces from a number of other people, but sadly I have lost track 117 | of where I got them. 118 | 119 | Improvements and corrections on this setup are very welcome. 120 | 121 | My experience with EXWM is that it works well, it just needs a good 122 | configuration. And that is the main deficiency at present, the documentation 123 | for how to do a complete setup is missing. If you have a setup you feel happy 124 | with, which might be of help for other users, why not publish a guide? 125 | For example, how about a more complete guide for EXWM under macOS, beyond 126 | what is published [[https://github.com/ch11ng/exwm/wiki/Installation-on-macOS][here]]. Or under LXDE or Gnome, or with a composite manager. 127 | But please remember: a guide should not just explain how to do something, 128 | but also why it is done. 129 | 130 | * Why use EXWM? Will it fit my workflow? 131 | :PROPERTIES: 132 | :ID: 4d5a26e5-09b3-4c4d-83bd-c65428745bb6 133 | :TOC: :include descendants 134 | :END: 135 | EXWM is a tiling window manager, geared to doing as much as possible using just 136 | the keyboard. A mouse is of course also supported. 137 | For more on tiling window managers see [[https://wiki.archlinux.org/index.php/Window_manager#Tiling_window_managers][Tiling window managers]]. If you prefer 138 | working with windows on a desktop, then EXWM might not be for you. 139 | 140 | In EXWM all X11 windows are available as emacs buffers, so switching to an 141 | X11 window can be done by selecting an emacs buffer. An X11 window is presented 142 | in an emacs window, so the usual emacs window movement commands can be used to 143 | move between windows, and move windows. 144 | 145 | EXWM windows are normally tiled, but there is also support for floating windows. 146 | Floating windows can be moved by pressing Super and left mouse button together. 147 | Floating windows can be resized by pressing Super and right mouse button 148 | together. 149 | 150 | EXWM has the concept of workspaces. A workspace is just an emacs frame. 151 | Each monitor has its own set of workspaces, and each monitor displays one 152 | workspace at a time. Only one workspace, on one monitor, is active (receives 153 | keyboard input) at a time. One uses emacs commands, normally bound to keys, 154 | to switch between workspaces. 155 | 156 | One can interact with X11 applications in two ways: 157 | - "Line mode": Using normal emacs interactions, with keys bound to emacs 158 | functions. Self inserting keys are handed off to the X11 application. 159 | Here there is also a buffer local key map, called "simulation keys" that 160 | translates some emacs key bindings to application specific keys. 161 | There is also a key map "exwm-mode-map" that is active only in EXWM windows 162 | (a window for an X11 application, as opposed to an ordinary emacs buffer). 163 | I find that I use line mode almost all the time. 164 | - "char-mode": This is an escape hatch, where almost all keys are sent directly 165 | to the X11 application. 166 | 167 | I find the ease of moving between, and interacting with, ordinary emacs buffers 168 | and EXWM windows, very addictive. 169 | 170 | EXWM has only one X11 display, to which all monitors are attached as X11 171 | screens (what [[https://wiki.archlinux.org/index.php/Xrandr][xrandr]] calls "output"), so you can freely move the mouse between 172 | monitors. For more on using several monitors with X11, and terminology for 173 | this, see [[https://wiki.archlinux.org/index.php/multihead][Multihead]]. 174 | 175 | A downside with using just one X11 display, is that X11 will use the same 176 | virtual resolution (Dots Per Inch, DPI) on all screens. The xrandr option 177 | "--dpi" is per display, not per screen. If you have a high resolution monitor 178 | and a low resolution monitor in your setup, and you want to use them together, 179 | you will probably have to make some ugly compromise. 180 | 181 | I have a HiDPI laptop, that can have up to 246 physical DPI, and an external 182 | monitor with up to 106 physical DPI. My compromise is that I configure the 183 | laptop display to use a resolution (number of horizontal and vertical pixels ), 184 | that is much lower than what the monitor supports. This results in text being 185 | about the same size on both monitors, but also somewhat unsightly black borders 186 | at the left and right side of the laptop monitor (the screen and the monitor 187 | have different proportions between vertical and horizontal). 188 | 189 | Emacs is fundamentally single threaded, so if you start something long running 190 | in emacs, e.g. executing an org mode code block, you will not be able to do 191 | anything until that job has finished. I am seldom bothered by this, but it 192 | happens. 193 | 194 | Also if you do something, such as an incomplete key sequence, that makes emacs 195 | wait for your input, you will not be able to do anything else until you have 196 | either completed the interaction, or aborted it. This has not been much of a 197 | problem for me, but it happens occasionally. 198 | 199 | * Bugs and deficiencies 200 | :PROPERTIES: 201 | :ID: e9e0f971-ec77-4585-a178-29313e1d86c4 202 | :TOC: :include descendants 203 | :END: 204 | X11 applications sometimes do not get input focus when they are created, or 205 | when one switches between the applications windows, in the same emacs window. 206 | This is probably an EXWM bug. The workaround is to then move out of the window, 207 | and back again. 208 | 209 | Emacs is fundamentally single threaded. 210 | 211 | What is a feature: that all screens are attached to one display, and thus 212 | allows: 213 | - Moving the mouse between screens 214 | - Possible to position screens individually 215 | also leads to the problem that all screens have the same virtual resolution. 216 | See the preceding section. 217 | 218 | Positioning screens relative to each other: 219 | - This configuration script supports positioning screens beside each other 220 | in the horizontal direction, but it does not (yet?) support xrandr options 221 | "--above", "--below" or "--same-as". 222 | 223 | When using helm together with EXWM, enabling emacs follow mode seems to 224 | corrupt EXWM. 225 | See [[https://github.com/emacs-helm/helm/issues/1889]] 226 | The issue is closed, but that is just because it was reported against helm, 227 | and the issue is probably an EXWM issue. 228 | 229 | * Overview of the setup 230 | :PROPERTIES: 231 | :ID: 160a21a2-336d-4a5d-8e6b-1b8fe4c1f2a7 232 | :TOC: :include descendants 233 | :END: 234 | ** Log in on a tty and run startx from .profile 235 | :PROPERTIES: 236 | :ID: e4bbe3c4-1296-4128-abb5-fe83b491d236 237 | :END: 238 | EXWM is started when I log in on tty5. I select tty5 by pressing C-M-, 239 | that is, I press function key F5 while holding down Ctrl and Alt. 240 | EXWM is started from my ~/.profile, see [[./.profile]]. Here is the relevant part: 241 | 242 | #+BEGIN_SRC shell 243 | # gpg has to be started here (or in .xinitrc.exwm), if we want to have encryption in exwm 244 | gpg-connect-agent /bye 245 | SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) 246 | export SSH_AUTH_SOCK 247 | if [ -z "$DISPLAY" -a "$(tty)" = '/dev/tty5' ]; then 248 | exec /usr/bin/startx ~/.xinitrc.exwm >/tmp/startx.log 2>&1 249 | fi 250 | #+END_SRC 251 | 252 | gpg is started in all logins, not just for EXWM, so that gpg encryption is 253 | always available. 254 | 255 | The script starts EXWM using the standard startx script. Using startx ensures 256 | that the environment is set up appropriately for X11. 257 | startx is called only if we login on tty5, and only if we are not already in 258 | an X11 session. 259 | 260 | startx will call xinit, and xinit will run the script ~/.xinitrc.exwm. 261 | The output is logged in /tmp/startx.log. Have a look at that file now and then 262 | to check that everything starts as expected. 263 | 264 | Avoid using the default script ~/.xinitrc, as that script may be executed by 265 | other window managers. 266 | 267 | ** .xinitrc.exwm 268 | :PROPERTIES: 269 | :ID: 58519e62-e313-4ff7-98d5-352f546e6e7c 270 | :END: 271 | This script, [[./.xinitrc.exwm]], is responsible for initializing X11 and starting 272 | emacs. When this script terminates, you will (hopefully) be logged out. 273 | I said hopefully, because this works only if everything started from this 274 | script can receive a termination signal when the script tries to terminate. 275 | So do not spawn daemon processes in this script. It is OK to execute processes 276 | in the background. 277 | 278 | The script runs as a bash script on my computer, but I have tried to limit 279 | myself to /bin/sh syntax, for compatibility. 280 | 281 | The script has the following parts, from top to bottom, some of which are 282 | described later: 283 | - Disable X11 access control for the current user. 284 | - Set an environment variable for Java AWT. Run site X11 init scripts. 285 | - Set environment variables for X11 screens, by sourcing [[exwm_screen_layout]]. 286 | - Run script, [[./exwm_xrandr.bash][~/exwm_xrandr.bash]] to execute xrandr according to the preceding 287 | configuration. 288 | This script first queries xrandr to see which screens are actually available, 289 | and then configures those with one or two more invocations of xrandr. 290 | - Optionally execute [[https://wiki.archlinux.org/index.php/x_resources][xrdb]] to add X11 resource configurations stored in some 291 | file. 292 | - Optionally start [[https://wiki.archlinux.org/index.php/Xsettingsd][xsettingsd]]. The idea behind this is that you should have 293 | previously started some other window manager such as Gnome or KDE, and saved 294 | that window managers configuration to a certain file. xsettingsd will read 295 | the file and report the settings to the application running under EXWM. 296 | - Run xset to configure screen blanking, i.e. that your displays will turn off 297 | when they have been idle for a while. 298 | - Optionally set keyboard delay and repeat rate. I like the default values 299 | provided by Ubuntu. 300 | - Set the default mouse cursor. This is from the original EXWM configuration. 301 | - Optionally start [[https://wiki.archlinux.org/index.php/Unclutter][unclutter]]. It hides the X11 mouse cursor, when it has been 302 | unused for a while. 303 | - Optionally start some non X11 processes. It is probably better to make them 304 | systemd user services. 305 | - Optionally execute numlockx to set keyboard keypad in "Num Lock" mode, 306 | or not. This program is part of some Linux distributions. 307 | - Finally start emacs. This can be done in two ways: In emacs server mode, 308 | or in non server mode. I use server mode, this has the upside that X11 309 | applications can use emacs as editor. I also provide the commented out 310 | command to start emacs in non server mode. 311 | In both cases the command to start exwm, "(exwm-enable)", is provided 312 | on the command line, it is not part of the emacs init file. 313 | It is thus possible to start emacs under another window manager, or in 314 | a terminal. 315 | For server mode: 316 | - export environment variables VISUAL and EDITOR 317 | - Start emacs server. This requires that the call "(server-start)" is part of 318 | emacs init file. This starts EXWM, but does not display any emacs frames. 319 | - Start emacsclient, to open emacs on the screens. 320 | 321 | Notably missing here is a call to [[https://wiki.archlinux.org/index.php/Xmodmap][xmodmap]] to configure the keyboard and mouse 322 | layout. I found that this call must be done after EXWM has started completely, 323 | otherwise the settings will be lost during EXWM start. So there is a call to 324 | xmodmap in the emacs init file. This runs on an emacs EXWM hook and is then 325 | removed from the hook. 326 | ** .xinitrc.exwm_gnome 327 | This script, [[./.xinitrc.exwm_gnome]], is used to configure EXWM when running under Gnome. See [[How to run EXWM under Gnome]]. 328 | It sources ~/exwm_screen_layout. 329 | ** exwm_screen_layout 330 | This bash script, [[./exwm_screen_layout]], is sourced by scripts that configure EXWM. It configures the X11 screen layout, 331 | by setting a number of environment variables: 332 | - Which screens are to be used, with what resolution, and how are they 333 | arranged? 334 | - Should some screen have a specific workspace? 335 | - Which screen should be "primary", i.e. be used for workspaces that have not 336 | been explicitly listed? 337 | - Should all listed screens be used, or just one? 338 | - What Dots Per Inch (X11 DPI) should be used? 339 | Actually this is a bit more involved, because screens can be unplugged, see 340 | the dedicated section below: [[X11 screen and workspace configuration]] 341 | ** .Xmodmap.exwm 342 | :PROPERTIES: 343 | :ID: ba48e5ee-b0aa-49b0-bfaf-d486a8152bc9 344 | :END: 345 | This file, [[./.Xmodmap.exwm]], is the input to [[https://wiki.archlinux.org/index.php/Xmodmap][xmodmap]]. It makes the "Caps Lock" 346 | key a "Hyper" modifier key. 347 | 348 | #+BEGIN_EXAMPLE 349 | keycode 66 = Hyper_R 350 | clear Lock 351 | add mod3 = Hyper_R 352 | #+END_EXAMPLE 353 | 354 | Change according to what you want. More examples can be found on 355 | the [[https://wiki.archlinux.org/index.php/Xmodmap][Archlinux xmodmap page]]. 356 | 357 | Keycode "66" is what my keyboard sends when I press the "Caps Lock" key. 358 | Note that your keyboard might have a keycode value different from "66". 359 | 360 | To test and check the result of running xmodmap, I found it convenient to open 361 | a shell window in emacs, and there run 362 | 363 | #+BEGIN_SRC shell 364 | xmodmap -pm 365 | #+END_SRC 366 | 367 | to show the current modifier map. 368 | 369 | ** EXWM configuration in the emacs init file 370 | :PROPERTIES: 371 | :ID: 69d5b576-b8bf-4227-a4a7-cd01728f0c97 372 | :END: 373 | This is an overview of the EXWM configuration. More detailed documentation is 374 | in [[./.emacs.d/config.org]] 375 | 376 | *** Support for encryption (gpg) 377 | :PROPERTIES: 378 | :ID: 6713083a-d69e-4df6-87c9-30ee7a7bdcc3 379 | :END: 380 | To make emacs handle queries for gpg passwords, the following is defined: 381 | 382 | #+BEGIN_SRC emacs-lisp 383 | ;; let's get encryption established 384 | (setf epg-pinentry-mode 'loopback) 385 | (defun pinentry-emacs (desc prompt ok error) 386 | (let ((str (read-passwd 387 | (concat (replace-regexp-in-string "%22" "\"" 388 | (replace-regexp-in-string "%0A" "\n" desc)) prompt ": ")))) 389 | str)) 390 | #+END_SRC 391 | 392 | You may also be interested in [[https://github.com/ecraven/pinentry-emacs][pinentry-emacs]] to make other applications use 393 | emacs to query for gpg passwords. 394 | 395 | Earlier versions of emacs used [[https://emacs.stackexchange.com/questions/59659/encrypted-password-file-with-emacs-gpg][epa-file]]. 396 | 397 | *** exwm-randr configuration 398 | :PROPERTIES: 399 | :ID: 2ac70cfd-8594-4465-ab58-cc987c70fc58 400 | :END: 401 | Support for multiple monitors, and plugging and unplugging of monitors. 402 | 403 | If you have a static setup, i.e. you will not change the screen configuration 404 | while emacs is running, then you do not need to 405 | define jw/exwm-change-screen-hook. 406 | 407 | If you are going to use more than one screen at the same time, you need to 408 | define exwm-randr-workspace-monitor-plist, and call "(exwm-randr-enable)". 409 | "(exwm-randr-enable)" must also be called if you use 410 | exwm-randr-screen-change-hook. 411 | 412 | *** exwm configuration 413 | :PROPERTIES: 414 | :ID: 04ffea26-08cc-4d4e-b6c8-60e0b3e070e0 415 | :END: 416 | **** exwm proper configuration 417 | :PROPERTIES: 418 | :ID: 97676e05-f77b-488f-bd11-23e5d5fc26af 419 | :END: 420 | Code has been copied from 421 | [[https://github.com/ch11ng/exwm/blob/master/exwm-config.el]], changing the names 422 | so they can not collide with exwm proper. 423 | The code has then been modified, mainly with settings from the [[https://gitlab.com/ambrevar/dotfiles/-/blob/master/.emacs.d/lisp/init-exwm.el][ambrevar]] 424 | configuration. 425 | 426 | A hook function that executes [[https://wiki.archlinux.org/index.php/Xmodmap][xmodmap]] is defined and added to 427 | exwm-manage-finish-hook. The hook function unhooks itself when executed, 428 | to only execute once. 429 | 430 | browse-url-generic-program is redefined to use google-chrome, if not overridden 431 | by the "BROWSER" environment variable, or it is defined via xdg-mime. 432 | 433 | The following code changes EXWM buffer names to be much more human readable. 434 | For example, the buffer for a google-chrome window, will get its name from the 435 | title of the currently selected tab in that window. I really like this. 436 | Also see [[Helm exwm specific configuration]]. 437 | 438 | #+BEGIN_SRC emacs-lisp 439 | ;; Make class name the buffer name 440 | (add-hook 'exwm-update-class-hook 441 | (lambda () 442 | (exwm-workspace-rename-buffer exwm-class-name))) 443 | #+END_SRC 444 | 445 | To bind keys I use (kbd "binding") instead of the arcane [binding] syntax. The 446 | kbd key syntax is much better documented, see for instance 447 | [[http://ergoemacs.org/emacs/keyboard_shortcuts_examples.html]]. 448 | 449 | The EXWM keybindings are all defined as one element sequences. This is 450 | required, except for some special cases such as "C-c C-q". To avoid collisions 451 | with other emacs keybindings the exwm-input-global-keys use the "Super" 452 | modifier key, and the simulation keys use the "Hyper" modifier key. 453 | 454 | A note about binding to non-ascii keys: If I bind to a non ascii key with the 455 | "Super" modifier, I get a warning at key binding time that the key is unavailable, 456 | but it still works. I suspect that this is an emacs bug. None of my attempted 457 | workarounds have succeed in eliminating this annoying warning. 458 | 459 | The key bindings under 460 | 461 | #+BEGIN_SRC emacs-lisp 462 | ;; 'S-s-N': Move window to, and switch to, a certain workspace. 463 | #+END_SRC 464 | 465 | are keyboard layout specific. The provided configuration is for an ascii 466 | keyboard. My efforts to make this code more generic, have so far failed. 467 | 468 | To support a mode-line indicator for EXWM "line-mode"/"char-mode" the following 469 | hook is set 470 | 471 | #+BEGIN_SRC emacs-lisp 472 | (add-hook 'exwm-input--input-mode-change-hook 473 | 'force-mode-line-update) 474 | #+END_SRC 475 | 476 | This forces a redisplay of the current buffers mode line. 477 | 478 | To support resizing windows, using the mouse, the following code is used. 479 | Position the mouse on the divider line between two windows, the mouse pointer 480 | should then change to a double arrow. 481 | Press the left mouse button, and move the mouse. 482 | 483 | #+BEGIN_SRC emacs-lisp 484 | ;; Allow resizing with mouse, of non-floating windows. 485 | (setq window-divider-default-bottom-width 2 486 | window-divider-default-right-width 2) 487 | (window-divider-mode) 488 | #+END_SRC 489 | 490 | my-exwm-config--fix/ido-buffer-window-other-frame is from exwm-config.el. 491 | 492 | **** mode line configuration 493 | :PROPERTIES: 494 | :ID: c24de552-6737-4ada-bcda-5a4cad960ab1 495 | :END: 496 | An indicator is added to the mode line of left-most, bottom-most window in each 497 | workspace, to display that workspaces number. 498 | An indicator is added to the mode line of each EXWM window to display the EXWM 499 | input mode: "line-mode" or "char-mode". 500 | 501 | The code is based on a configuration by ambrevar, but I can no longer find it 502 | on the internet. It uses the emacs package [[https://github.com/dbordak/telephone-line][telephone-line]], but similar things 503 | are easily achieved with any mode line package. 504 | 505 | Note that a hook to redisplay the modeline is set 506 | in [[exwm proper configuration]]. 507 | 508 | **** Helm exwm specific configuration 509 | :PROPERTIES: 510 | :ID: d55f0f21-8deb-49c7-9fb8-f3e92465770f 511 | :END: 512 | When a buffer list is displayed, we want a separate section for EXWM buffers. 513 | EXWM buffers that do not belong to the current workspace, are listed with an 514 | indent. 515 | 516 | By default one can not switch to EXWM buffers belonging to other workspaces. 517 | [[exwm proper configuration]] sets variable exwm-layout-show-all-buffers to t, 518 | thus allowing such switching. Selecting an EXWM buffer that is currently 519 | displaying in another workspace, results in somewhat unintuitive behaviour. 520 | But selecting non displaying buffers works OK. 521 | 522 | #+BEGIN_SRC emacs-lisp 523 | (use-package helm-exwm 524 | :ensure t 525 | :config 526 | (setq helm-exwm-emacs-buffers-source (helm-exwm-build-emacs-buffers-source)) 527 | (setq helm-exwm-source (helm-exwm-build-source)) 528 | (setq helm-mini-default-sources `(helm-exwm-emacs-buffers-source 529 | helm-exwm-source 530 | helm-source-recentf))) 531 | #+END_SRC 532 | 533 | **** A tip about browser interaction 534 | :PROPERTIES: 535 | :ID: adaf68a1-c025-4830-94bd-e909877acb70 536 | :END: 537 | With EXWM we are supposed to use the keyboard as much as possible. But internet 538 | browsers like google-chrome in their basic configuration, are a bit lacking in 539 | that respect. One is often forced to use the mouse. 540 | 541 | To improve on this situation one can install an extension in the browser that 542 | supports a more keyboard oriented interaction. For example: 543 | - google-chrome: [[https://github.com/philc/vimium][Vimium]] 544 | - firefox: [[https://addons.mozilla.org/en-GB/firefox/addon/vimium-ff/][vimium-ff]] 545 | - safari: [[https://github.com/guyht/vimari][Vimari]] 546 | 547 | **** A tip about monitoring memory, cpu etc 548 | :PROPERTIES: 549 | :ID: 96d9f808-71eb-4fb6-b015-2e62e9d8359d 550 | :END: 551 | I do not monitor resources directly in emacs. Instead I start an X11 app that 552 | provides resource monitoring. When I want resource monitoring I start an X11 553 | terminal application, in which I start [[https://www.byobu.org/][byobu]], a configuration for tmux. 554 | This provides resource monitoring, in the terminal status bar. 555 | 556 | * X11 screen and workspace configuration 557 | :PROPERTIES: 558 | :ID: e28da70a-dc4f-465f-9533-f328e725669b 559 | :TOC: :include descendants 560 | :END: 561 | An overview of: 562 | - the environment variables X11_* and EXWM_* defined in .xinitrc.exwm 563 | - the [[script ~/exwm_xrandr.bash]] (called from [[.xinitrc.exwm]]) 564 | - the [[jw/exwm-change-screen-hook()]] elisp code in the emacs init file. 565 | 566 | The configuration is completely determined by the variables X11_* and EXWM_*, 567 | and the screen status reported by xrandr. 568 | 569 | ** environment variables X11_* and EXWM_* 570 | :PROPERTIES: 571 | :ID: a981a052-1b51-4555-b9f3-4178c7841ad9 572 | :END: 573 | #+BEGIN_SRC shell 574 | # X11 screens (xrandr graphics outputs) I want to use. Names and values are from the output of /usr/bin/xrandr 575 | # They can be ordered in any way you want. The leftmost available screen will be primary, unless overridden 576 | # by X11_SCREEN_PREFERRED and that screen is available. 577 | # The primary screen is the default screen used for EXWM workspaces. 578 | # It will also be sorted first in Xinerama and RANDR geometry requests. 579 | export X11_SCREEN_LIST="eDP-1 DP-3" 580 | # xrandr --mode for each screen in X11_SCREEN_LIST 581 | export X11_SCREEN_MODE_LIST="1680x1050 3840x1600" 582 | # xrandr --rate for each screen in X11_SCREEN_LIST 583 | export X11_SCREEN_RATE_LIST="59.95 59.99" 584 | # How screens are arranged from left to right. Vertical order, and "--same-as" not yet implemented. 585 | export X11_SCREEN_ORDER_LIST="DP-3 eDP-1" 586 | # X11 screens (graphics outputs) that should always be explicitly turned off, if available. 587 | export X11_SCREEN_DISABLED_LIST="DP-2" 588 | # Primary X11 screen, if available 589 | export X11_SCREEN_PREFERRED="DP-3" 590 | #export X11_SCREEN_PREFERRED="eDP-1" 591 | # If X11_SCREEN_USE_ALL_AVAILABLE="yes" then use all available screens in X11_SCREEN_LIST: 592 | # - X11_SCREEN_PREFERRED is primary, if available 593 | # - If X11_SCREEN_PREFERRED is unavailable, primary is first available screen in X11_SCREEN_LIST. 594 | # Otherwise use only one: 595 | # - X11_SCREEN_PREFERRED if available 596 | # - If X11_SCREEN_PREFERRED is unavailable then use first available screen in X11_SCREEN_LIST. 597 | export X11_SCREEN_USE_ALL_AVAILABLE="yes" 598 | #export X11_SCREEN_USE_ALL_AVAILABLE="no" 599 | # Argument value for "xrandr --dpi", i.e. Dots Per Inch. This is for the X11 DISPLAY, i.e. used for all screens. 600 | export X11_DISPLAY_DPI=106 601 | # List of pairs "workspace-number screen" 602 | # Used to construct exwm-randr-workspace-monitor-plist in emacs. 603 | # If a screen in this list is unavailable, the workspace will be mapped to the primary screen. 604 | export EXWM_WORKSPACE_LIST="1 eDP-1 3 eDP-1" 605 | #export EXWM_WORKSPACE_LIST="1 DP-3 3 DP-3" 606 | #+END_SRC 607 | 608 | ** script ~/exwm_xrandr.bash 609 | :PROPERTIES: 610 | :ID: 83fac1f7-3b4b-4d10-b693-54a61fa2c182 611 | :END: 612 | This script, [[./exwm_xrandr.bash]], executes xrandr before the start of EXWM, to 613 | configure the X11 screens according to [[environment variables X11_* and EXWM_*]] 614 | 615 | First xrandr is executed without arguments, to report the current status of 616 | the X11 screens. 617 | 618 | Then the intersection of the available screens from that status, with 619 | X11_SCREEN_LIST, X11_SCREEN_ORDER_LIST and X11_SCREEN_DISABLED_LIST is used to 620 | build xrandr commands for the available screens. 621 | 622 | An xrandr command is executed to configure "--primary", "--mode" and --"rate" 623 | for the screens to be used. All available screens in X11_SCREEN_DISABLED_LIST 624 | are configured as "--off". 625 | 626 | If more than one screen is to be used, then a final xrandr command is executed 627 | to position these screens relative to each other. 628 | 629 | ** jw/exwm-change-screen-hook() 630 | :PROPERTIES: 631 | :ID: 5fe4c608-afb1-4eb7-8d40-c92ec885ce92 632 | :END: 633 | This elisp code, defined in the emacs init file, executes in EXWM when a screen 634 | is plugged in or unplugged, to configure the X11 screens according to 635 | [[environment variables X11_* and EXWM_*]] 636 | 637 | The semantics of the code is very similar to that in [[script ~/exwm_xrandr.bash]] except 638 | that xrandr is also provided with arguments to explicitly turn "--off" any 639 | unavailable screen, if it is part of X11_SCREEN_LIST. The xrandr argument 640 | "--auto" could have been used, but "--off" seems to work ok. This is necessary, 641 | otherwise "xrandr --listactivemonitors" may list the screen as available. 642 | See [[https://github.com/ch11ng/exwm/issues/529]] 643 | 644 | First xrandr is executed without arguments, to report the current status of the 645 | X11 screens. 646 | 647 | Then the intersection of the available screens from that status, with 648 | X11_SCREEN_LIST, X11_SCREEN_ORDER_LIST and X11_SCREEN_DISABLED_LIST is used to 649 | build xrandr commands for the available screens. 650 | 651 | An xrandr command is executed to configure "--primary", "--mode" and --"rate" 652 | for the screens to be used. All available screens in X11_SCREEN_DISABLED_LIST 653 | are configured as "--off". All unavailable screens in X11_SCREEN_LIST are 654 | configured as "--off". 655 | 656 | If more than one screen is to be used, then a final xrandr command is executed 657 | to position those screens relative to each other. 658 | * Emacs init loads files from melpa and github 659 | :PROPERTIES: 660 | :ID: ac8b8ba0-5f01-4ded-a283-1b825a03adbb 661 | :END: 662 | The provided emacs init files loads the following: 663 | - org mode from the org repository 664 | - The [[https://github.com/raxod502/straight.el][straight]] package manager is loaded from its github repository 665 | - The straight package manager is used to load [[https://github.com/grettke/lolsmacs][lolsmacs]] from its github repository 666 | - a number of packages from melpa 667 | * How to run EXWM under Gnome 668 | Clone [[https://github.com/WJCFerguson/exwm-gnome-flashback]] 669 | Read the Readme and install. 670 | Check what is in /usr/bin/exwm-gnome-flashback, perhaps you need to modify the path to emacs? 671 | I replaced the line 672 | #+BEGIN_SRC shell 673 | emacs --fullscreen --eval "(exwm-enable)" 674 | #+END_SRC 675 | with 676 | #+BEGIN_SRC shell 677 | . ~/.xinitrc.exwm_gnome 678 | /usr/local/bin/emacs --daemon --eval "(require 'exwm)" -f exwm-enable 679 | /usr/local/bin/emacsclient -c 680 | # /usr/local/bin/emacs --fullscreen --eval "(exwm-enable)" 681 | #+END_SRC 682 | 683 | The Readme says that we should disable show-desktop-icons, but when I ran the command I got a message saying that the 684 | variable was not writable. I then logged in to Gnome and started 685 | #+BEGIN_SRC shell 686 | dconf 687 | #+END_SRC 688 | I navigated to org.gnome.desktop.background, and verified that show-desktop-icons was indeed disabled. 689 | 690 | I then opened Gnome Settings and selected submenu "Keyboard Shortcuts". I disabled all shortcuts except for: 691 | - "Lock screen" which I rebound to the same shortcut I use in EXWM: s- 692 | - "Log out", because I wanted to have this as an escape hatch. 693 | 694 | * How to try the provided configuration 695 | :PROPERTIES: 696 | :ID: 56d63cc3-3fe6-4ae8-a125-02fc427b8877 697 | :TOC: :include descendants 698 | :END: 699 | Copy .Xmodmap.exwm, .xinitrc.exwm, exwm_xrandr.bash, set_xmodmap.sh to your home directory. 700 | In these scripts change references from "/home/jw" to the path to your home directory. 701 | 702 | Configure the X11_SCREEN_* and EXWM_WORKSPACE_LIST environment variables in .xinitrc.exwm. 703 | 704 | Copy .emacs.d, renaming it to say ~/exwm-setup 705 | 706 | Assuming that your current emacs directory is ~/.emacs.d do: 707 | - mv .emacs.d my_emacs.d 708 | - ln -s exwm-setup .emacs.d 709 | 710 | In .emacs.d/config.org change references from "/home/jw" to the path to your home directory. 711 | 712 | Then either: 713 | - Modify your ,profile, adding what is in .profile 714 | Assuming that no X11 session is running, login to the tty, by pressing C-M- from the login screen. 715 | - Or, assuming no X11 session is running, login to a tty, and execute: 716 | #+BEGIN_SRC shell 717 | gpg-connect-agent /bye 718 | SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) 719 | export SSH_AUTH_SOCK 720 | /usr/bin/startx ~/.xinitrc.exwm >/tmp/startx.log 2>&1 721 | #+END_SRC 722 | -------------------------------------------------------------------------------- /announcement.txt: -------------------------------------------------------------------------------- 1 | A complete configuration for the emacs EXWM X11 window manager 2 | 3 | I have created a complete example configuration for EXWM. This includes 4 | files like .profile, .xinitrc and of course init files for emacs. 5 | There is also a README that explains the configuration. 6 | 7 | I have tried to keep the configuration small, so as not to bring in a lot of 8 | emacs packages unrelated to EXWM. An exception to this is that there are many 9 | configured keybindings for EXWM, and emacs packages have been added to support 10 | those keybindings. 11 | 12 | I use Helm for completion in emacs, so that is what is used in the sample 13 | configuration. It should hopefully not be difficult to substitute a different 14 | completion framework. 15 | 16 | The configuration has been developed under Ubuntu, with emacs 27.1, but it 17 | should hopefully be easy to adapt this to other environments. 18 | 19 | You can of course also just pick fragments and put them in your current 20 | configuration. 21 | 22 | Features: 23 | - Support for multiple monitors, and plugging and unplugging of monitors. 24 | - Uses xmodmap to configure the keyboard. 25 | - Many convenient key bindings related to EXWM. 26 | - A mode line indicator that shows the workspace number. Only one 27 | indicator per workspace. 28 | - A mode line indicator in EXWM windows that shows "line mode" or 29 | "character mode" 30 | - The EXWM buffers have meaningful names. 31 | - The buffer list has a section for EXWM buffers. Indented buffer names 32 | belong to a different workspace. 33 | - Hide the mouse pointer when not in use. 34 | - Some tips about how to get a more pleasant interaction with Google Chrome. 35 | 36 | Here is a link to a README and the configuration files: 37 | https://github.com/johanwiden/exwm-setup 38 | 39 | -------------------------------------------------------------------------------- /exwm_screen_layout: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # https://wiki.archlinux.org/index.php/multihead 4 | # The current version of exwm (0.23) uses only one X11 display. All X11 screens (what xrandr calls "output") are attached 5 | # to that display, so X11 considers all screens to have the same Dots-Per-Inch (DPI). 6 | # "xrandr --dpi" sets DPI for an X11 display, not for just a screen. 7 | # "xrandr --fbmm" is also per display, not for just a screen. 8 | # This implies that if we want a certain font size to have similar physical size on each screen, then we need to 9 | # set the xrandr --mode on each screen to a similar physical DPI. 10 | # I have two monitors, one that can achieve a physical DPI of up to 246 (call that HiDPI), 11 | # and one that can achieve a physical DPI of up to 106. 12 | # So in case I want say emacs default font to display similarly on both monitors, then I have to set a low resolution mode 13 | # on the screen attached to the HiDPI monitor. 14 | 15 | # X11 screens (xrandr graphics outputs) I want to use. Names and values are from the output of /usr/bin/xrandr 16 | # They can be ordered in any way you want. The leftmost available screen will be primary, unless overridden 17 | # by X11_SCREEN_PREFERRED and that screen is available. 18 | # The primary screen is the default screen used for EXWM workspaces. 19 | # It will also be sorted first in Xinerama and RANDR geometry requests. 20 | export X11_SCREEN_LIST="eDP-1 DP-3" 21 | # xrandr --mode for each screen in X11_SCREEN_LIST 22 | export X11_SCREEN_MODE_LIST="1680x1050 3840x1600" 23 | # xrandr --rate for each screen in X11_SCREEN_LIST 24 | export X11_SCREEN_RATE_LIST="59.95 59.99" 25 | # How screens are arranged from left to right. Vertical order, and "--same-as" not yet implemented. 26 | export X11_SCREEN_ORDER_LIST="DP-3 eDP-1" 27 | # X11 screens (graphics outputs) that should always be explicitly turned off, if available. 28 | export X11_SCREEN_DISABLED_LIST="DP-2" 29 | # Primary X11 screen, if available 30 | export X11_SCREEN_PREFERRED="DP-3" 31 | #export X11_SCREEN_PREFERRED="eDP-1" 32 | # If X11_SCREEN_USE_ALL_AVAILABLE="yes" then use all available screens in X11_SCREEN_LIST: 33 | # - X11_SCREEN_PREFERRED is primary, if available 34 | # - If X11_SCREEN_PREFERRED is unavailable, primary is first available screen in X11_SCREEN_LIST. 35 | # Otherwise use only one: 36 | # - X11_SCREEN_PREFERRED if available 37 | # - If X11_SCREEN_PREFERRED is unavailable then use first available screen in X11_SCREEN_LIST. 38 | export X11_SCREEN_USE_ALL_AVAILABLE="yes" 39 | #export X11_SCREEN_USE_ALL_AVAILABLE="no" 40 | # Argument value for "xrandr --dpi", i.e. Dots Per Inch. This is for the X11 DISPLAY, i.e. used for all screens. 41 | export X11_DISPLAY_DPI=106 42 | # List of pairs "workspace-number screen" 43 | # Used to construct exwm-randr-workspace-monitor-plist in emacs. 44 | # If a screen in this list is unavailable, the workspace will be mapped to the primary screen. 45 | export EXWM_WORKSPACE_LIST="1 eDP-1 3 eDP-1" 46 | #export EXWM_WORKSPACE_LIST="1 DP-3 3 DP-3" 47 | -------------------------------------------------------------------------------- /exwm_xrandr.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Execute xrandr with appropriate arguments, to configure the X11 screens for EXWM 3 | # For specification see: ".xinitrc.exwm" 4 | 5 | grep="/bin/grep" 6 | awk="/usr/bin/awk" 7 | xrandr="/usr/bin/xrandr" 8 | 9 | if [[ ! -z "${X11_SCREEN_LIST}" ]]; then 10 | declare -a x11_screens_a=(${X11_SCREEN_LIST}) 11 | declare -a x11_screen_order_a=(${X11_SCREEN_ORDER_LIST}) 12 | declare -a x11_screens_disabled_a=(${X11_SCREEN_DISABLED_LIST}) 13 | declare -a x11_screen_mode_a=(${X11_SCREEN_MODE_LIST}) 14 | declare -a x11_screen_rate_a=(${X11_SCREEN_RATE_LIST}) 15 | declare -a x11_connected_screens_a=($(${xrandr} | ${grep} " connected " | ${awk} '{ print $1 }')) 16 | x11_connected_screens_list=" ${x11_connected_screens_a[*]} " 17 | 18 | x11_available_screens_a=() 19 | x11_available_screen_modes_a=() 20 | x11_available_screen_rates_a=() 21 | for ((i=0;i<${#x11_screens_a[@]};++i)); do 22 | screen=${x11_screens_a[$i]} 23 | if [[ ${x11_connected_screens_list} =~ " $screen " ]]; then 24 | x11_available_screens_a+=($screen) 25 | x11_available_screen_modes_a+=("${x11_screen_mode_a[$i]}") 26 | x11_available_screen_rates_a+=("${x11_screen_rate_a[$i]}") 27 | fi 28 | done 29 | 30 | x11_available_screen_order_a=() 31 | for ((i=0;i<${#x11_screen_order_a[@]};++i)); do 32 | screen=${x11_screen_order_a[$i]} 33 | if [[ ${x11_connected_screens_list} =~ " $screen " ]]; then 34 | x11_available_screen_order_a+=($screen) 35 | fi 36 | done 37 | 38 | x11_available_disabled_screens_a=() 39 | for screen in ${x11_screens_disabled_a[@]}; do 40 | if [[ ${x11_connected_screens_list} =~ " $screen " ]]; then 41 | x11_available_disabled_screens_a+=($screen) 42 | fi 43 | done 44 | 45 | if [[ ! -z ${x11_available_screens_a} ]]; then 46 | x11_available_screens_list=" ${x11_available_screens_a[*]} " 47 | if [[ ! -z ${X11_SCREEN_PREFERRED} ]] && [[ ${x11_available_screens_list} =~ " ${X11_SCREEN_PREFERRED} " ]]; then 48 | x11_primary_screen=${X11_SCREEN_PREFERRED} 49 | else 50 | x11_primary_screen=${x11_available_screens_a[0]} 51 | fi 52 | 53 | # Start building xrandr command line 54 | for ((i=0;i<${#x11_available_screens_a[@]};++i)); do 55 | if [[ "${x11_available_screens_a[$i]}" == "${x11_primary_screen}" ]]; then 56 | x11_primary_mode=${x11_available_screen_modes_a[$i]} 57 | x11_primary_rate=${x11_available_screen_rates_a[$i]} 58 | break 59 | fi 60 | done 61 | declare -a xrandr_args_a=("--dpi" "${X11_DISPLAY_DPI}" "--output" "${x11_primary_screen}" "--primary" 62 | "--mode" "${x11_primary_mode}" 63 | "--rate" "${x11_primary_rate}") 64 | 65 | for ((i=0;i<${#x11_available_disabled_screens_a[@]};++i)); do 66 | xrandr_args_a+=("--output" "${x11_available_disabled_screens_a[$i]}" "--off") 67 | done 68 | 69 | if [[ "${X11_SCREEN_USE_ALL_AVAILABLE}" == "yes" ]]; then 70 | # Add remaining available screens, except the primary screen 71 | for ((i=0;i<${#x11_available_screens_a[@]};++i)); do 72 | screen="${x11_available_screens_a[$i]}" 73 | if [[ "${screen}" != "${x11_primary_screen}" ]]; then 74 | xrandr_args_a+=("--output" "${screen}" 75 | "--mode" "${x11_available_screen_modes_a[$i]}" 76 | "--rate" "${x11_available_screen_rates_a[$i]}") 77 | fi 78 | done 79 | else 80 | # Disable all remaining available screens except the primary screen 81 | for ((i=0;i<${#x11_available_screens_a[@]};++i)); do 82 | screen="${x11_available_screens_a[$i]}" 83 | if [[ "${screen}" != "${x11_primary_screen}" ]]; then 84 | xrandr_args_a+=("--output" "${screen}" "--off") 85 | fi 86 | done 87 | fi 88 | echo ${xrandr} ${xrandr_args_a[*]} 89 | ${xrandr} ${xrandr_args_a[*]} 90 | # Place screens relative to each other, if needed 91 | if [[ "${X11_SCREEN_USE_ALL_AVAILABLE}" == "yes" ]] && [[ ${#x11_available_screen_order_a[@]} -gt 1 ]]; then 92 | declare -a xrandr_screen_order_args_a 93 | left_screen=${x11_available_screen_order_a[0]} 94 | for ((i=1;i<${#x11_available_screen_order_a[@]};++i)); do 95 | screen="${x11_available_screens_a[$i]}" 96 | xrandr_screen_order_args_a+=("--output" "${screen}" "--right-of" "${left_screen}") 97 | left_screen=${screen} 98 | done 99 | echo ${xrandr} ${xrandr_screen_order_args_a[*]} 100 | ${xrandr} ${xrandr_screen_order_args_a[*]} 101 | fi 102 | else 103 | echo "No available X11 screens in X11_SCREEN_LIST" 104 | fi 105 | else 106 | echo "X11_SCREEN_LIST is empty" 107 | fi 108 | -------------------------------------------------------------------------------- /set_xmodmap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo DISPLAY $DISPLAY >>/tmp/jw_xmodmap 3 | /usr/bin/xmodmap -verbose /home/jw/.Xmodmap.exwm 2>&1 >>/tmp/jw_xmodmap 4 | --------------------------------------------------------------------------------