diff --git a/exwm-input.el b/exwm-input.el index 9ba3502..f943267 100644 --- a/exwm-input.el +++ b/exwm-input.el @@ -117,9 +117,6 @@ defined in `exwm-mode-map' here." (defvar exwm-input--simulation-keys nil "Simulation keys in line-mode.") -(defvar exwm-input--skip-buffer-list-update nil - "Skip the upcoming 'buffer-list-update'.") - (defvar exwm-input--temp-line-mode nil "Non-nil indicates it's in temporary line-mode for char-mode.") @@ -140,6 +137,12 @@ defined in `exwm-mode-map' here." (defvar exwm-input--update-focus-window nil "The (Emacs) window to be focused. This value should always be overwritten.") +(defvar exwm-input--last-selected-window nil + "Last selected window. Help us discern cause of `buffer-list-update-hook'.") + +(defvar exwm-input--last-selected-buffer nil + "Last selected window. Help us discern cause of `buffer-list-update-hook'.") + (defvar exwm-input--echo-area-timer nil "Timer for detecting echo area dirty.") (defvar exwm-input--event-hook nil @@ -292,13 +295,25 @@ ARGS are additional arguments to CALLBACK." (defun exwm-input--on-buffer-list-update () "Run in `buffer-list-update-hook' to track input focus." - (when (and (not (exwm-workspace--client-p)) - (not exwm-input--skip-buffer-list-update)) - (exwm--log "current-buffer=%S selected-window=%S" - (current-buffer) (selected-window)) - (redirect-frame-focus (selected-frame) nil) - (setq exwm-input--update-focus-window (selected-window)) - (exwm-input--update-focus-defer))) + ;; `buffer-list-update-hook' is invoked by several functions + ;; (`get-buffer-create', `select-window', `with-temp-buffer', etc.), but we + ;; just want to notice when a different window has been selected, or when the + ;; selected window displays a different buffer, so that we can set the focus + ;; to the associated X window (in case of an `exwm-mode' buffer). In order to + ;; differentiate, we keep track of the last selected window and buffer in the + ;; `exwm-input--last-selected-window' and + ;; `exwm-input--last-selected-buffer' variables. + (let* ((win (selected-window)) + (buf (window-buffer win))) + (when (and (not (exwm-workspace--client-p)) + (not (and (eq exwm-input--last-selected-window win) + (eq exwm-input--last-selected-buffer buf)))) + (setq exwm-input--last-selected-window win) + (setq exwm-input--last-selected-buffer buf) + (exwm--log "selected-window=%S current-buffer=%S" win buf) + (redirect-frame-focus (selected-frame) nil) + (setq exwm-input--update-focus-window (selected-window)) + (exwm-input--update-focus-defer)))) (defun exwm-input--update-focus-defer () "Defer updating input focus." diff --git a/exwm-manage.el b/exwm-manage.el index a7866f1..0664c09 100644 --- a/exwm-manage.el +++ b/exwm-manage.el @@ -151,7 +151,6 @@ want to match against EXWM internal variables such as `exwm-title', (defvar exwm-manage--ping-lock nil "Non-nil indicates EXWM is pinging a window.") -(defvar exwm-input--skip-buffer-list-update) (defvar exwm-input-prefix-keys) (defvar exwm-workspace--current) (defvar exwm-workspace--id-struts-alist) @@ -263,8 +262,7 @@ want to match against EXWM internal variables such as `exwm-title', (make-instance 'xcb:ChangeSaveSet :mode xcb:SetMode:Insert :window id)) - (with-current-buffer (let ((exwm-input--skip-buffer-list-update t)) - (generate-new-buffer "*EXWM*")) + (with-current-buffer (generate-new-buffer "*EXWM*") ;; Keep the oldest X window first. (setq exwm--id-buffer-alist (nconc exwm--id-buffer-alist `((,id . ,(current-buffer))))) @@ -349,8 +347,7 @@ want to match against EXWM internal variables such as `exwm-title', :stack-mode xcb:StackMode:Below))) (xcb:flush exwm--connection) (setq exwm--id-buffer-alist (assq-delete-all id exwm--id-buffer-alist)) - (let ((kill-buffer-query-functions nil) - (exwm-input--skip-buffer-list-update t)) + (let ((kill-buffer-query-functions nil)) (kill-buffer (current-buffer))) (throw 'return 'ignored)) (let ((index (plist-get exwm--configurations 'workspace)))