Can exwm be made to allow multiple buffers to share an app?
Right now if I have a firefox window open on one window, anything that even just previews that "buffer" steals the buffer from the other window, leaving it in some other place.
This is close to an old 2018 issue, #295 , but I am not dealing with floating windows, and setting the _NET_WM_DESKTOP in my system (non-emacs) config seems to have had no effect. In the issue above it was mentioned that decoupling apps from workspaces might be a solution. In any case, how can I allow one window to look move to an app buffer without stealing it from another?
Right now if I have a firefox window open on one window, anything that even just previews that "buffer" steals the buffer from the other window, leaving it in some other place.
I think this is not possible, since X windows cannot be duplicated and displayed twice. I recommend to define an EXWM-specific buffer source for Consult without preview, see https://github.com/minad/consult/wiki#exwm-buffers.
With tab-bar-mode, multiple tabs can display the same EXWM buffer (but only on the same screen), because they're all in the same frame. It has the disadvantage that every redisplay obviously causes the window to be resized, but in practice I've found this to be quite OK.
@tazjin Yes, I use such a setup with tab-bar-mode and the tab bar as system status bar. You are right that an EXWM buffer can be present in multiple tabs. But the problem mentioned by @WorldsEndless goes further. It could be that you have an EXWM buffer in one window and Consult tries to preview the buffer in another window too, which is not possible.
Right, that Consult caused an issue. I indeed did what someone above mentioned: I turned off much of Consult preview. Here is my Consult customization to this end.
``` lisp
(consult-customize
consult-bookmark :preview-key nil
consult-buffer :preview-key (kbd "M-p"))
```
I have mostly learned to live with the fact that changing to an exwm buffer in one frame captures it away from other frames. Why do I use consult at all? Because I do like interactive line search, search results, and in-buffer things; just not many of the extra-buffer things.
@WorldsEndless for consult, I'd recommend:
(defun consult--buffer-filter-x (cand)
(when-let* ((buffer (get-buffer cand))
(mode (buffer-local-value 'major-mode buffer)))
(and (eq 'exwm-mode mode)
(get-buffer-window buffer 'visible))))
(defun consult--buffer-state-no-x ()
"Buffer state function that doesn't preview X buffers."
(let ((orig-state (consult--buffer-state)))
(lambda (action cand)
(unless (and cand (eq action 'preview) (consult--buffer-filter-x cand))
(funcall orig-state action cand)))))
(consult-customize
consult--source-buffer
:state #'consult--buffer-state-no-x)
This preserves previewing, but avoids previewing visible EXWM windows.
@Stebalien I think a separate Consult source is a cleaner alternative, as already mentioned in https://github.com/ch11ng/exwm/issues/812#issuecomment-1859254300, see https://github.com/minad/consult/wiki#exwm-buffers. This is what I use currently.
Yeah, that's significantly nicer but only works if you prefix exwm buffers with EXWM.
Yeah, that's significantly nicer but only works if you prefix exwm buffers with EXWM.
Indeed. Without the prefix one needs another hack to filter out the buffers by mode from the default buffer source, since consult-buffer-filter won't do it. Another alternative could be to prefix the buffers and only drop the prefix from the strings in the :items function of the EXWM-buffer source. But this may lead to confusion.
I wonder why you want to avoid a prefix. Such buffer prefixes are common in Emacs and don't hurt when filtering with Orderless. One could also use a short prefix like *X.
I prefix with the application class which is usually what I care about. I try to blur the line between "Emacs" and "X" buffers as much as possible. For example, I've configured (insert "foo") in an EXWM buffer to copy the text into the X window via fake input events allowing tools like consult-yank-from-kill-ring to work.
Another alternative could be to prefix the buffers and only drop the prefix from the strings in the :items function of the EXWM-buffer source. But this may lead to confusion.
That and I frequently use tools like ibuffer and would prefer consistent naming everywhere.
But, in general, I agree. Using a separate buffer source makes sense for most users.
Thanks.
I prefix with the application class which is usually what I care about. I try to blur the line between "Emacs" and "X" buffers as much as possible.
This sounds good. I will also give this a try. As I've just converted to EXWM recently, I didn't yet achieve the same blurring of the boundaries. ;) But EXWM is already a relief in many aspects over my simple i3 setup. I had expected much more rough edges. All in all, EXWM works astonishingly well.
For example, I've configured (insert "foo") in an EXWM buffer to copy the text into the X window via fake input events allowing tools like consult-yank-from-kill-ring to work.
I've also seen such tricks in the wiki but haven't gotten it to work yet.
In case anyone is interested, I modified the preview function to only preview when there isn't another EXWM window present in the current frame. This lets me keep preview EXWM buffers without messing up my layouts whenever it's already present during a buffer switch:
(defun my/get-all-window-buffers ()
"Get all buffers of all open windows."
(let ((buffers '()))
(walk-windows
(lambda (window)
(push (window-buffer window) buffers))
'no-mini)
buffers))
(with-eval-after-load 'consult
(defun consult--buffer-preview ()
"Buffer preview function."
(let ((orig-buf (current-buffer))
(orig-prev (copy-sequence (window-prev-buffers)))
(orig-next (copy-sequence (window-next-buffers)))
other-win)
(lambda (action cand)
(pcase action
('exit
(set-window-prev-buffers other-win orig-prev)
(set-window-next-buffers other-win orig-next))
('preview
(when (or
(not cand)
(not (eq (buffer-local-value 'major-mode (get-buffer cand)) 'exwm-mode))
(not (member (get-buffer cand) (my/get-all-window-buffers))))
(when (and (eq consult--buffer-display #'switch-to-buffer-other-window)
(not other-win))
(switch-to-buffer-other-window orig-buf)
(setq other-win (selected-window)))
(let ((win (or other-win (selected-window)))
(buf (or (and cand (get-buffer cand)) orig-buf)))
(when (and (window-live-p win) (buffer-live-p buf))
(with-selected-window win
(unless (or orig-prev orig-next)
(setq orig-prev (copy-sequence (window-prev-buffers))
orig-next (copy-sequence (window-next-buffers))))
(switch-to-buffer buf 'norecord)))))))))))
It works well, but its implementation is far from ideal.
I've also seen such tricks in the wiki but haven't gotten it to work yet.
I wrote this messy function to do this in case you are interested:
(defun my/exwm-insert (text)
(let ((orig-text (and kill-ring (car kill-ring))))
(kill-new text)
(exwm-input--fake-key ?\C-v)
(run-with-timer (* 0.1 2) nil `(lambda ()
(when ,orig-text
(kill-new ,orig-text))))))
I then wrote a custom kill-ring function that uses that function whenever EXWM mode is enabled.
I've configured (insert "foo") in an EXWM buffer to copy the text into the X window via fake input events allowing tools like consult-yank-from-kill-ring to work.
I wonder how you implemented that. By advicing insert?
@walseb
In case anyone is interested, I modified the preview function to only preview when there isn't another EXWM window present in the current frame. This lets me keep preview EXWM buffers without messing up my layouts whenever it's already present during a buffer switch:
Good idea, but a bit too complicated for my config. I try to keep the amount of hacks there low.
I wrote this messy function to do this in case you are interested: I then wrote a custom kill-ring function that uses that function whenever EXWM mode is enabled.
Thanks, will try this.
@Stebalien Regarding the EXWM naming - another simple idea would be to add EXWM as suffix instead. Then the buffer may blend in a little more, the suffix would get removed due to truncation in Ibuffer and also possibly in the special Consult source. The question is if having a separate source in the first place prevents the EXWM buffers from blending in sufficiently. ;)