11 KiB
Aner's Emacs EXWM Configuration
Base setup
Require
(require 'azos-emacs-station)
(require 'azos-emacs-base)
EXWM
We execute the following code only if started with EXWM argument
EXWM Setup
(defvar azos/exwm/load-hook nil "Load EXWM hook")
(defun azos/exwm/load-exwm (switch) "Loads EXWM"
(use-package exwm
:ensure t
:config
(require 'exwm)
(require 'exwm-randr)
;Workspaces
(setq exwm-workspace-number 4
exwm-layout-show-all-buffers t
exwm-workspace-show-all-buffers t)
;System tray
(require 'exwm-systemtray)
(setq exwm-systemtray-background-color "LightYellow3")
(exwm-systemtray-enable)
;In EXWM mode, no evil
(add-to-list 'evil-emacs-state-modes 'exwm-mode)
(run-hooks 'azos/exwm/load-hook)
;Enable
(exwm-randr-enable)
(exwm-enable)
))
Smart buffer naming
(add-hook 'azos/exwm/load-hook (lambda () (progn
(add-hook 'exwm-update-class-hook
(lambda ()
(unless (or (string-prefix-p "sun-awt-X11-" exwm-instance-name)
(string= "gimp" exwm-instance-name))
(string-prefix-p "qute" exwm-instance-name)
(exwm-workspace-rename-buffer exwm-class-name))))
(add-hook 'exwm-update-title-hook
(lambda ()
(when (or (not exwm-instance-name)
(string-prefix-p "sun-awt-X11-" exwm-instance-name)
(string-prefix-p "qute" exwm-instance-name)
(string= "gimp" exwm-instance-name))
(exwm-workspace-rename-buffer exwm-title))))
(add-hook 'exwm-update-class-hook
(lambda ()
(when (or (not exwm-instance-name)
(string-prefix-p "mpv" exwm-class-name))
(exwm-workspace-rename-buffer (concat "mpv | " exwm-title)))))
)))
Basic keybindings
Global keybindings can be defined with `exwm-input-global-keys'. Here are a few examples:
(add-hook 'azos/exwm/load-hook (lambda ()
(setq exwm-input-global-keys
`(
;; Bind "s-<f2>" to "slock", a simple X display locker.
([s-f2] . (lambda ()
(interactive)
(start-process "" nil "/usr/bin/slock")))
([s-<tab>] . persp-switch)
;; Bind "s-r" to exit char-mode and fullscreen mode.
([?\s-r] . exwm-reset)
;; Bind "s-w" to switch workspace interactively.
([?\s-w] . exwm-workspace-switch)
;; Bind "s-0" to "s-9" to switch to a workspace by its index.
,@(mapcar (lambda (i)
`(,(kbd (format "s-%d" i)) .
(lambda ()
(interactive)
(exwm-workspace-switch-create ,i))))
(number-sequence 0 9))
;; Bind "s-&" to launch applications ('M-&' also works if the output
;; buffer does not bother you).
([?\s-&] . (lambda (command)
(interactive (list (read-shell-command "$ ")))
(start-process-shell-command command nil command)))
))))
(defun azos/exwm/take-screenshot ()
(interactive)
(shell-command "flameshot gui")
)
(defun azos/exwm/start-qutebrowser ()
(interactive)
(start-process "qutebrowser" nil "qutebrowser"))
(add-hook 'azos/exwm/load-hook (lambda () (progn
(define-key azos/global-minor-mode/open-keymap
(kbd "q") 'azos/exwm/start-qutebrowser)
(define-key azos/global-minor-mode/keymap
(kbd "<print>") 'azos/exwm/take-screenshot))))
Better modeline
This currently does nothing and I am not sure why.
(defvar azos/exwm/modeline-hash-table (make-hash-table)
"Table to store relative face change cookies in")
(defface azos/exwm/modeline-remap-style
(list (list t (list :background azos/evil-color-insert)))
"Make the backgrounds pop to green")
(defun azos/exwm/input-mode-modeline () "Changes modeline based on input mode"
(let ((currbuff (current-buffer)))
(if (eq exwm--input-mode 'char-mode)
;;line
(let ((remap-cookie (gethash currbuff
azos/exwm/modeline-hash-table)))
(if remap-cookie
(progn
(face-remap-remove-relative remap-cookie)
(remhash currbuff
azos/exwm/modeline-hash-table))))
;;char
(puthash
currbuff
(face-remap-add-relative 'mode-line
'azos/exwm/modeline-remap-style)
azos/exwm/modeline-hash-table)
)))
(add-hook 'exwm-input-input-mode-change-hook 'azos/exwm/input-mode-modeline)
;; (set-face-attribute 'mode-line nil :box nil :background "AliceBlue")
;; (set-face-attribute 'mode-line-inactive nil :box nil :background "LightYellow3")
RANDR screen settings
Enabling randr. Automatic mapping of randr screens to workspaces.
(defun azos/exwm/get-monitor-list ()
(mapcar (lambda (x) (match-string (string-match "^[A-Za-z]+-*[0-9]+" x) x))
(azos/re-seq "^[A-Za-z]+-*[0-9]+ connected"
(shell-command-to-string "xrandr"))))
(defun azos/exwm/add-indexes (list)
(azos/exwm/add-indexes-i list 1)
)
(defun azos/exwm/add-indexes-i (list i)
(if list
(cons i (cons (car list) (azos/exwm/add-indexes-i (cdr list) (+ i 1))))
nil))
(defun azos/exwm/update-randr-monitor-plist ()
(interactive)
(progn
(start-process
"xlayoutdisplay" nil "xlayoutdisplay")
(setq exwm-randr-workspace-monitor-plist
(azos/exwm/add-indexes (azos/exwm/get-monitor-list)))
(exwm-randr-refresh)))
(add-hook 'azos/exwm/load-hook (lambda () (progn
(add-hook 'exwm-randr-screen-change-hook
'azos/exwm/update-randr-monitor-plist)
(define-key azos/global-minor-mode/keymap
(kbd "s-x") 'azos/exwm/update-randr-monitor-plist))))
Prefix keys
Sending simulated keys to X windows
(add-hook 'azos/exwm/load-hook (lambda () (progn
(setq exwm-input-prefix-keys
'(?\C-x ?\C-u ?\C-h ?\M-x ?\M-& ?\M-: ?\s-d
?\s-m ?\s-r ?\s-s ?\s-q ?\H-l ?\C-w)))))
Desktop environment
(use-package desktop-environment :after exwm)
Bluetooth
(use-package bluetooth :after exwm)
Pulse
(use-package pulseaudio-control :after exwm)
Media keys
https://gist.github.com/ajyoon/5323b999a01dce8db2d4456da1740fe3
(add-hook 'azos/exwm/load-hook (lambda ()
(progn
(dolist (k '(
XF86AudioLowerVolume
XF86AudioRaiseVolume
XF86AudioPlay
XF86AudioStop
XF86AudioPrev
XF86AudioNext))
(push k exwm-input-prefix-keys))
(exwm-input-set-key
(kbd "<XF86AudioRaiseVolume>")
(lambda ()
(interactive) (start-process
"pactl" nil "pactl" "set-sink-volume" "0" "+5%")))
(exwm-input-set-key
(kbd "<XF86AudioLowerVolume>")
(lambda ()
(interactive) (start-process
"pactl" nil "pactl" "set-sink-volume" "0" "-5%")))
(exwm-input-set-key
(kbd "<XF86AudioMute>")
(lambda ()
(interactive) (start-process
"pactl" nil "pactl" "set-sink-mute" "0" "toggle")))
(exwm-input-set-key
(kbd "<XF86AudioPlay>")
'desktop-environment-toggle-music)
(exwm-input-set-key
(kbd "<XF86AudioNext>")
'desktop-environment-music-next)
(exwm-input-set-key
(kbd "<XF86AudioPrev>")
'desktop-environment-music-previous)
(exwm-input-set-key
(kbd "<XF86AudioStop>")
'desktop-environment-music-stop)
(exwm-input-set-key
(kbd "<XF86AudioPause>")
'desktop-environment-toggle-music)
(exwm-input-set-key
(kbd "<XF86MonBrightnessUp>")
(lambda ()
(interactive) (start-process
"light" nil "light" "-A" "5")))
(exwm-input-set-key
(kbd "<XF86MonBrightnessDown>")
(lambda ()
(interactive) (start-process
"light" nil "light" "-U" "5")))
)))
In the event xbacklight doesn't work, the following command can be run:
xrandr --output eDP1 --brightness 0.5
Dedicated processes
We'd want to be able to quickly map processes (Spotify, etc.) to keybindings, and have dedicated buffers for them (so they don't reopen).
We first define variables to be used later, and a function that checks, for each new process, should it be displayed in a new buffer/tab.
(defvar azos/exwm/startproc-regex-buffname-list nil
"Match between buffer and tab.")
(defun azos/exwm/startproc-check-for-buff-entry ()
"On new buffer, check if requested to display differently"
(let ((entry (cdr (car (seq-filter
(lambda (e) (string-match (car e) (buffer-name)))
azos/exwm/startproc-regex-buffname-list
)))))
(if entry
(let ((rn (nth 0 entry)) (tn (nth 1 entry)) (buff (current-buffer)))
;; Too much complication for renaming
;; (if requested-name (rename-buffer requested-name))
(progn
(if tn (tab-bar-switch-to-tab tn))
(switch-to-buffer buff)
)))))
(add-hook 'exwm-manage-finish-hook 'azos/exwm/startproc-check-for-buff-entry)
(defun azos/exwm/start-proc-dedicated
(name tab-name procregex proc &rest args)
(let ((buff (car (seq-filter (lambda (b
)
(string-match procregex (buffer-name b)))
(buffer-list)))))
(if buff
;; Found buffer, display
(progn
(if tab-name (tab-bar-switch-to-tab tab-name))
(switch-to-buffer buff)
)
;;No known buffer, add entry to alist
(let ((new-entry `(,procregex ,tab-name ,name))) (progn
(add-to-list 'azos/exwm/startproc-regex-buffname-list
new-entry)
(apply 'start-process name nil proc
args))))))
EXWM Ending
End the execute only if EXWM block.
(add-to-list 'command-switch-alist '("--start-exwm" . azos/exwm/load-exwm))
Provide
(provide 'azos-emacs-exwm)
(add-hook 'after-init-hook (lambda () (require 'azos-emacs-exwm)))