feat(exwm): some improvements

This commit is contained in:
Pavel Korytov 2021-11-18 07:05:30 +03:00
parent a8a2ea0b00
commit d3f9973d63
2 changed files with 125 additions and 40 deletions

View file

@ -92,34 +92,72 @@ _=_: Balance "
(defun my/cycle-persp-exwm-buffers (dir) (defun my/cycle-persp-exwm-buffers (dir)
(let* ((current (current-buffer)) (let* ((current (current-buffer))
(ignore-rx (persp--make-ignore-buffer-rx)) (ignore-rx (persp--make-ignore-buffer-rx))
(exwm-buffers (visible-buffers '())
(exwm-data
(cl-loop for buf in (persp-current-buffers) (cl-loop for buf in (persp-current-buffers)
for is-another = (and (get-buffer-window buf) (not (eq current buf)))
if (and (buffer-live-p buf) if (and (buffer-live-p buf)
(eq 'exwm-mode (buffer-local-value 'major-mode buf)) (eq 'exwm-mode (buffer-local-value 'major-mode buf))
(not (string-match-p ignore-rx (buffer-name buf)))) (not (string-match-p ignore-rx (buffer-name buf))))
collect buf)) collect buf into all-buffers
(current-pos (or (cl-position current exwm-buffers) -1))) and if (not is-another) collect buf into cycle-buffers
(if (seq-empty-p exwm-buffers) finally (return (list all-buffers cycle-buffers))))
(message "No EXWM buffers!") (all-buffers (nth 0 exwm-data))
(let* ((next-pos (% (+ current-pos (length exwm-buffers) (cycle-buffers (nth 1 exwm-data))
(current-pos (or (cl-position current cycle-buffers) -1)))
(if (seq-empty-p cycle-buffers)
(message "No EXWM buffers to cycle!")
(let* ((next-pos (% (+ current-pos (length cycle-buffers)
(if (eq dir 'forward) 1 -1)) (if (eq dir 'forward) 1 -1))
(length exwm-buffers))) (length cycle-buffers)))
(next-buffer (nth next-pos exwm-buffers))) (next-buffer (nth next-pos cycle-buffers)))
(switch-to-buffer next-buffer) (switch-to-buffer next-buffer)
(message (message
"%s" "%s"
(mapconcat (mapconcat
(lambda (buf) (lambda (buf)
(let ((name (string-replace "EXWM :: " "" (buffer-name buf)))) (let ((name (string-replace "EXWM :: " "" (buffer-name buf))))
(if (eq (current-buffer) buf) (cond
(concat ((eq (current-buffer) buf)
"[" (concat
(propertize name 'face `(foreground-color . ,(doom-color 'yellow))) "["
"]") (propertize name 'face `(foreground-color . ,(doom-color 'yellow)))
(format " %s " name)))) "]"))
exwm-buffers ((not (member buf cycle-buffers))
(concat
"["
(propertize name 'face `(foreground-color . ,(doom-color 'blue)))
"]"))
(t (format " %s " name)))))
all-buffers
" ")))))) " "))))))
(defun my/add-exwm-buffers-to-current-perspective ()
(interactive)
(let ((ignore-rx (persp--make-ignore-buffer-rx)))
(cl-loop for buf in (buffer-list)
if (and (buffer-live-p buf)
(eq 'exwm-mode (buffer-local-value 'major-mode buf))
(not (string-match-p ignore-rx (buffer-name buf))))
do (persp-add-buffer (buffer-name buf)))))
(defun my/exwm-revive-perspectives ()
"Make perspectives in the current frame not killed."
(interactive)
(let ((to-switch nil))
(maphash
(lambda (_ v)
(setf (persp-killed v) nil)
(unless to-switch
(setq to-switch v)))
(frame-parameter nil 'persp--hash))
(when to-switch
(persp-switch (persp-name to-switch)))))
(defun my/exwm-lock ()
(interactive)
(my/run-in-background "i3lock -f -i /home/pavel/Pictures/lock-wallpaper.png"))
(use-package pinentry (use-package pinentry
:straight t :straight t
:after (exwm) :after (exwm)

View file

@ -260,13 +260,10 @@ References:
- [[https://github.com/ch11ng/exwm/wiki][EXWM Wiki]] - [[https://github.com/ch11ng/exwm/wiki][EXWM Wiki]]
- [[https://github.com/daviwil/emacs-from-scratch/blob/master/Desktop.org][Emacs From Scratch config]] - [[https://github.com/daviwil/emacs-from-scratch/blob/master/Desktop.org][Emacs From Scratch config]]
TODO Look at:
- https://github.com/ch11ng/exwm/issues/202
** Xsession ** Xsession
First things first, Emacs has to be launched as a window wanager. On a more conventional system I'd create a .desktop file in some system folder that can be seen by a login manager, but in the case of Guix it's a bit more complicated, because all such folders are not meant to be changed manually. First things first, Emacs has to be launched as a window manager. On a more conventional system, I'd create a .desktop file in some system folder that can be seen by a login manager, but in the case of Guix, it's a bit more complicated, because all such folders are not meant to be changed manually.
However, GDM, the login manager that seems to be default on Guix, launches =~/.xsession= on the startup if it's present, which is just fine for my purposes. However, GDM, the login manager that seems to default on Guix, launches =~/.xsession= on the startup if it's present, which is just fine for my purposes.
#+begin_src sh :tangle ~/.xsession #+begin_src sh :tangle ~/.xsession
# Source .profile # Source .profile
@ -304,7 +301,7 @@ I want to launch some apps from EXWM instead of the Xsession file for two purpos
- the app may need to have the entire desktop environment set up - the app may need to have the entire desktop environment set up
- or it may need to be restarted if Emacs is killed. - or it may need to be restarted if Emacs is killed.
As of now, these are polybar, feh and shepherd: As of now, these are polybar, feh and, shepherd:
#+begin_src emacs-lisp #+begin_src emacs-lisp
(defun my/exwm-run-polybar () (defun my/exwm-run-polybar ()
(call-process "~/bin/polybar.sh")) (call-process "~/bin/polybar.sh"))
@ -331,7 +328,7 @@ A predicate which checks whether there is space in the given direction:
#+end_src #+end_src
And a function to move windows with the following behavior: And a function to move windows with the following behavior:
- if there is space in the required directon, move the Emacs window there; - if there is space in the required direction, move the Emacs window there;
- if there is no space in the required direction, but space in two orthogonal directions, move the Emacs window so that there is no more space in the orthogonal directions; - if there is no space in the required direction, but space in two orthogonal directions, move the Emacs window so that there is no more space in the orthogonal directions;
#+begin_src emacs-lisp #+begin_src emacs-lisp
(defun my/exwm-move-window (dir) (defun my/exwm-move-window (dir)
@ -451,41 +448,91 @@ Switch to the opposite monitor.
(exwm-workspace-switch other))) (exwm-workspace-switch other)))
#+end_src #+end_src
** Switching buffers ** Switching buffers
A single perspective usually has only a handful of EXWM buffers, so here are functions to cycle them A single perspective usually has only a handful of EXWM buffers, so here is a function to cycle them.
Those buffers that are visible in another window are highlighted blue and skipped. The current buffer is highlighted yellow.
#+begin_src emacs-lisp #+begin_src emacs-lisp
(defun my/cycle-persp-exwm-buffers (dir) (defun my/cycle-persp-exwm-buffers (dir)
(let* ((current (current-buffer)) (let* ((current (current-buffer))
(ignore-rx (persp--make-ignore-buffer-rx)) (ignore-rx (persp--make-ignore-buffer-rx))
(exwm-buffers (visible-buffers '())
(exwm-data
(cl-loop for buf in (persp-current-buffers) (cl-loop for buf in (persp-current-buffers)
for is-another = (and (get-buffer-window buf) (not (eq current buf)))
if (and (buffer-live-p buf) if (and (buffer-live-p buf)
(eq 'exwm-mode (buffer-local-value 'major-mode buf)) (eq 'exwm-mode (buffer-local-value 'major-mode buf))
(not (string-match-p ignore-rx (buffer-name buf)))) (not (string-match-p ignore-rx (buffer-name buf))))
collect buf)) collect buf into all-buffers
(current-pos (or (cl-position current exwm-buffers) -1))) and if (not is-another) collect buf into cycle-buffers
(if (seq-empty-p exwm-buffers) finally (return (list all-buffers cycle-buffers))))
(message "No EXWM buffers!") (all-buffers (nth 0 exwm-data))
(let* ((next-pos (% (+ current-pos (length exwm-buffers) (cycle-buffers (nth 1 exwm-data))
(current-pos (or (cl-position current cycle-buffers) -1)))
(if (seq-empty-p cycle-buffers)
(message "No EXWM buffers to cycle!")
(let* ((next-pos (% (+ current-pos (length cycle-buffers)
(if (eq dir 'forward) 1 -1)) (if (eq dir 'forward) 1 -1))
(length exwm-buffers))) (length cycle-buffers)))
(next-buffer (nth next-pos exwm-buffers))) (next-buffer (nth next-pos cycle-buffers)))
(switch-to-buffer next-buffer) (switch-to-buffer next-buffer)
(message (message
"%s" "%s"
(mapconcat (mapconcat
(lambda (buf) (lambda (buf)
(let ((name (string-replace "EXWM :: " "" (buffer-name buf)))) (let ((name (string-replace "EXWM :: " "" (buffer-name buf))))
(if (eq (current-buffer) buf) (cond
(concat ((eq (current-buffer) buf)
"[" (concat
(propertize name 'face `(foreground-color . ,(doom-color 'yellow))) "["
"]") (propertize name 'face `(foreground-color . ,(doom-color 'yellow)))
(format " %s " name)))) "]"))
exwm-buffers ((not (member buf cycle-buffers))
(concat
"["
(propertize name 'face `(foreground-color . ,(doom-color 'blue)))
"]"))
(t (format " %s " name)))))
all-buffers
" ")))))) " "))))))
#+end_src #+end_src
** Add all EXWM buffers to current perspective
#+begin_src emacs-lisp
(defun my/add-exwm-buffers-to-current-perspective ()
(interactive)
(let ((ignore-rx (persp--make-ignore-buffer-rx)))
(cl-loop for buf in (buffer-list)
if (and (buffer-live-p buf)
(eq 'exwm-mode (buffer-local-value 'major-mode buf))
(not (string-match-p ignore-rx (buffer-name buf))))
do (persp-add-buffer (buffer-name buf)))))
#+end_src
** Revive perspectives
Occasionally the current perspective gets screwed up after a popup. This function attempts to fix it.
#+begin_src emacs-lisp
(defun my/exwm-revive-perspectives ()
"Make perspectives in the current frame not killed."
(interactive)
(let ((to-switch nil))
(maphash
(lambda (_ v)
(setf (persp-killed v) nil)
(unless to-switch
(setq to-switch v)))
(frame-parameter nil 'persp--hash))
(when to-switch
(persp-switch (persp-name to-switch)))))
#+end_src
** Locking up
Run i3lock.
#+begin_src emacs-lisp
(defun my/exwm-lock ()
(interactive)
(my/run-in-background "i3lock -f -i /home/pavel/Pictures/lock-wallpaper.png"))
#+end_src
** Keybindings ** Keybindings
Setting keybindings for EXWM. This actually has to be in the =:config= block of the =use-package= form, that is it has to be run after EXWM is loaded, so I use noweb to put this block in a correct place. Setting keybindings for EXWM. This actually has to be in the =:config= block of the =use-package= form, that is it has to be run after EXWM is loaded, so I use noweb to put this block in the correct place.
First, some prefixes for keybindings that are always passed to EXWM instead of the X application in =line-mode=: First, some prefixes for keybindings that are always passed to EXWM instead of the X application in =line-mode=:
#+begin_src emacs-lisp :tangle no :noweb-ref exwm-keybindings #+begin_src emacs-lisp :tangle no :noweb-ref exwm-keybindings
@ -595,7 +642,7 @@ And keybindings that are available in both =char-mode= and =line-mode=:
#+end_src #+end_src
** Pinentry ** Pinentry
The GUI pinentry doesn't work too well with EXWM because of the popup windows, so we will the the built-in Emacs pinentry. The GUI pinentry doesn't work too well with EXWM because of issues with popup windows, so we will use the Emacs one.
#+begin_src emacs-lisp #+begin_src emacs-lisp
(use-package pinentry (use-package pinentry