Skip to content

Instantly share code, notes, and snippets.

@alexforsale
Created February 12, 2023 09:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexforsale/7d2390700ac9d6f130854747acc8c7e7 to your computer and use it in GitHub Desktop.
Save alexforsale/7d2390700ac9d6f130854747acc8c7e7 to your computer and use it in GitHub Desktop.
WIP exwm configuration
;;; Config --- Exwm Configuration -*- emacs-lisp -*-
;;; Commentary:
;;; Code:
;; system-tray
(use-package exwm)
(use-package desktop-environment)
(use-package pinentry)
(use-package exwm-modeline)
(use-package perspective)
(use-package perspective-exwm)
(use-package which-key)
(require 'exwm-systemtray)
(exwm-systemtray-enable)
(setq exwm-systemtray-height 12) ; default 16
(require 'exwm)
;; variables
(setq exwm-workspace-show-all-buffers nil ; keep buffers per workspace
exwm-workspace-warp-cursor t ; after workspace switch
mouse-autoselect-window t ; like any other tiling window manager
focus-follows-mouse nil
exwm-workspace-number 1
)
;; hooks
;; things that should runs after initializing exwm
(defun +config/exwm-init-hook ()
"Things that should run after initialization."
(when (file-exists-p "~/.fehbg")
(exwm/run-in-background "~/.fehbg"))
(exwm/run-in-background "xrdg -merge ~/.Xresources")
(exwm/run-in-background "xsetroot -cursor_name left_ptr")
(exwm/run-in-background "xset r rate 300 30")
(exwm/run-in-background "nm-applet")
(exwm/run-in-background "iwgtk -i")
(exwm/run-in-background "/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1")
(exwm/run-in-background "picom")
(exwm/run-in-background "udiskie -t")
(exwm/run-in-background "dunst -conf ~/.config/dunst/dunstrc")
(exwm/run-in-background "light-locker")
(exwm/run-in-background "wal --theme solarized")
(exwm/run-in-background "blueman-applet")
(exwm/run-in-background "volumeicon")
(exwm/run-in-background "xsettingsd")
(exwm/run-in-background "unclutter")
(exwm/run-in-background "greenclip daemon>/dev/null")
(exwm/run-in-background "/usr/lib/geoclue-2.0/demos/agent")
;;(exwm/run-in-background "keepassxc ~/Sync/Password.kdbx")
)
;; normal hook run when `exwm' has just finished initializing
(add-hook 'exwm-init-hook #'+config/exwm-init-hook)
(add-hook 'exwm-init-hook #'exwm-modeline-mode)
(defun +config/fix-exwm-floating-windows ()
"Fix behaviour when switching to floating."
(setq-local exwm-workspace-warp-cursor nil)
(setq-local mouse-autoselect-window nil)
(setq-local focus-follows-mouse nil))
;; normal hook run when an X window has been made floating
(add-hook 'exwm-floating-setup-hook
(progn
#'+config/fix-exwm-floating-windows
(lambda ()
(exwm-layout-hide-mode-line))))
;; normal hook run when window title is updated
(add-hook 'exwm-update-title-hook
(lambda ()
(when (or (not exwm-instance-name)
(string-prefix-p "sun-awt-X11-" exwm-instance-name)
(string= "gimp" exwm-instance-name))
(exwm-workspace-rename-buffer exwm-title))))
;; Make buffer name more meaningful
(add-hook 'exwm-update-class-hook
(progn
(lambda ()
(exwm-workspace-rename-buffer exwm-class-name))
(lambda ()
(pcase exwm-class-name
("firefox" (exwm-workspace-rename-buffer (format "%s" exwm-title)))))))
(defvar +config/exwm-workspace--switch-history-hack (cons exwm-workspace-current-index '()))
(defun +config/exwm-workspace-switch-to-last ()
"Switch to last visited workspace."
(interactive)
"Switch to the workspace that was used before current workspace"
(exwm-workspace-switch (cdr +config/exwm-workspace--switch-history-hack)))
;; normal hook run after switching workspace
(add-hook 'exwm-workspace-switch-hook
(lambda ()
(setq +config/exwm-workspace--switch-history-hack
(cons exwm-workspace-current-index
(car +config/exwm-workspace--switch-history-hack)))))
(defun exwm/run-in-background (command)
"Run COMMAND in background if exists."
(let ((command-parts (split-string command "[ ]+")))
(when (executable-find (car command-parts))
(apply #'call-process `(,(car command-parts) nil 0 nil ,@(cdr command-parts))))))
(defun +config/raise-or-run (suffix &optional cmd)
"Raises the buffer with SUFFIX otherwise runs the CMD (if provided) or SUFFIX"
(let ((existing-buffer
(mb/buffer-with-suffix suffix)))
(if existing-buffer
(if (string= (buffer-name (current-buffer)) (buffer-name existing-buffer))
(bury-buffer)
(if (get-buffer-window existing-buffer)
(pop-to-buffer existing-buffer)
(exwm-workspace-switch-to-buffer existing-buffer)))
(start-process-shell-command suffix nil cmd))))
(setq +config/exwm-manage-configurations
;; workspace 0 reserved for terminal emulators
'(((string= exwm-class-name "Xterm") workspace 0)
((string= exwm-class-name "Termite") workspace 0)
((string= exwm-class-name "URxvt") workspace 0)
;; windows 1 is exclusively for `Emacs'
;; windows 2 is for web browsers
((string= exwm-class-name "firefox") workspace 2)
((string= exwm-class-name "Nyxt") workspace 2)
((string= exwm-class-name "qutebrowser") workspace 2)
;; workspace 3 for mail apps
((string= exwm-class-name "Thunderbird") workspace 3)
((string= exwm-class-name "Mail") workspace 3)
;; workspace 4 is for Multimedia apps
((string= exwm-class-name "Spotify") workspace 4)
((string= exwm-class-name "Cheese") workspace 4)
((string= exwm-class-name "Picard") workspace 4)
((string= exwm-class-name "hakuneko-desktop") workspace 4)
((string= exwm-class-name "mpv") workspace 4)
((string= exwm-class-name "vlc") workspace 4)
((string= exwm-class-name "Gimp") workspace 4)
;; workspace 5 for Network apps
((string= exwm-class-name "Org.remmina.Remmina") workspace 5)
((string= exwm-class-name "Virt-manager") workspace 5)
((string= exwm-class-name "Vncviewer") workspace 5)
;; workspace 6 for messaging
((string= exwm-class-name "TelegramDesktop") workspace 6)
;; workspace 7 for other editors
((string= exwm-class-name "libreoffice-startcenter") workspace 7)
((string= exwm-class-name "libreoffice-calc") workspace 7)
((string= exwm-class-name "libreoffice-draw") workspace 7)
((string= exwm-class-name "libreoffice-math") workspace 7)
((string= exwm-class-name "libreoffice-writer") workspace 7)
))
(defun +config/exwm-logout ()
"Logout cleanly from EXWM."
(interactive)
(recentf-save-list)
(save-some-buffers)
(save-buffers-kill-terminal))
(defun +config/exwm-terminal ()
"Set the default terminal."
(interactive)
(let ((terminal
(or
(getenv "TERMINAL")
(executable-find "xterm")
(executable-find "urxvt")
(executable-find "termite"))))
(exwm/run-in-background terminal)
(message "s-<f11> to toggle fullscreen")))
(defun +config/rofi-launcher ()
"Run rofi."
(interactive)
(exwm/run-in-background "rofi -show drun -theme exwm"))
(defun +config/greenclip-launcher ()
"Run greenclip."
(interactive)
(exwm/run-in-background "rofi-greenclip exwm"))
;; (customize-set-variable 'persp-initial-frame-name "Main")
;; (if (boundp '+emacs-data-dir)
;; (customize-set-variable 'persp-state-default-file (expand-file-name "statesave" +emacs-data-dir))
;; (progn (let ((emacs-data-dir (expand-file-name ".local/share/emacs" (getenv "HOME"))))
;; (customize-set-variable 'persp-state-default-file (expand-file-name "statesave" emacs-data-dir)))))
;; (customize-set-variable 'persp-mode-prefix-key (kbd "C-c b"))
;; Disable menu-bar, tool-bar and scroll-bar to increase the usable space.
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
;; Also shrink fringes to 1 pixel.
(fringe-mode 1)
(require 'time)
(setq display-time-default-load-average nil)
(customize-set-variable 'display-time-24hr-format t)
(customize-set-variable 'display-time-day-and-date t)
(display-time-mode 1)
;; (cond ((not (directory-empty-p "/sys/class/power_supply/"))
;; (display-battery-mode)))
(if (and (fboundp 'server-running-p)
(not (server-running-p)))
(server-start))
(require 'recentf)
;; (setq-default persp-mode-prefix-key (kbd "C-c TAB"))
(require 'perspective)
(require 'perspective-exwm)
(customize-set-variable 'persp-mode-prefix-key (kbd "C-c TAB"))
(unless (equal persp-mode t)
(persp-mode))
(customize-set-variable 'perspective-exwm-override-initial-name
'((0 . "Term")
(1 . "Dev")
(2 . "Web")
(3 . "Files")
(4 . "Multimedia")
(5 . "Chat")
(6 . "Remotes")
(7 . "Games")
(8 . "Work")
(9 . "Others")))
(setenv "GPG_AGENT_INFO" nil) ;; use emacs pinentry
(setq auth-source-debug t)
(setq epg-gpg-program "gpg2") ;; not necessary
(require 'epa-file)
(unless (featurep 'epa)
(epa-file-enable))
(setq epg-pinentry-mode 'loopback)
(pinentry-start)
(require 'org-crypt)
(org-crypt-use-before-save-magic)
(require 'which-key)
(which-key-setup-side-window-right-bottom)
(customize-set-variable 'desktop-environment-brightness-small-increment "1%+")
(customize-set-variable 'desktop-environment-brightness-small-decrement "1%-")
(customize-set-variable 'desktop-environment-brightness-normal-increment "1%+")
(customize-set-variable 'desktop-environment-brightness-normal-decrement "1%-")
(customize-set-variable 'desktop-environment-volume-normal-decrement "1%-")
(customize-set-variable 'desktop-environment-volume-normal-increment "1%+")
(customize-set-variable 'desktop-environment-screenshot-command "flameshot gui")
(customize-set-variable 'desktop-environment-screenshot-directory (expand-file-name "Screenshots/" (getenv "XDG_PICTURES_DIR")))
(unless (file-directory-p desktop-environment-screenshot-directory)
(make-directory desktop-environment-screenshot-directory :parents))
(when (featurep 'emms)
(with-eval-after-load 'desktop-environment
(customize-set-variable 'desktop-environment-music-next-command nil)
(customize-set-variable 'desktop-environment-music-previous-command nil)
(customize-set-variable 'desktop-environment-music-stop-command nil)
(customize-set-variable 'desktop-environment-music-toggle-command nil)
(define-key desktop-environment-mode-map (kbd "<XF86AudioNext>") #'emms-next)
(define-key desktop-environment-mode-map (kbd "<XF86AudioPrev>") #'emms-previous)
(define-key desktop-environment-mode-map (kbd "<XF86AudioPlay>") #'emms-pause)
(global-set-key (kbd "M-s-<f12>") #'emms-next)
(global-set-key (kbd "M-s-<f11>") #'emms-pause)
(global-set-key (kbd "M-s-<f10>") #'emms-previous)
(global-set-key (kbd "M-s-<f9>") 'desktop-environment-volume-increment)
(global-set-key (kbd "M-s-<f8>") 'desktop-environment-volume-decrement)
(global-set-key (kbd "M-s-<f7>") 'desktop-environment-toggle-mute)))
(unless (featurep 'emms)
(with-eval-after-load 'desktop-environment
(global-set-key (kbd "M-s-<f12>") 'desktop-environment-music-next)
(global-set-key (kbd "M-s-<f11>") 'desktop-environment-toggle-music)
(global-set-key (kbd "M-s-<f10>") 'desktop-environment-music-previous)
(global-set-key (kbd "M-s-<f9>") 'desktop-environment-volume-increment)
(global-set-key (kbd "M-s-<f8>") 'desktop-environment-volume-decrement)
(global-set-key (kbd "M-s-<f7>") 'desktop-environment-toggle-mute)))
(desktop-environment-mode)
(require 'battery)
(with-eval-after-load 'battery
(when
(or
(eq battery-status-function
'battery-upower)
(eq battery-status-function
'battery-bsd-apm)
(eq battery-status-function
'battery-linux-sysfs)
(eq battery-status-function
'battery-linux-proc-apm)
(eq battery-status-function
'battery-linux-proc-acpi))
(display-battery-mode)))
(exwm-input-set-key (kbd "C-x C-c") '+config/exwm-logout)
;; (exwm-input-set-key (kbd "s-F3") )
(defun +config/setup-header-line-format ()
"Hide header line if required."
(set-window-parameter (next-window) 'header-line-format
(unless (window-at-side-p (next-window) 'top)
'none)))
(add-hook 'window-configuration-change-hook #'+config/setup-header-line-format)
(setq exwm-input-global-keys
`(
;; 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)
([?\s-q] . delete-window)
([?\s-j] . next-buffer)
([?\s-k] . previous-buffer)
([?\s-m] . exwm-layout-toggle-mode-line)
;; 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))
([s-tab] . +config/exwm-workspace-switch-to-last)
;; ([s-return] . +config/exwm-terminal)
([?\s-d] . +config/rofi-launcher)
([?\s-c] . +config/greenclip-launcher)
;; Bind "s-&" to launch applications ('M-&' also works if the output
;; buffer does not bother you).
([?\s-D] . (lambda (command)
(interactive (list (read-shell-command "$ ")))
(start-process-shell-command command nil command)))
([s-f11] . exwm-layout-toggle-fullscreen)
;; Bind "s-<f2>" to "slock", a simple X display locker.
([s-f1] . (lambda ()
(interactive)
(start-process "" nil "/usr/bin/slock")))))
;; Ctrl+Q will enable the next key to be sent directly
(define-key exwm-mode-map [?\C-q] #'exwm-input-send-next-key)
;; Make Doom's leader work.
;; (when (featurep 'doom)
;; (exwm-input-set-key (kbd doom-leader-alt-key) doom-leader-map))
;;(setq exwm-workspace-minibuffer-position 'bottom)
(setq +config/simulation-key-window-classes
'(google-chrome firefox qutebrowser))
(add-hook 'exwm-manage-finish-hook
(lambda ()
(when (and exwm-class-name (member exwm-class-name +config/simulation-key-window-classes))
(exwm-input-set-local-simulation-keys
'(
;; movement
([?\C-b] . [left])
([?\M-b] . [C-left])
([?\C-f] . [right])
([?\M-f] . [C-right])
([?\C-p] . [up])
([?\C-n] . [down])
([?\C-a] . [home])
([?\C-e] . [end])
([?\M-v] . [prior])
([?\C-v] . [next])
([?\C-d] . [delete])
;;([?\C-k] . [S-end delete])
;; cut/paste.
([?\C-w] . [?\C-x])
([?\M-w] . [?\C-c])
([?\C-y] . [?\C-v])
([?\C-c ?\C-c] . [?\C-c])
([?\C-w ?\C-w] . [?\C-w])
([?\C-v ?\C-v] . [?\C-v])
;; search
([?\C-s] . [?\C-f]))))))
;; (when (featurep doom)
;; (exwm-input-set-key (kbd "<s-return>") '+vterm/here))
;; firefox
(exwm-input-set-key (kbd "<s-b>")
(lambda ()
(interactive)
(+config/raise-or-run "Firefox" "firefox")))
(with-eval-after-load 'all-the-icons
(add-to-list 'all-the-icons-mode-icon-alist
'(exwm-mode all-the-icons-faicon "desktop"
:height 1.0 :face all-the-icons-purple)))
;;(start-process-shell-command "xrandr" nil "xrandr --output Virtual-0 --mode 1366x768")
(require 'perspective-exwm)
(perspective-exwm-mode)
(require 'exwm-randr)
(exwm-randr-enable)
(when (featurep 'diminish)
(diminish 'desktop-environment-mode))
(exwm-enable)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment