;;; EXWM ;;; REVIEW: Athena+Xaw3d confuses xcape when binding Caps-lock to both L_Ctrl ;;; escape, in which case it will procude in Emacs. In practice, it ;;; means that `C-` keys will works but `` will need a fast double tap ;;; on Caps Lock. ;;; ;;; See https://github.com/ch11ng/exwm/issues/285 ;;; and https://gitlab.com/interception/linux/plugins/caps2esc/issues/2. ;;; Rename buffer to window title. (defun exwm-rename-buffer-to-title () (exwm-workspace-rename-buffer exwm-title)) (add-hook 'exwm-update-title-hook 'exwm-rename-buffer-to-title) (add-hook 'exwm-floating-setup-hook 'exwm-layout-hide-mode-line) (add-hook 'exwm-floating-exit-hook 'exwm-layout-show-mode-line) ;;; Allow non-floating resizing with mouse. (setq window-divider-default-bottom-width 2 window-divider-default-right-width 2) (window-divider-mode) ;;; send all keypresses to emacs in line mode (setq exwm-input-line-mode-passthrough t) ;;; make exwm windows default to char instead of line mode (add-hook 'exwm-manage-finish-hook (lambda () (call-interactively #'exwm-input-release-keyboard) (exwm-layout-hide-mode-line))) (defun exwm-input-line-mode () "Set exwm window to line-mode and show mode line" (call-interactively #'exwm-input-grab-keyboard) (exwm-layout-show-mode-line)) (defun exwm-input-char-mode () "Set exwm window to char-mode and hide mode line" (call-interactively #'exwm-input-release-keyboard) (exwm-layout-hide-mode-line)) (require 'cl) (defun exwm-input-toggle-mode () "Toggle between line- and char-mode" (with-current-buffer (window-buffer) (when (eq major-mode 'exwm-mode) (if (equal (second (second mode-line-process)) "line") (exwm-input-char-mode) (exwm-input-line-mode))))) (exwm-input-set-key (kbd "s-i") (lambda () (interactive) (exwm-input-toggle-mode))) ;;; System tray (require 'exwm-systemtray) (exwm-systemtray-enable) (setq exwm-systemtray-height 16) ;;; Those cannot be set globally: if Emacs would be run in another WM, the "s-" ;;; prefix will conflict with the WM bindings. (exwm-input-set-key (kbd "s-R") #'exwm-reset) (exwm-input-set-key (kbd "s-x") #'exwm-input-toggle-keyboard) (exwm-input-set-key (kbd "s-h") #'windmove-left) (exwm-input-set-key (kbd "s-j") #'windmove-down) (exwm-input-set-key (kbd "s-k") #'windmove-up) (exwm-input-set-key (kbd "s-l") #'windmove-right) (exwm-input-set-key (kbd "s-d") #'delete-window) (exwm-input-set-key (kbd "s-D") #'kill-this-buffer) (exwm-input-set-key (kbd "s-b") #'ivy-switch-buffer) (exwm-input-set-key (kbd "s-f") #'find-file) (exwm-input-set-key (kbd "s-M") #'exwm-floating-toggle-floating) (exwm-input-set-key (kbd "s-C") #'ivy-resume) (exwm-input-set-key (kbd "s-f") #'counsel-find-file) (exwm-input-set-key (kbd "s-g") #'counsel-ag) (exwm-input-set-key (kbd "s-c") #'counsel-grep-or-swiper) (defun exwm-layout-toggle-fullscreen-or-single-window () (interactive) (if (eq major-mode 'exwm-mode) (call-interactively 'exwm-layout-toggle-fullscreen) (require 'functions) (toggle-single-window))) (exwm-input-set-key (kbd "s-O") #'exwm-layout-toggle-fullscreen-or-single-window) (defvar single-window--last-configuration nil "Last window configuration before calling `delete-other-windows'.") (defun toggle-single-window () "Un-maximize current window. If multiple windows are active, save window configuration and delete other windows. If only one window is active and a window configuration was previously save, restore that configuration." (interactive) (if (= (count-windows) 1) (when single-window--last-configuration (set-window-configuration single-window--last-configuration)) (setq single-window--last-configuration (current-window-configuration)) (delete-other-windows))) ;; 's-SPC': Launch application (exwm-input-set-key (kbd "s-SPC") (lambda (command) (interactive (list (read-shell-command "$ "))) (start-process-shell-command command nil command))) ;; split windows (defun toggle-window-split () "Switch between vertical and horizontal split. It only works for frames with exactly two windows." (interactive) (if (= (count-windows) 2) (let* ((this-win-buffer (window-buffer)) (next-win-buffer (window-buffer (next-window))) (this-win-edges (window-edges (selected-window))) (next-win-edges (window-edges (next-window))) (this-win-2nd (not (and (<= (car this-win-edges) (car next-win-edges)) (<= (cadr this-win-edges) (cadr next-win-edges))))) (splitter (if (= (car this-win-edges) (car (window-edges (next-window)))) 'split-window-horizontally 'split-window-vertically))) (delete-other-windows) (let ((first-win (selected-window))) (funcall splitter) (if this-win-2nd (other-window 1)) (set-window-buffer (selected-window) this-win-buffer) (set-window-buffer (next-window) next-win-buffer) (select-window first-win) (if this-win-2nd (other-window 1)))))) (exwm-input-set-key (kbd "s-\\") #'toggle-window-split) (defun switch-to-last-buffer () "Switch to last open buffer in current window." (interactive) (switch-to-buffer (other-buffer (current-buffer) 1))) (exwm-input-set-key (kbd "s-") #'switch-to-last-buffer) ;;; Emacs mode shortcuts. (exwm-input-set-key (kbd "s-t") #'org-find-first-agenda) ;;; TODO: (exwm-input-set-key (kbd "s-") #'eshell-or-new-session) (exwm-input-set-key (kbd "s-") #'eshell) (when (fboundp 'magit-status) (exwm-input-set-key (kbd "s-v") #'magit-status)) (when (fboundp 'emms-all) (exwm-input-set-key (kbd "s-a") #'emms-smart-browse) (exwm-input-set-key (kbd "s-A") #'emms)) (when (delq nil (mapcar (lambda (path) (string-match "/mu4e/\\|/mu4e$" path)) load-path)) (exwm-input-set-key (kbd "s-m") #'mu4e-headers)) (defvar exwm-lock-program "slock" "Shell command used to lock the screen.") (defun exwm-start-lock () (interactive) (start-process-shell-command exwm-lock-program nil exwm-lock-program)) (exwm-input-set-key (kbd "s-z") #'exwm-start-lock) (defun exwm-start-screenshot () (interactive) (start-process-shell-command "scrot" nil "scrot ~/temp/screen-%F-%T.png")) (exwm-input-set-key (kbd "") #'exwm-start-screenshot) ;;; TODO: Check out the 'volume' package. (defun exwm-volume (&optional up-or-down) (let ((controllers '(("amixer" . ((control . "set Master") (down . "5%-") (up . "5%+") (toggle . "toggle"))) ("mixer" . ((control . "vol") (down . "-5") (up . "+5") (toggle . "^")))))) (while (not (executable-find (caar controllers))) (setq controllers (cdr controllers))) (when controllers (start-process-shell-command "volume control" nil (format "%s %s %s >/dev/null" (caar controllers) (alist-get 'control (cdar controllers)) (alist-get up-or-down (cdar controllers) (alist-get 'toggle (cdar controllers) ))))))) (defun exwm-start-volume-down () (interactive) (exwm-volume 'down)) (defun exwm-start-volume-up () (interactive) (exwm-volume 'up)) (defun exwm-start-volume-toggle () (interactive) (exwm-volume)) (exwm-input-set-key (kbd "s-") #'exwm-start-volume-down) (exwm-input-set-key (kbd "s-") #'exwm-start-volume-up) (exwm-input-set-key (kbd "s-") #'exwm-start-volume-toggle) (provide 'init-exwm) (exwm-enable)