- ;;; EXWM
- ;;; REVIEW: Athena+Xaw3d confuses xcape when binding Caps-lock to both L_Ctrl
- ;;; escape, in which case it will procude <C-escape> in Emacs. In practice, it
- ;;; means that `C-` keys will works but `<escape>` 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-<tab>") #'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-<return>") #'eshell-or-new-session)
- (exwm-input-set-key (kbd "s-<return>") #'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 "<print>") #'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-<kp-subtract>") #'exwm-start-volume-down)
- (exwm-input-set-key (kbd "s-<kp-add>") #'exwm-start-volume-up)
- (exwm-input-set-key (kbd "s-<kp-enter>") #'exwm-start-volume-toggle)
- (provide 'init-exwm)
- (exwm-enable)