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`.
This commit is contained in:
Steven Allen 2024-02-05 07:32:51 -08:00 committed by GitHub
parent 44e74bcc07
commit a6e66f5e33
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -135,14 +135,12 @@ defined in `exwm-mode-map' here."
(defvar exwm-input--timestamp-window nil) (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 (defvar exwm-input--update-focus-lock nil
"Lock for solving input focus update contention.") "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. (defvar exwm-input--update-focus-window nil "The (Emacs) window to be focused.
This value should always be overwritten.") 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." "Run in `buffer-list-update-hook' to track input focus."
(when (and ; this hook is called incesantly; place cheap tests on top (when (and ; this hook is called incesantly; place cheap tests on top
(not exwm-input--skip-buffer-list-update) (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" (exwm--log "current-buffer=%S selected-window=%S"
(current-buffer) (selected-window)) (current-buffer) (selected-window))
(redirect-frame-focus (selected-frame) nil) (redirect-frame-focus (selected-frame) nil)
@ -310,31 +309,28 @@ ARGS are additional arguments to CALLBACK."
(exwm-input--update-focus-defer))) (exwm-input--update-focus-defer)))
(defun exwm-input--update-focus-defer () (defun exwm-input--update-focus-defer ()
"Defer updating input focus." "Schedule a deferred update to input focus.
(when exwm-input--update-focus-defer-timer Instead of immediately focusing the current window, it defers the focus change
(cancel-timer exwm-input--update-focus-defer-timer)) until the selected window stops changing (debouncing input focus updates)."
(if exwm-input--update-focus-lock (when exwm-input--update-focus-timer
(setq exwm-input--update-focus-defer-timer (cancel-timer exwm-input--update-focus-timer))
(exwm--defer 0 #'exwm-input--update-focus-defer)) (setq exwm-input--update-focus-timer
(setq exwm-input--update-focus-defer-timer nil) ;; Attempt to accumulate successive events close enough.
(when exwm-input--update-focus-timer (run-with-timer exwm-input--update-focus-interval
(cancel-timer exwm-input--update-focus-timer)) nil
(setq exwm-input--update-focus-timer #'exwm-input--update-focus-commit)))
;; 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) (defun exwm-input--update-focus-commit ()
"Commit updating input focus." "Attempt to update the window focus.
(setq exwm-input--update-focus-lock t) If we're currently updating the window focus, re-schedule a focus update
(unwind-protect attempt later."
(exwm-input--update-focus window) (if exwm-input--update-focus-lock
(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) (defun exwm-input--update-focus (window)
"Update input focus." "Update input focus to WINDOW."
(when (window-live-p window) (when (window-live-p window)
(exwm--log "focus-window=%s focus-buffer=%s" window (window-buffer window)) (exwm--log "focus-window=%s focus-buffer=%s" window (window-buffer window))
(with-current-buffer (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)) (setq exwm-input--echo-area-timer nil))
(remove-hook 'echo-area-clear-hook #'exwm-input--on-echo-area-clear) (remove-hook 'echo-area-clear-hook #'exwm-input--on-echo-area-clear)
(remove-hook 'buffer-list-update-hook #'exwm-input--on-buffer-list-update) (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 (when exwm-input--update-focus-timer
(cancel-timer exwm-input--update-focus-timer)) (cancel-timer exwm-input--update-focus-timer))
;; Make input focus working even without a WM. ;; Make input focus working even without a WM.