about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSteven Allen <steven@stebalien.com>2024-02-05T15·32-0800
committerGitHub <noreply@github.com>2024-02-05T15·32-0800
commita6e66f5e339473105d83dd4e7e3f3db9b1aa9f0f (patch)
tree494a33e00b8870ca490ad83a377aeebfbb9e6dce
parent44e74bcc07f6ab2f985bcce12d68dccb943475cf (diff)
Simplify and improve focus handling (#10)
Combine both focus update timers into one and ignore windows in "no
focus" frames.

* exwm-input.el
  (exwm-input--on-buffer-list-update):
    Avoid focusing windows in frames with the `no-accept-focus` frame
    property.
  (exwm-input--update-focus-defer-timer):
    Remove the duplicate timer.
  (exwm-input--update-focus-defer):
    Use a single `exwm-input--update-focus-timer`.
  (exwm-input--update-focus-commit):
    Read `exwm-input--update-focus-window` instead of taking a window
    as a parameter (this is what lets us combine the timers).
  (exwm-input--update-focus-commit):
    Use a let-bind instead of unwind-protect.
  (exwm-input--exit):
    Remove references to `exwm-input--update-focus-defer-timer`.
-rw-r--r--exwm-input.el52
1 files changed, 23 insertions, 29 deletions
diff --git a/exwm-input.el b/exwm-input.el
index 835705ff9d69..f1f035c91ad9 100644
--- a/exwm-input.el
+++ b/exwm-input.el
@@ -135,14 +135,12 @@ defined in `exwm-mode-map' here."
 
 (defvar exwm-input--timestamp-window nil)
 
-(defvar exwm-input--update-focus-defer-timer nil "Timer for polling the lock.")
+(defvar exwm-input--update-focus-timer nil
+  "Timer for deferring the update of input focus.")
 
 (defvar exwm-input--update-focus-lock nil
   "Lock for solving input focus update contention.")
 
-(defvar exwm-input--update-focus-timer nil
-  "Timer for deferring the update of input focus.")
-
 (defvar exwm-input--update-focus-window nil "The (Emacs) window to be focused.
 This value should always be overwritten.")
 
@@ -302,7 +300,8 @@ ARGS are additional arguments to CALLBACK."
   "Run in `buffer-list-update-hook' to track input focus."
   (when (and          ; this hook is called incesantly; place cheap tests on top
          (not exwm-input--skip-buffer-list-update)
-         (exwm--terminal-p))      ; skip other terminals, e.g. TTY client frames
+         (exwm--terminal-p) ; skip other terminals, e.g. TTY client frames
+         (not (frame-parameter nil 'no-accept-focus)))
     (exwm--log "current-buffer=%S selected-window=%S"
                (current-buffer) (selected-window))
     (redirect-frame-focus (selected-frame) nil)
@@ -310,31 +309,28 @@ ARGS are additional arguments to CALLBACK."
     (exwm-input--update-focus-defer)))
 
 (defun exwm-input--update-focus-defer ()
-  "Defer updating input focus."
-  (when exwm-input--update-focus-defer-timer
-    (cancel-timer exwm-input--update-focus-defer-timer))
+  "Schedule a deferred update to input focus.
+Instead of immediately focusing the current window, it defers the focus change
+until the selected window stops changing (debouncing input focus updates)."
+  (when exwm-input--update-focus-timer
+    (cancel-timer exwm-input--update-focus-timer))
+  (setq exwm-input--update-focus-timer
+        ;; Attempt to accumulate successive events close enough.
+        (run-with-timer exwm-input--update-focus-interval
+                        nil
+                        #'exwm-input--update-focus-commit)))
+
+(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
-      (setq exwm-input--update-focus-defer-timer
-            (exwm--defer 0 #'exwm-input--update-focus-defer))
-    (setq exwm-input--update-focus-defer-timer nil)
-    (when exwm-input--update-focus-timer
-      (cancel-timer exwm-input--update-focus-timer))
-    (setq exwm-input--update-focus-timer
-          ;; Attempt to accumulate successive events close enough.
-          (run-with-timer exwm-input--update-focus-interval
-                          nil
-                          #'exwm-input--update-focus-commit
-                          exwm-input--update-focus-window))))
-
-(defun exwm-input--update-focus-commit (window)
-  "Commit updating input focus."
-  (setq exwm-input--update-focus-lock t)
-  (unwind-protect
-      (exwm-input--update-focus window)
-    (setq exwm-input--update-focus-lock nil)))
+      (exwm-input--update-focus-defer)
+    (let ((exwm-input--update-focus-lock t))
+      (exwm-input--update-focus exwm-input--update-focus-window))))
 
 (defun exwm-input--update-focus (window)
-  "Update input focus."
+  "Update input focus to WINDOW."
   (when (window-live-p window)
     (exwm--log "focus-window=%s focus-buffer=%s" window (window-buffer window))
     (with-current-buffer (window-buffer window)
@@ -1234,8 +1230,6 @@ One use is to access the keymap bound to KEYS (as prefix keys) in `char-mode'."
     (setq exwm-input--echo-area-timer nil))
   (remove-hook 'echo-area-clear-hook #'exwm-input--on-echo-area-clear)
   (remove-hook 'buffer-list-update-hook #'exwm-input--on-buffer-list-update)
-  (when exwm-input--update-focus-defer-timer
-    (cancel-timer exwm-input--update-focus-defer-timer))
   (when exwm-input--update-focus-timer
     (cancel-timer exwm-input--update-focus-timer))
   ;; Make input focus working even without a WM.