mirror of
https://github.com/emacs-exwm/exwm.git
synced 2024-11-27 14:57:59 +01:00
Fix input focus issues revealed by recent commits
* exwm-input.el (exwm-input--update-focus-window) (exwm-input--on-buffer-list-update, exwm-input--update-focus-interval) (exwm-input--update-focus-lock, exwm-input--update-focus-defer-timer) (exwm-input--update-focus-timer, exwm-input--update-focus-defer) (defun exwm-input--update-focus): Rework the input focus update mechanism, mainly to overcome the input focus update contention. * exwm-input.el (defun exwm-input--update-focus): Use `select-window' instead of `exwm-workspace-switch'; calling the latter is too expensive. * exwm-layout.el (exwm-layout--on-minibuffer-setup): Drop a unnecessary line. * exwm-workspace.el (exwm-workspace-switch): Set input focus to the new workspace frame.
This commit is contained in:
parent
0c114d97b7
commit
76ced38ae4
3 changed files with 57 additions and 27 deletions
|
@ -79,21 +79,51 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
|
||||||
(exwm-input--set-active-window id)
|
(exwm-input--set-active-window id)
|
||||||
(xcb:flush exwm--connection))))
|
(xcb:flush exwm--connection))))
|
||||||
|
|
||||||
(defvar exwm-input--focus-window nil "The (Emacs) window to be focused.")
|
(defvar exwm-input--update-focus-window nil "The (Emacs) window to be focused.
|
||||||
(defvar exwm-input--timer nil "Currently running timer.")
|
|
||||||
|
This value should always be overwritten.")
|
||||||
|
|
||||||
(defun exwm-input--on-buffer-list-update ()
|
(defun exwm-input--on-buffer-list-update ()
|
||||||
"Run in buffer-list-update-hook to track input focus."
|
"Run in `buffer-list-update-hook' to track input focus."
|
||||||
(let ((frame (selected-frame))
|
(when (and (not (minibufferp)) ;Do not set input focus on minibuffer window.
|
||||||
(window (selected-window))
|
(eq (current-buffer) (window-buffer)) ;e.g. `with-temp-buffer'.
|
||||||
(buffer (current-buffer)))
|
(frame-parameter nil 'exwm-outer-id)) ;e.g. emacsclient frame.
|
||||||
(when (and (not (minibufferp buffer))
|
(setq exwm-input--update-focus-window (selected-window))
|
||||||
(frame-parameter frame 'exwm-outer-id) ;e.g. emacsclient frame
|
(exwm-input--update-focus-defer)))
|
||||||
(eq buffer (window-buffer))) ;e.g. `with-temp-buffer'
|
|
||||||
(when exwm-input--timer (cancel-timer exwm-input--timer))
|
;; Input focus update requests should be accumulated for a short time
|
||||||
(setq exwm-input--focus-window window
|
;; interval so that only the last one need to be processed. This not
|
||||||
exwm-input--timer
|
;; improves the overall performance, but avoids the problem of input
|
||||||
(run-with-idle-timer 0.01 nil #'exwm-input--update-focus)))))
|
;; focus loop, which is a result of the interaction with Emacs frames.
|
||||||
|
;;
|
||||||
|
;; FIXME: The time interval is hard to decide and perhaps machine-dependent.
|
||||||
|
;; A value too small can cause redundant updates of input focus,
|
||||||
|
;; and even worse, dead loops. OTOH a large value would bring
|
||||||
|
;; laggy experience.
|
||||||
|
(defconst exwm-input--update-focus-interval 0.01
|
||||||
|
"Time interval (in seconds) for accumulating input focus update requests.")
|
||||||
|
|
||||||
|
(defvar exwm-input--update-focus-lock nil
|
||||||
|
"Lock for solving input focus update contention.")
|
||||||
|
(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.")
|
||||||
|
|
||||||
|
(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))
|
||||||
|
(if exwm-input--update-focus-lock
|
||||||
|
(setq exwm-input--update-focus-defer-timer
|
||||||
|
(run-with-idle-timer 0 nil
|
||||||
|
#'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
|
||||||
|
(run-with-idle-timer exwm-input--update-focus-interval nil
|
||||||
|
#'exwm-input--update-focus
|
||||||
|
exwm-input--update-focus-window))))
|
||||||
|
|
||||||
(defvar exwm-workspace--current)
|
(defvar exwm-workspace--current)
|
||||||
(defvar exwm-workspace--switch-history-outdated)
|
(defvar exwm-workspace--switch-history-outdated)
|
||||||
|
@ -106,21 +136,23 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
|
||||||
(declare-function exwm-workspace-switch "exwm-workspace.el"
|
(declare-function exwm-workspace-switch "exwm-workspace.el"
|
||||||
(frame-or-index &optional force))
|
(frame-or-index &optional force))
|
||||||
|
|
||||||
(defun exwm-input--update-focus ()
|
(defun exwm-input--update-focus (window)
|
||||||
"Update input focus."
|
"Update input focus."
|
||||||
(when (and (window-live-p exwm-input--focus-window)
|
(setq exwm-input--update-focus-lock t)
|
||||||
|
(when (and (window-live-p window)
|
||||||
;; Do not update input focus when there's an active minibuffer.
|
;; Do not update input focus when there's an active minibuffer.
|
||||||
(not (active-minibuffer-window)))
|
(not (active-minibuffer-window)))
|
||||||
(with-current-buffer (window-buffer exwm-input--focus-window)
|
(with-current-buffer (window-buffer window)
|
||||||
(if (eq major-mode 'exwm-mode)
|
(if (eq major-mode 'exwm-mode)
|
||||||
(if (not (eq exwm--frame exwm-workspace--current))
|
(if (not (eq exwm--frame exwm-workspace--current))
|
||||||
;; Do not focus X windows on other workspace
|
;; Do not focus X windows on other workspace.
|
||||||
(progn
|
(progn
|
||||||
(set-frame-parameter exwm--frame 'exwm-urgency t)
|
(set-frame-parameter exwm--frame 'exwm-urgency t)
|
||||||
(setq exwm-workspace--switch-history-outdated t)
|
(setq exwm-workspace--switch-history-outdated t)
|
||||||
(force-mode-line-update)
|
(force-mode-line-update)
|
||||||
;; The application may have changed its input focus
|
;; The application may have changed its input focus
|
||||||
(exwm-workspace-switch exwm-workspace--current t))
|
(select-window
|
||||||
|
(frame-selected-window exwm-workspace--current)))
|
||||||
(exwm--log "Set focus on #x%x" exwm--id)
|
(exwm--log "Set focus on #x%x" exwm--id)
|
||||||
(exwm-input--set-focus exwm--id)
|
(exwm-input--set-focus exwm--id)
|
||||||
(when exwm--floating-frame
|
(when exwm--floating-frame
|
||||||
|
@ -135,13 +167,12 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
|
||||||
(exwm-layout--set-state exwm--id
|
(exwm-layout--set-state exwm--id
|
||||||
xcb:icccm:WM_STATE:NormalState))
|
xcb:icccm:WM_STATE:NormalState))
|
||||||
(xcb:flush exwm--connection)))
|
(xcb:flush exwm--connection)))
|
||||||
(when (eq (selected-window) exwm-input--focus-window)
|
(when (eq (selected-window) window)
|
||||||
(exwm--log "Focus on %s" exwm-input--focus-window)
|
(exwm--log "Focus on %s" window)
|
||||||
(select-frame-set-input-focus (window-frame exwm-input--focus-window)
|
(select-frame-set-input-focus (window-frame window) t)
|
||||||
t)
|
|
||||||
(exwm-input--set-active-window)
|
(exwm-input--set-active-window)
|
||||||
(xcb:flush exwm--connection)))
|
(xcb:flush exwm--connection)))))
|
||||||
(setq exwm-input--focus-window nil))))
|
(setq exwm-input--update-focus-lock nil))
|
||||||
|
|
||||||
(defun exwm-input--set-active-window (&optional id)
|
(defun exwm-input--set-active-window (&optional id)
|
||||||
"Set _NET_ACTIVE_WINDOW."
|
"Set _NET_ACTIVE_WINDOW."
|
||||||
|
|
|
@ -381,9 +381,7 @@ selected by `other-buffer'."
|
||||||
(run-with-idle-timer 0.01 nil ;FIXME
|
(run-with-idle-timer 0.01 nil ;FIXME
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(when (< 1 (window-height (minibuffer-window)))
|
(when (< 1 (window-height (minibuffer-window)))
|
||||||
(exwm-layout--refresh))))
|
(exwm-layout--refresh))))))
|
||||||
;; Set input focus on the Emacs frame
|
|
||||||
(x-focus-frame (window-frame (minibuffer-selected-window)))))
|
|
||||||
|
|
||||||
(defun exwm-layout--on-echo-area-change (&optional dirty)
|
(defun exwm-layout--on-echo-area-change (&optional dirty)
|
||||||
"Run when message arrives or in `echo-area-clear-hook' to refresh layout."
|
"Run when message arrives or in `echo-area-clear-hook' to refresh layout."
|
||||||
|
|
|
@ -460,6 +460,7 @@ The optional FORCE option is for internal use only."
|
||||||
(set-frame-parameter (buffer-local-value 'exwm--frame (window-buffer))
|
(set-frame-parameter (buffer-local-value 'exwm--frame (window-buffer))
|
||||||
'exwm-selected-window (selected-window)))
|
'exwm-selected-window (selected-window)))
|
||||||
(select-window window)
|
(select-window window)
|
||||||
|
(x-focus-frame frame) ;essential for transferring input focus
|
||||||
(set-frame-parameter frame 'exwm-selected-window nil)
|
(set-frame-parameter frame 'exwm-selected-window nil)
|
||||||
;; Close the (possible) active minibuffer
|
;; Close the (possible) active minibuffer
|
||||||
(when (active-minibuffer-window)
|
(when (active-minibuffer-window)
|
||||||
|
|
Loading…
Reference in a new issue