diff options
| -rw-r--r-- | config.org | 141 |
1 files changed, 141 insertions, 0 deletions
@@ -1453,6 +1453,147 @@ This section is purely used to help me with editing root owned files, without ca (tramp-remote-shell-args ("-c")) (tramp-connection-timeout 10)))) #+end_src +* EXWM +#+begin_quote +Who needs a WM if you have Emacs? +#+end_quote +EXWM is the Emacs X Window Manager. +#+begin_src emacs-lisp :tangle ~/.config/doom/packages.el +(package! exwm) +(package! edwina) ; dynamic tiling +(package! exwm-edit) ; edit X text fields in an Emacs buffer +(package! exwm-mff) ; mouse follows focus +(package! app-launcher :recipe (:host github :repo "SebastienWae/app-launcher")) +#+end_src + +** Helpers and bindings +#+begin_src emacs-lisp +(defconst my/exwm-session-p (and (getenv "EXWM") t)) + +(defun my/spawn (cmd) + "Return a command that runs shell CMD." + (lambda () (interactive) (start-process-shell-command cmd nil cmd))) + +(defun my/run-once (cmd) + "Run CMD only if no process named like its executable is already running." + (let ((name (file-name-nondirectory (car (split-string cmd))))) + (start-process-shell-command + cmd nil (format "pgrep -x %s >/dev/null || %s" (shell-quote-argument name) cmd)))) + +(defun my/close-window () + (interactive) + (kill-buffer) + (when (cdr (window-list)) + (edwina-delete-window))) + +(defconst my/spawn-binds + '(("s-<return>" . "alacritty") ("s-w" . "vivaldi") ("s-e" . "xfe") + ("s-s" . "discord") ("s-x" . "loginctl lock-session") + ("<print>" . "screenshot") ("S-<print>" . "screenrecord") + ("s-S" . "screenshot select") ("s-R" . "screenrecord select") + ("<XF86AudioRaiseVolume>" . "wpctl set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ 5%+") + ("<XF86AudioLowerVolume>" . "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-") + ("<XF86AudioMute>" . "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle") + ("<XF86AudioPlay>" . "playerctl play-pause") + ("<XF86AudioNext>" . "playerctl next") + ("<XF86AudioPrev>" . "playerctl previous"))) + +(defconst my/wm-binds + '(("s-r" . exwm-reset) + ("s-p" . app-launcher-run-app) + ("s-j" . edwina-select-next-window) + ("s-k" . edwina-select-previous-window) + ("s-J" . edwina-swap-next-window) + ("s-K" . edwina-swap-previous-window) + ("s-h" . edwina-dec-mfact) + ("s-l" . edwina-inc-mfact) + ("s-H" . edwina-inc-nmaster) + ("s-L" . edwina-dec-nmaster) + ("s-m" . edwina-zoom) ; promote to master, dwm-style + ("s-q" . my/close-window) + ("s-f" . exwm-floating-toggle-floating) + ("C-s-q" . save-buffers-kill-emacs))) + +(defconst my/ws-binds + (cl-loop for i from 0 below 9 + for sym in '("!" "@" "#" "$" "%" "^" "&" "*" "(") + collect (cons (format "s-%d" (1+ i)) + (let ((ws i)) (lambda () (interactive) (exwm-workspace-switch-create ws)))) + collect (cons (format "s-%s" sym) + (let ((ws i)) (lambda () (interactive) (exwm-workspace-move-window ws)))))) + +(defun my/exwm-key (spec) + (cons (kbd (car spec)) + (if (stringp (cdr spec)) (my/spawn (cdr spec)) (cdr spec)))) +#+end_src + +** EXWM itself +#+begin_src emacs-lisp +(use-package! exwm + :when my/exwm-session-p + :config + (setenv "EXWM" nil) + (setq exwm-workspace-number 9 + exwm-manage-configurations + '(((member exwm-class-name '("Alacritty")) char-mode t) + ((equal exwm-class-name "discord") workspace 8) + ((member exwm-class-name '("Pavucontrol" "Blueman-manager" "ssh-askpass" "Gcr-prompter")) + floating t) + ((equal exwm-title "pinentry") floating t)) + exwm-input-global-keys + (mapcar #'my/exwm-key (append my/spawn-binds my/wm-binds my/ws-binds)) + exwm-input-simulation-keys + '(([?\C-b] . [left]) ([?\C-f] . [right]) + ([?\C-p] . [up]) ([?\C-n] . [down]) + ([?\C-a] . [home]) ([?\C-e] . [end]) + ([?\C-d] . [delete]) ([?\C-k] . [S-end delete]) + ([?\C-w] . [?\C-x]) ([?\M-w] . [?\C-c]) ([?\C-y] . [?\C-v]))) + + (cl-pushnew ?\C-c exwm-input-prefix-keys) + + (add-hook 'exwm-update-class-hook + (lambda () (exwm-workspace-rename-buffer exwm-class-name))) + (add-hook 'exwm-update-title-hook + (lambda () + (exwm-workspace-rename-buffer + (format "%s | %s" exwm-class-name + (truncate-string-to-width (or exwm-title "") 40 nil nil "…"))))) + + (add-hook 'exwm-mode-hook #'doom-mark-buffer-as-real-h) + (advice-add #'suspend-frame :override #'ignore) + + (add-hook 'exwm-init-hook + (lambda () + (start-process-shell-command + "dbus-env" nil "dbus-update-activation-environment DISPLAY XAUTHORITY") + (dolist (c '("feh --bg-scale ~/Pictures/floating_gnu.png" "xset m 0")) + (start-process-shell-command c nil c)) + (my/run-once "~/.cargo/bin/mprisence"))) + + (if (fboundp 'exwm-systemtray-mode) (exwm-systemtray-mode 1) (exwm-systemtray-enable)) + (if (fboundp 'exwm-wm-mode) (exwm-wm-mode 1) (exwm-enable))) ; 0.34+ vs 0.33 + +(use-package! exwm-edit + :when my/exwm-session-p + :after exwm + :config (setq exwm-edit-split "below")) + +(use-package! exwm-mff + :when my/exwm-session-p + :hook (exwm-init . exwm-mff-mode)) +#+end_src +** Edwina +Edwina lets EXWM become a dynamically tiling window manager. +#+begin_src emacs-lisp +(use-package! edwina + :when my/exwm-session-p + :after exwm + :config + (setq display-buffer-base-action '(display-buffer-below-selected) + edwina-mfact 0.50 + edwina-narrow-threshold 0) + (edwina-mode 1)) +#+end_src * Evil ~Mapping at its finest~ EVIl mode emulates VIM bindings in Emacs. |
