init-exwm.el 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. ;;; EXWM
  2. ;;; When stating the client from .xinitrc, `save-buffer-kill-terminal' will
  3. ;;; force-kill Emacs before it can run through `kill-emacs-hook'.
  4. (global-set-key (kbd "C-x C-c") 'save-buffers-kill-emacs)
  5. ;;; REVIEW: Athena+Xaw3d confuses xcape when binding Caps-lock to both L_Ctrl
  6. ;;; escape, in which case it will procude <C-escape> in Emacs. In practice, it
  7. ;;; means that `C-` keys will works but `<escape>` will need a fast double tap
  8. ;;; on Caps Lock.
  9. ;;;
  10. ;;; See https://github.com/ch11ng/exwm/issues/285
  11. ;;; and https://gitlab.com/interception/linux/plugins/caps2esc/issues/2.
  12. ;;; REVIEW: Pressing "s-a" ('emms-smart-browse) loses the cursor.
  13. ;;; Sometimes waiting helps. Calling emms-smart-browse manually does not trigger the issue.
  14. ;;; https://github.com/ch11ng/exwm/issues/366
  15. ;;; REVIEW: helm-mini with follow-mode hangs when using EXWM.
  16. ;;; https://github.com/emacs-helm/helm/issues/1889
  17. ;;; Rename buffer to window title.
  18. (defun ambrevar/exwm-rename-buffer-to-title () (exwm-workspace-rename-buffer exwm-title))
  19. (add-hook 'exwm-update-title-hook 'ambrevar/exwm-rename-buffer-to-title)
  20. (add-hook 'exwm-floating-setup-hook 'exwm-layout-hide-mode-line)
  21. (add-hook 'exwm-floating-exit-hook 'exwm-layout-show-mode-line)
  22. ;;; Allow non-floating resizing with mouse.
  23. (setq window-divider-default-bottom-width 2
  24. window-divider-default-right-width 2)
  25. (window-divider-mode)
  26. ;;; System tray
  27. (require 'exwm-systemtray)
  28. (exwm-systemtray-enable)
  29. (setq exwm-systemtray-height 16)
  30. ;;; Those cannot be set globally: if Emacs would be run in another WM, the "s-"
  31. ;;; prefix will conflict with the WM bindings.
  32. (exwm-input-set-key (kbd "s-R") #'exwm-reset)
  33. (exwm-input-set-key (kbd "s-x") #'exwm-input-toggle-keyboard)
  34. (exwm-input-set-key (kbd "s-h") #'windmove-left)
  35. (exwm-input-set-key (kbd "s-j") #'windmove-down)
  36. (exwm-input-set-key (kbd "s-k") #'windmove-up)
  37. (exwm-input-set-key (kbd "s-l") #'windmove-right)
  38. (exwm-input-set-key (kbd "s-D") #'kill-this-buffer)
  39. (exwm-input-set-key (kbd "s-b") #'list-buffers)
  40. (exwm-input-set-key (kbd "s-f") #'find-file)
  41. (when (require 'functions)
  42. (exwm-input-set-key (kbd "s-\\") 'ambrevar/toggle-window-split)
  43. (exwm-input-set-key (kbd "s-H") 'ambrevar/swap-windows-left)
  44. (exwm-input-set-key (kbd "s-J") 'ambrevar/swap-windows-below)
  45. (exwm-input-set-key (kbd "s-K") 'ambrevar/swap-windows-above)
  46. (exwm-input-set-key (kbd "s-L") 'ambrevar/swap-windows-right))
  47. ;; The following can only apply to EXWM buffers, else it could have unexpected effects.
  48. (push ?\s- exwm-input-prefix-keys)
  49. (define-key exwm-mode-map (kbd "s-SPC") #'exwm-floating-toggle-floating)
  50. (exwm-input-set-key (kbd "s-i") #'follow-delete-other-windows-and-split)
  51. (exwm-input-set-key (kbd "s-o") #'ambrevar/toggle-single-window)
  52. (exwm-input-set-key (kbd "s-O") #'exwm-layout-toggle-fullscreen)
  53. (with-eval-after-load 'helm
  54. ;; Need `with-eval-after-load' here since 'helm-map is not defined in 'helm-config.
  55. (ambrevar/define-keys helm-map
  56. "s-\\" 'helm-toggle-resplit-and-swap-windows)
  57. (exwm-input-set-key (kbd "s-c") #'helm-resume)
  58. (exwm-input-set-key (kbd "s-b") #'helm-mini)
  59. (exwm-input-set-key (kbd "s-f") #'helm-find-files)
  60. (exwm-input-set-key (kbd "s-F") #'helm-locate)
  61. (when (fboundp 'ambrevar/helm-locate-meta)
  62. (exwm-input-set-key (kbd "s-F") #'ambrevar/helm-locate-meta))
  63. (exwm-input-set-key (kbd "s-g") 'ambrevar/helm-grep-git-or-ag)
  64. (exwm-input-set-key (kbd "s-G") 'ambrevar/helm-grep-git-all-or-ag))
  65. (require 'functions)
  66. (exwm-input-set-key (kbd "s-<tab>") #'ambrevar/switch-to-last-buffer)
  67. (when (require 'evil nil t)
  68. (exwm-input-set-key (kbd "s-<tab>") #'evil-switch-to-windows-last-buffer)
  69. (exwm-input-set-key (kbd "C-6") #'evil-switch-to-windows-last-buffer))
  70. ;;; Emacs mode shortcuts.
  71. (exwm-input-set-key (kbd "s-t") #'ambrevar/org-switch-agenda-file)
  72. (exwm-input-set-key (kbd "s-T") #'ambrevar/org-switch-agenda-file-other-window)
  73. (exwm-input-set-key (kbd "s-<return>") #'ambrevar/eshell-or-new-session)
  74. (when (fboundp 'magit-status)
  75. (exwm-input-set-key (kbd "s-v") #'magit-status))
  76. (when (fboundp 'emms-all)
  77. (exwm-input-set-key (kbd "s-a") #'emms-smart-browse)
  78. (exwm-input-set-key (kbd "S-s-<kp-enter>") #'emms-pause)
  79. (if (fboundp 'helm-emms)
  80. (exwm-input-set-key (kbd "s-A") #'helm-emms)
  81. (exwm-input-set-key (kbd "s-A") #'emms)))
  82. (when (or (fboundp 'mu4e)
  83. (delq nil (mapcar (lambda (path) (string-match "/mu4e/\\|/mu4e$" path)) load-path)))
  84. (exwm-input-set-key (kbd "s-m") #'ambrevar/mu4e-headers))
  85. (exwm-input-set-key (kbd "s-n") #'ambrevar/elfeed-switch-back) ; "n" for "news"
  86. (exwm-input-set-key (kbd "s-e") #'ambrevar/eww-switch-back)
  87. (exwm-input-set-key (kbd "s-E") #'eww)
  88. (when (fboundp 'helm-pass)
  89. (defun ambrevar/helm-pass-for-page ()
  90. "Default prompt to current exwm-title"
  91. (interactive)
  92. (require 'helm-pass)
  93. (helm :sources 'helm-pass-source-pass
  94. :input (cond
  95. ((derived-mode-p 'eww-mode)
  96. (let* ((url (replace-regexp-in-string ".*//\\([^/]*\\).*" "\\1" (eww-current-url)))
  97. (domain (split-string url "\\.")))
  98. (concat (nth (- (length domain) 2) domain) "." (nth (1- (length domain)) domain))))
  99. ((and (derived-mode-p 'exwm-mode) exwm-title)
  100. (let* ((url (car (last (split-string exwm-title " "))))
  101. (domain (split-string url "\\.")))
  102. (concat (nth (- (length domain) 2) domain) "." (nth (1- (length domain)) domain)))))
  103. :buffer "*helm-pass*"))
  104. (exwm-input-set-key (kbd "s-p") #'ambrevar/helm-pass-for-page))
  105. ;;; External application shortcuts.
  106. (defun ambrevar/exwm-start (command)
  107. (interactive (list (read-shell-command "$ ")))
  108. (start-process-shell-command command nil command))
  109. (exwm-input-set-key (kbd "s-&") #'ambrevar/exwm-start)
  110. (exwm-input-set-key (kbd "s-r") #'ambrevar/exwm-start)
  111. (when (require 'helm-exwm nil t)
  112. (add-to-list 'helm-source-names-using-follow "EXWM buffers")
  113. (setq helm-exwm-emacs-buffers-source (helm-exwm-build-emacs-buffers-source))
  114. (setq helm-exwm-source (helm-exwm-build-source))
  115. (setq helm-mini-default-sources `(helm-exwm-emacs-buffers-source
  116. helm-exwm-source
  117. helm-source-recentf
  118. ,(when (boundp 'helm-source-ls-git) 'helm-source-ls-git)
  119. helm-source-bookmarks
  120. helm-source-bookmark-set
  121. helm-source-buffer-not-found))
  122. (ambrevar/define-keys
  123. helm-exwm-map
  124. "M-d" 'helm-buffer-run-kill-persistent
  125. "S-<return>" 'helm-buffer-switch-other-window)
  126. ;; Launcher
  127. (exwm-input-set-key (kbd "s-r") 'helm-run-external-command)
  128. ;; Web browser
  129. (exwm-input-set-key (kbd "s-w") #'helm-exwm-switch-browser)
  130. (exwm-input-set-key (kbd "s-W") #'helm-exwm-switch-browser-other-window))
  131. ;;; Lock screen
  132. (defun ambrevar/exwm-start-lock () (interactive) (start-process "slock" nil "slock"))
  133. (exwm-input-set-key (kbd "s-z") #'ambrevar/exwm-start-lock)
  134. ;;; Screenshot
  135. (defun ambrevar/exwm-start-screenshot () (interactive) (start-process-shell-command "scrot" nil "scrot ~/temp/screen-%F-%T.png"))
  136. (exwm-input-set-key (kbd "<print>") #'ambrevar/exwm-start-screenshot)
  137. ;;; Volume control
  138. (when (require 'pulseaudio-control nil t)
  139. (exwm-input-set-key (kbd "s-<kp-subtract>") #'pulseaudio-control-decrease-volume)
  140. (exwm-input-set-key (kbd "s-<kp-add>") #'pulseaudio-control-increase-volume)
  141. (exwm-input-set-key (kbd "s-<kp-enter>") #'pulseaudio-control-toggle-current-sink-mute)
  142. (exwm-input-set-key (kbd "s--") #'pulseaudio-control-decrease-volume)
  143. (exwm-input-set-key (kbd "s-=") #'pulseaudio-control-increase-volume)
  144. (exwm-input-set-key (kbd "s-0") #'pulseaudio-control-toggle-current-sink-mute))
  145. ;;; Check for start-up errors. See ~/.profile.
  146. (let ((error-logs (directory-files "~" t "errors.*log$")))
  147. (when error-logs
  148. (warn "Error during system startup. See %s." (mapconcat 'identity error-logs ", "))
  149. (when (daemonp)
  150. ;; Non-daemon Emacs already brings up the *Warning* buffer.
  151. (setq initial-buffer-choice
  152. (lambda () (get-buffer "*Warnings*"))))))
  153. ;;; Some programs such as 'emacs' are better off being started in char-mode.
  154. (defun ambrevar/exwm-start-in-char-mode ()
  155. (when (string-prefix-p "emacs" exwm-instance-name)
  156. (exwm-input-release-keyboard (exwm--buffer->id (window-buffer)))))
  157. (add-hook 'exwm-manage-finish-hook 'ambrevar/exwm-start-in-char-mode)
  158. (provide 'init-exwm)