EXWM Configuration
Package Requirements
(require 'exwm)
(require 'exwm-randr)
;; (require 'exwm-systemtray)
Helper Functions
System Integration
(defun efs/run-in-background (command)
"Execute shell command in background"
(let ((command-parts (split-string command "[ ]+")))
(apply 'call-process `(,(car command-parts) nil 0 nil ,@(cdr command-parts)))))
(defun efs/set-wallpaper ()
"Set desktop wallpaper using feh"
(interactive)
(start-process-shell-command
"feh" nil "feh --bg-scale ~/Pictures/lain_wallpaper/lain_bear_frappe.png"))
Window Management
(defun efs/configure-window-by-class ()
"Automatically configure windows based on class"
(interactive)
(pcase exwm-class-name
("Firefox" (exwm-workspace-move-window 2))
("Sol" (exwm-workspace-move-window 3))
("mpv" (exwm-floating-toggle-floating)
(exwm-layout-toggle-mode-line))))
(defun efs/exwm-update-class ()
"Update buffer name to window class"
(exwm-workspace-rename-buffer exwm-class-name))
(defun efs/exwm-update-title ()
"Update buffer name with window title for specific apps"
(pcase exwm-class-name
("Firefox" (exwm-workspace-rename-buffer (format "Firefox: %s" exwm-title)))))
Polybar Integration
(defvar efs/polybar-process nil "Polybar process handle")
(defun efs/kill-panel ()
"Stop Polybar process"
(interactive)
(when efs/polybar-process
(kill-process efs/polybar-process))
(setq efs/polybar-process nil))
(defun efs/start-panel ()
"Start Polybar panel"
(interactive)
(efs/kill-panel)
(setq efs/polybar-process (start-process-shell-command "polybar" nil "polybar panel")))
(defun efs/send-polybar-exwm-workspace ()
"Update Polybar workspace indicator"
(start-process-shell-command
"polybar-msg" nil "polybar-msg hook exwm-workspace 1"))
(defun efs/polybar-exwm-workspace ()
"Get workspace icons for Polybar"
(pcase exwm-workspace-current-index
(0 "") (1 "") (2 "") (3 "") (4 "")))
(add-hook 'exwm-workspace-switch-hook 'efs/send-polybar-exwm-workspace)
Perspective EXWM Integration
;; First, ensure perspective.el is loaded
;; (use-package! perspective
;; :init
;; (setq persp-mode-prefix-key (kbd "C-c M-p"))
;; :config
;; (persp-mode))
;; Then load perspective-exwm before exwm-init
;; (use-package! perspective-exwm
;; :after (perspective exwm)
;; :config
;; (perspective-exwm-mode)
;; (setq perspective-exwm-override-initial-name
;; '((0 . "misc")
;; (1 . "core")
;; (2 . "browser")
;; (3 . "comms")
;; (4 . "dev")
;; (5 . "five")
;; (6 . "six")
;; (7 . "seven")
;; (8 . "eight")
;; (9 . "nine"))))
;; Hooks configuration
;; (add-hook 'exwm-update-class-hook 'efs/exwm-update-class)
;; (add-hook 'exwm-update-title-hook 'efs/exwm-update-title)
;; (add-hook 'exwm-manage-finish-hook 'efs/configure-window-by-class)
Keybindings
(setq exwm-input-prefix-keys '(?\M-x
?\M-:)
exwm-input-simulation-keys '(([?\s-F] . [?\C-f])
)
exwm-input-global-keys '(([?\M-\s-7] . (lambda (command)
(interactive (list (read-shell-command "$ ")))
(start-process-shell-command command nil command)))
;; splits
([?\s-v] . evil-window-vsplit)
([?\s-z] . evil-window-split)
;; managing workspaces
([?\s-w] . exwm-workspace-switch)
([?\s-W] . exwm-workspace-swap)
([?\s-\C-w] . exwm-workspace-move)
;; essential programs
([?\s-d] . dirvish)
([?\s-e] . eshell)
([s-return] . dmenu)
;; killing buffers and windows
([?\s-b] . ibuffer)
([?\s-B] . kill-current-buffer)
([?\s-C] .#+workspace/close-window-or-workspace)
;; change window focus with super+h,j,k,l
([?\s-h] . evil-window-left)
([?\s-j] . evil-window-next)
([?\s-k] . evil-window-prev)
([?\s-l] . evil-window-right)
;; move windows around using SUPER+SHIFT+h,j,k,l
([?\s-H] .#+evil/window-move-left)
([?\s-J] .#+evil/window-move-down)
([?\s-K] .#+evil/window-move-up)
([?\s-L] .#+evil/window-move-right)
;; move window to far left or far right with SUPER+CTRL+h,l
([?\s-\C-h] . side-left-window)
([?\s-\C-j] . side-bottom-window)
([?\s-\C-l] . side-right-window)
([?\s-\C-d] . side-window-delete-all)
([?\s-\C-r] . resize-window)
;; switch workspace with SUPER+{0-9}
([?\s-0] . (lambda () (interactive) (exwm-workspace-switch-create 0)))
([?\s-1] . (lambda () (interactive) (exwm-workspace-switch-create 1)))
([?\s-2] . (lambda () (interactive) (exwm-workspace-switch-create 2)))
([?\s-3] . (lambda () (interactive) (exwm-workspace-switch-create 3)))
([?\s-4] . (lambda () (interactive) (exwm-workspace-switch-create 4)))
([?\s-5] . (lambda () (interactive) (exwm-workspace-switch-create 5)))
([?\s-6] . (lambda () (interactive) (exwm-workspace-switch-create 6)))
([?\s-7] . (lambda () (interactive) (exwm-workspace-switch-create 7)))
([?\s-8] . (lambda () (interactive) (exwm-workspace-switch-create 8)))
([?\s-9] . (lambda () (interactive) (exwm-workspace-switch-create 9)))
;; move window workspace with SUPER+SHIFT+{0-9}
([?\s-\)] . (lambda () (interactive) (exwm-workspace-move-window 0)))
([?\s-!] . (lambda () (interactive) (exwm-workspace-move-window 1)))
([?\s-@] . (lambda () (interactive) (exwm-workspace-move-window 2)))
([?\s-] . (lambda () (interactive) (exwm-workspace-move-window 3)))
([?\s-$] . (lambda () (interactive) (exwm-workspace-move-window 4)))
([?\s-%] . (lambda () (interactive) (exwm-workspace-move-window 5)))
([?\s-^] . (lambda () (interactive) (exwm-workspace-move-window 6)))
([?\s-&] . (lambda () (interactive) (exwm-workspace-move-window 7)))
([?\s-*] . (lambda () (interactive) (exwm-workspace-move-window 8)))
([?\s-\(] . (lambda () (interactive) (exwm-workspace-move-window 9)))
;; SUPER+/ switches to char-mode (needed to pass commands in XWindows sometimes)
;; SUPER+? switches us back to line-mode
([?\s-/] . exwm-input-release-keyboard)
([?\s-?] . exwm-reset)
;; setting some toggle commands
([?\s-f] . exwm-floating-toggle-floating)
([?\s-m] . exwm-layout-toggle-mode-line)
([f11] . exwm-layout-toggle-fullscreen)))
Multi-Monitor Configuration
(defun dw/apply-screen-layout ()
"Configure multi-monitor setup"
(start-process-shell-command
"xrandr" nil
"xrandr --output HDMI-1 --mode 1920x1080 --pos 0x0 --rotate normal \
--output DP-1 --primary --mode 1920x1080 --rate 144 --pos 1920x0 --rotate normal \
--output DP-2 --mode 1920x1080 --pos 3840x0 --rotate normal"))
(setq exwm-randr-workspace-monitor-plist
'(1 "DP-1" 2 "DP-1" 3 "DP-1" 4 "DP-1" 5 "DP-1"
6 "DP-2" 7 "DP-2" 8 "HDMI-1" 9 "HDMI-1"))
(add-hook 'exwm-randr-screen-change-hook 'dw/apply-screen-layout)
(run-with-timer 2 nil 'dw/apply-screen-layout)
(exwm-randr-mode 1)
Visual Customization
;; Frame transparency
(set-frame-parameter (selected-frame) 'alpha '(90 . 90))
(add-to-list 'default-frame-alist '(alpha . (90 . 90)))
;; Frame size
(set-frame-parameter (selected-frame) 'fullscreen 'maximized)
(add-to-list 'default-frame-alist '(fullscreen . maximized))
;; Initial setup
(defun dw/exwm-init-hook ()
"Initialization hook for EXWM"
;; (exwm-workspace-switch-create 1)
;; (efs/start-panel)
;; (efs/run-in-background "pasystray")
;; (efs/run-in-background "blueman-applet")
;; (efs/run-in-background "flameshot")
;; (efs/set-wallpaper)
)
(add-hook 'exwm-init-hook 'dw/exwm-init-hook)
System Integration
;; Enable system tray (optional)
;; (exwm-systemtray-mode 1)
;; (setq exwm-systemtray-height 28)
;; (perspective-exwm-mode)
;; Start EXWM
(exwm-enable)
multi monitor code suggestion fix
(defun get-focused-monitor-geometry ()
"Get the geometry of the monitor displaying the selected frame in EXWM."
(let* ((monitor-attrs (frame-monitor-attributes))
(workarea (assoc 'workarea monitor-attrs))
(geometry (cdr workarea)))
(list (nth 0 geometry) ; X
(nth 1 geometry) ; Y
(nth 2 geometry) ; Width
(nth 3 geometry) ; Height
)))
(defun advise-corfu-make-frame-with-monitor-awareness (orig-fun frame x y width height buffer)
"Advise `corfu--make-frame` to be monitor-aware, adjusting X and Y according to the focused monitor."
;; Get the geometry of the currently focused monitor
(let* ((monitor-geometry (get-focused-monitor-geometry))
(monitor-x (nth 0 monitor-geometry))
(monitor-y (nth 1 monitor-geometry))
(selected-frame-position (frame-position))
(selected-frame-x (car selected-frame-position))
(selected-frame-y (cdr selected-frame-position))
(new-x (+ monitor-x selected-frame-x x))
(new-y (+ monitor-y selected-frame-y y)))
;; Call the original function with potentially adjusted coordinates
(funcall orig-fun frame new-x new-y width height buffer)))
;; Entferne zuerst alle vorhandenen Advices für diese Funktion
(advice-remove 'corfu--make-frame 'advise-corfu-make-frame-with-monitor-awareness)
;; Füge die neue Advice hinzu
(advice-add 'corfu--make-frame :around 'advise-corfu-make-frame-with-monitor-awareness)