Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EXWM windows lose focus when switching persps with persp-mode #18

Open
LemonBreezes opened this issue Feb 18, 2024 · 6 comments
Open

EXWM windows lose focus when switching persps with persp-mode #18

LemonBreezes opened this issue Feb 18, 2024 · 6 comments

Comments

@LemonBreezes
Copy link

LemonBreezes commented Feb 18, 2024

I'm having a lot of difficulty getting persp-mode working together with EXWM. For some reason, if I switch to a Persp containing Discord, Discord does not gain focus unless I was previously in a persp containing an EXWM buffer. Firefox seems to behave though.

@minad
Copy link
Member

minad commented Feb 18, 2024

Do you have such focus issues only with persp-mode and only with Discord, or also other programs? I don't use Discord but with Chromium I also regularly observe focus issues, when switching buffers with switch-to-buffer, consult-buffer or switching between tabs. I use tab-bar-mode instead of perspectives. After switching buffers, Chromium will not gain focus. I don't observe such a behavior with other programs, e.g., a simple Xterm or Thunderbird.

@LemonBreezes
Copy link
Author

LemonBreezes commented Feb 18, 2024

Do you have such focus issues only with persp-mode and only with Discord, or also other programs? I don't use Discord but with Chromium I also regularly observe focus issues, when switching buffers with switch-to-buffer, consult-buffer or switching between tabs. I use tab-bar-mode instead of perspectives. After switching buffers, Chromium will not gain focus. I don't observe such a behavior with other programs, e.g., a simple Xterm or Thunderbird.

Yeah, I think this can happen when switching buffer, switching window, etc, according to an old workaround I wrote years ago (but have disabled). Lately I don't use many programs outside of Emacs but definitely it seems to happen in Discord and not in Firefox.

I wrote a workaround that doesn't work as well as I would like it to because it interrupts repeat mode and creates a race condition where if I switch workspaces and start typing before the timers finish it will be interrupted, but if the delays are too low, it will also not work:

(defvar +exwm-refocus-application--message "")
(defvar +exwm-refocus-application--delays '(0.015 0.03))
(defvar +exwm-refocus-application--timer nil)
(defvar +exwm-refocus-application--last-time 0)
(defvar +exwm-refocus-application--last-state nil)

;;;###autoload
(defun +exwm-refocus-application (&rest _)
  "Refocus input for the currently selected EXWM buffer, if any."
  (when (and (derived-mode-p 'exwm-mode)
             (not (memq +exwm-refocus-application--timer
                        timer-list))
             (> (float-time) (+ +exwm-refocus-application--last-time
                                0.01
                                (cl-reduce #'+ +exwm-refocus-application--delays))))
    (run-at-time (nth 0 +exwm-refocus-application--delays)
                 nil #'+exwm-refocus-application--timer)))

(defun +exwm-refocus-application--timer ()
  (when (derived-mode-p 'exwm-mode)
    (setq +exwm-refocus-application--message (current-message))
    (let ((+exwm-refocus-application--last-state (bound-and-true-p evil-state)))
      (minibuffer-with-setup-hook
          #'+exwm-refocus-application-minibuffer-quit-timer
        (read-string "")))))

(defun +exwm-refocus-application-minibuffer-quit-timer ()
  (setq +exwm-refocus-application--timer
        (run-at-time (nth 1 +exwm-refocus-application--delays) nil
                     (lambda ()
                       (run-at-time
                        0.0 nil
                        (lambda ()
                          (when +exwm-refocus-application--message
                            (minibuffer-message +exwm-refocus-application--message))
                          (pcase +exwm-refocus-application--last-state
                            ;; My `exwm-evil' package.
                            ('insert (exwm-evil-core-insert))
                            ('normal (exwm-evil-core-normal))
                            (_ nil))))
                       (when (minibufferp)
                         (setq +exwm-refocus-application--last-time (float-time))
                         (throw 'exit nil))))))

Then add +exwm-refocus-application to as many focus-changing hooks as possible. This is probably the most major EXWM issue I've noticed throughout the years.

@minad
Copy link
Member

minad commented Mar 15, 2024

I currently use the workaround from ch11ng/exwm#933 and ch11ng/exwm#759.

    (advice-add #'exwm-layout--hide
                :after (lambda (id)
                         (with-current-buffer (exwm--id->buffer id)
                           (setq exwm--ewmh-state
                                 (delq xcb:Atom:_NET_WM_STATE_HIDDEN exwm--ewmh-state))
                           (exwm-layout--set-ewmh-state id)
                           (xcb:flush exwm--connection))))

This workaround completely defeats the _NET_WM_STATE_HIDDEN wm hint, which may have unwanted power consumption consequences.

@LemonBreezes
Copy link
Author

LemonBreezes commented Mar 26, 2024

I currently use the workaround from ch11ng/exwm#933 and ch11ng/exwm#759.

    (advice-add #'exwm-layout--hide
                :after (lambda (id)
                         (with-current-buffer (exwm--id->buffer id)
                           (setq exwm--ewmh-state
                                 (delq xcb:Atom:_NET_WM_STATE_HIDDEN exwm--ewmh-state))
                           (exwm-layout--set-ewmh-state id)
                           (xcb:flush exwm--connection))))

This workaround completely defeats the _NET_WM_STATE_HIDDEN wm hint, which may have unwanted power consumption consequences.

Man. I've been using this for a few days and it's a game-changer. EXWM is not broken anymore. I think this fix alone will make a lot of people who try EXWM again stay in EXWM.

@Stebalien
Copy link
Contributor

Have you tried setting exwm-layout-auto-iconify to nil? That may help.

This might be a race between updating input focus (which we defer and serialize with a lock) and processing other X events (which we serialize with a per-connection lock). Unfortunately, we're using two different locks here.

This is a shot in the dark, but could you test this patch?

diff --git a/exwm-input.el b/exwm-input.el
index f1f035c..fd8ed51 100644
--- a/exwm-input.el
+++ b/exwm-input.el
@@ -324,7 +324,7 @@ defun exwm-input--update-focus-commit
   "Attempt to update the window focus.
 If we're currently updating the window focus, re-schedule a focus update
 attempt later."
-  (if exwm-input--update-focus-lock
+  (if (or exwm-input--update-focus-lock (< 0 (slot-value exwm--connection 'event-lock)))
       (exwm-input--update-focus-defer)
     (let ((exwm-input--update-focus-lock t))
       (exwm-input--update-focus exwm-input--update-focus-window))))

@LemonBreezes
Copy link
Author

LemonBreezes commented May 20, 2024

Have you tried setting exwm-layout-auto-iconify to nil? That may help.

This might be a race between updating input focus (which we defer and serialize with a lock) and processing other X events (which we serialize with a per-connection lock). Unfortunately, we're using two different locks here.

This is a shot in the dark, but could you test this patch?

diff --git a/exwm-input.el b/exwm-input.el
index f1f035c..fd8ed51 100644
--- a/exwm-input.el
+++ b/exwm-input.el
@@ -324,7 +324,7 @@ defun exwm-input--update-focus-commit
   "Attempt to update the window focus.
 If we're currently updating the window focus, re-schedule a focus update
 attempt later."
-  (if exwm-input--update-focus-lock
+  (if (or exwm-input--update-focus-lock (< 0 (slot-value exwm--connection 'event-lock)))
       (exwm-input--update-focus-defer)
     (let ((exwm-input--update-focus-lock t))
       (exwm-input--update-focus exwm-input--update-focus-window))))

Hi. I haven't tried your patch but I've been using the exwm-layout--hide advice and the issue has not reoccured since.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants