Improve input focus switch mechanism
This commit should fix most input focus bugs (especially those related to floating windows). The actual settings of input focus are delayed to exclude redundant event. Dead code since this commit is removed. This commit also fixes a bug for non-floating windows converted form floating state. The workaround for `ido-mode` is also improved to properly handle `exwm-mode` buffers.
This commit is contained in:
parent
1ce18afd05
commit
04e4269617
5 changed files with 62 additions and 81 deletions
|
@ -179,12 +179,7 @@
|
||||||
exwm--floating-frame frame)
|
exwm--floating-frame frame)
|
||||||
(set-window-buffer window (current-buffer)) ;this changes current buffer
|
(set-window-buffer window (current-buffer)) ;this changes current buffer
|
||||||
(set-window-dedicated-p window t))
|
(set-window-dedicated-p window t))
|
||||||
(with-current-buffer (exwm--id->buffer id)
|
(select-window window)))
|
||||||
;; Some window should not get input focus on creation
|
|
||||||
;; FIXME: other conditions?
|
|
||||||
(unless (memq xcb:Atom:_NET_WM_WINDOW_TYPE_UTILITY exwm-window-type)
|
|
||||||
(x-focus-frame exwm--floating-frame)
|
|
||||||
(exwm-input--set-focus id)))))
|
|
||||||
|
|
||||||
(defun exwm-floating--unset-floating (id)
|
(defun exwm-floating--unset-floating (id)
|
||||||
"Make window ID non-floating."
|
"Make window ID non-floating."
|
||||||
|
@ -212,11 +207,12 @@
|
||||||
(set-window-dedicated-p (frame-first-window exwm--floating-frame) nil)
|
(set-window-dedicated-p (frame-first-window exwm--floating-frame) nil)
|
||||||
(delete-frame exwm--floating-frame))) ;remove the floating frame
|
(delete-frame exwm--floating-frame))) ;remove the floating frame
|
||||||
(with-current-buffer buffer
|
(with-current-buffer buffer
|
||||||
(setq exwm--floating-frame nil
|
(setq window-size-fixed nil
|
||||||
|
exwm--floating-frame nil
|
||||||
exwm--frame exwm-workspace--current))
|
exwm--frame exwm-workspace--current))
|
||||||
(select-frame exwm-workspace--current t)
|
(let ((window (frame-selected-window exwm-workspace--current)))
|
||||||
(set-window-buffer nil buffer)
|
(set-window-buffer window buffer)
|
||||||
(exwm-input--set-focus id)))
|
(select-window window))))
|
||||||
|
|
||||||
(defun exwm-floating-toggle-floating ()
|
(defun exwm-floating-toggle-floating ()
|
||||||
"Toggle the current window between floating and non-floating states."
|
"Toggle the current window between floating and non-floating states."
|
||||||
|
|
|
@ -57,8 +57,6 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
|
||||||
(defun exwm-input--set-focus (id)
|
(defun exwm-input--set-focus (id)
|
||||||
"Set input focus to window ID in a proper way."
|
"Set input focus to window ID in a proper way."
|
||||||
(with-current-buffer (exwm--id->buffer id)
|
(with-current-buffer (exwm--id->buffer id)
|
||||||
(exwm--log "Set focus ID to #x%x" id)
|
|
||||||
(setq exwm-input--focus-id id)
|
|
||||||
(if (and (not exwm--hints-input)
|
(if (and (not exwm--hints-input)
|
||||||
(memq xcb:Atom:WM_TAKE_FOCUS exwm--protocols))
|
(memq xcb:Atom:WM_TAKE_FOCUS exwm--protocols))
|
||||||
(progn
|
(progn
|
||||||
|
@ -79,45 +77,53 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
|
||||||
:time xcb:Time:CurrentTime)))
|
:time xcb:Time:CurrentTime)))
|
||||||
(xcb:flush exwm--connection)))
|
(xcb:flush exwm--connection)))
|
||||||
|
|
||||||
(defvar exwm-input--focus-id xcb:Window:None
|
(defvar exwm-input--focus-buffer nil "The buffer to be focused.")
|
||||||
"The window that is theoretically focused.")
|
(defvar exwm-input--redirected nil
|
||||||
|
"Indicate next update on buffer list is actually a result of redirection.")
|
||||||
|
(defvar exwm-input--timer nil "Currently running timer.")
|
||||||
|
|
||||||
|
(defun exwm-input--on-buffer-list-update ()
|
||||||
|
"Run in buffer-list-update-hook to track input focus."
|
||||||
|
(let ((frame (selected-frame))
|
||||||
|
(buffer (current-buffer)))
|
||||||
|
(when (and (not (minibufferp buffer))
|
||||||
|
(frame-parameter frame 'exwm-window-id) ;e.g. emacsclient frame
|
||||||
|
(eq buffer (window-buffer))) ;e.g. `with-temp-buffer'
|
||||||
|
(unless (and exwm-input--redirected
|
||||||
|
exwm-input--focus-buffer
|
||||||
|
(with-current-buffer exwm-input--focus-buffer
|
||||||
|
exwm--floating-frame))
|
||||||
|
(setq exwm-input--focus-buffer buffer)
|
||||||
|
(when exwm-input--timer (cancel-timer exwm-input--timer))
|
||||||
|
(setq exwm-input--timer
|
||||||
|
(run-with-timer 0.01 nil 'exwm-input--update-focus)))
|
||||||
|
(setq exwm-input--redirected nil))))
|
||||||
|
|
||||||
|
(defun exwm-input--on-focus-in ()
|
||||||
|
"Run in focus-in-hook to remove redirected focus on frame."
|
||||||
|
(let ((frame (selected-frame)))
|
||||||
|
(when (and (frame-parameter frame 'exwm-window-id)
|
||||||
|
(not (memq frame exwm-workspace--list)))
|
||||||
|
(setq exwm-input--redirected t))))
|
||||||
|
|
||||||
(defun exwm-input--update-focus ()
|
(defun exwm-input--update-focus ()
|
||||||
"Update input focus."
|
"Update input focus."
|
||||||
(when (and (frame-parameter nil 'exwm-window-id) ;e.g. emacsclient frame
|
(when exwm-input--focus-buffer
|
||||||
(eq (current-buffer) (window-buffer))) ;e.g. `with-temp-buffer'
|
(with-current-buffer exwm-input--focus-buffer
|
||||||
|
(exwm--log "Set focus on %s" exwm-input--focus-buffer)
|
||||||
|
(setq exwm-input--focus-buffer nil)
|
||||||
(if (eq major-mode 'exwm-mode)
|
(if (eq major-mode 'exwm-mode)
|
||||||
(progn (exwm--log "Set focus ID to #x%x" exwm--id)
|
|
||||||
(setq exwm-input--focus-id exwm--id)
|
|
||||||
(when exwm--floating-frame
|
|
||||||
(if (eq (selected-frame) exwm--floating-frame)
|
|
||||||
;; Cancel the possible input focus redirection
|
|
||||||
(progn
|
(progn
|
||||||
(exwm--log "Cancel input focus redirection on %s"
|
(when exwm--floating-frame
|
||||||
exwm--floating-frame)
|
(redirect-frame-focus exwm--floating-frame nil)
|
||||||
(redirect-frame-focus exwm--floating-frame nil))
|
(select-frame-set-input-focus exwm--floating-frame t))
|
||||||
;; Focus the floating frame
|
(exwm-input--set-focus exwm--id))
|
||||||
(exwm--log "Focus on floating frame %s"
|
(select-frame-set-input-focus exwm-workspace--current t)
|
||||||
exwm--floating-frame)
|
(dolist (pair exwm--id-buffer-alist)
|
||||||
(x-focus-frame exwm--floating-frame)))
|
(with-current-buffer (cdr pair)
|
||||||
;; Finally focus the window
|
(when (and exwm--floating-frame
|
||||||
(when (exwm--id->buffer exwm-input--focus-id)
|
(eq exwm--frame exwm-workspace--current))
|
||||||
(exwm-input--set-focus exwm-input--focus-id)))
|
(redirect-frame-focus exwm--floating-frame exwm--frame))))))))
|
||||||
(let ((buffer (exwm--id->buffer exwm-input--focus-id)))
|
|
||||||
(when (and buffer (eq (selected-frame) exwm-workspace--current))
|
|
||||||
(with-current-buffer buffer
|
|
||||||
(exwm--log "Set focus ID to #x%x" xcb:Window:None)
|
|
||||||
(setq exwm-input--focus-id xcb:Window:None)
|
|
||||||
(if exwm--floating-frame
|
|
||||||
(unless (active-minibuffer-window)
|
|
||||||
;; Redirect input focus to the workspace frame
|
|
||||||
(exwm--log "Redirect input focus (%s => %s)"
|
|
||||||
exwm--floating-frame exwm-workspace--current)
|
|
||||||
(redirect-frame-focus exwm--floating-frame
|
|
||||||
exwm-workspace--current))
|
|
||||||
;; Focus the workspace frame
|
|
||||||
(exwm--log "Focus on workspace %s" exwm-workspace--current)
|
|
||||||
(x-focus-frame exwm-workspace--current))))))))
|
|
||||||
|
|
||||||
(defun exwm-input--finish-key-sequence ()
|
(defun exwm-input--finish-key-sequence ()
|
||||||
"Mark the end of a key sequence (with the aid of `pre-command-hook')."
|
"Mark the end of a key sequence (with the aid of `pre-command-hook')."
|
||||||
|
@ -169,12 +175,8 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
|
||||||
;; Resize
|
;; Resize
|
||||||
(exwm-floating--start-moveresize event))
|
(exwm-floating--start-moveresize event))
|
||||||
(t
|
(t
|
||||||
;; Click to focus
|
(select-window (get-buffer-window (exwm--id->buffer event)
|
||||||
(unless (and (boundp 'exwm--id) (= event exwm--id))
|
'visible))
|
||||||
(with-current-buffer (exwm--id->buffer event)
|
|
||||||
(select-frame-set-input-focus (or exwm--floating-frame
|
|
||||||
exwm--frame))
|
|
||||||
(select-window (get-buffer-window nil 'visible))))
|
|
||||||
;; The event should be replayed
|
;; The event should be replayed
|
||||||
(setq mode xcb:Allow:ReplayPointer))))
|
(setq mode xcb:Allow:ReplayPointer))))
|
||||||
(xcb:+request exwm--connection
|
(xcb:+request exwm--connection
|
||||||
|
@ -246,7 +248,6 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
|
||||||
;; (when (and keysym
|
;; (when (and keysym
|
||||||
;; (setq event (xcb:keysyms:keysym->event keysym state))
|
;; (setq event (xcb:keysyms:keysym->event keysym state))
|
||||||
;; (or exwm-input--during-key-sequence
|
;; (or exwm-input--during-key-sequence
|
||||||
;; (= exwm-input--focus-id xcb:Window:None)
|
|
||||||
;; (setq window (active-minibuffer-window))
|
;; (setq window (active-minibuffer-window))
|
||||||
;; (eq event ?\C-c) ;mode-specific key
|
;; (eq event ?\C-c) ;mode-specific key
|
||||||
;; (memq event exwm-input--global-prefix-keys)
|
;; (memq event exwm-input--global-prefix-keys)
|
||||||
|
@ -273,7 +274,6 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
|
||||||
(if (and keysym
|
(if (and keysym
|
||||||
(setq event (xcb:keysyms:keysym->event keysym state))
|
(setq event (xcb:keysyms:keysym->event keysym state))
|
||||||
(or exwm-input--during-key-sequence
|
(or exwm-input--during-key-sequence
|
||||||
(= exwm-input--focus-id xcb:Window:None)
|
|
||||||
(setq minibuffer-window (active-minibuffer-window))
|
(setq minibuffer-window (active-minibuffer-window))
|
||||||
(eq event ?\C-c) ;mode-specific key
|
(eq event ?\C-c) ;mode-specific key
|
||||||
(memq event exwm-input--global-prefix-keys)
|
(memq event exwm-input--global-prefix-keys)
|
||||||
|
@ -466,7 +466,8 @@ SIMULATION-KEYS is a list of alist (key-sequence1 . key-sequence2)."
|
||||||
;; `pre-command-hook' marks the end of a key sequence (existing or not)
|
;; `pre-command-hook' marks the end of a key sequence (existing or not)
|
||||||
(add-hook 'pre-command-hook 'exwm-input--finish-key-sequence)
|
(add-hook 'pre-command-hook 'exwm-input--finish-key-sequence)
|
||||||
;; Update focus when buffer list updates
|
;; Update focus when buffer list updates
|
||||||
(add-hook 'buffer-list-update-hook 'exwm-input--update-focus)
|
(add-hook 'buffer-list-update-hook 'exwm-input--on-buffer-list-update)
|
||||||
|
(add-hook 'focus-in-hook 'exwm-input--on-focus-in)
|
||||||
;; Update prefix keys for global keys
|
;; Update prefix keys for global keys
|
||||||
(exwm-input--update-global-prefix-keys))
|
(exwm-input--update-global-prefix-keys))
|
||||||
|
|
||||||
|
|
|
@ -183,15 +183,8 @@ corresponding buffer.")
|
||||||
(let ((floating exwm--floating-frame))
|
(let ((floating exwm--floating-frame))
|
||||||
(kill-buffer)
|
(kill-buffer)
|
||||||
(when floating
|
(when floating
|
||||||
(if (eq 'exwm-mode
|
(select-window
|
||||||
(with-current-buffer
|
(frame-selected-window exwm-workspace--current))))))))
|
||||||
(window-buffer
|
|
||||||
(frame-first-window exwm-workspace--current))
|
|
||||||
major-mode))
|
|
||||||
;; Input focus is to be set on a window
|
|
||||||
(x-focus-frame exwm-workspace--current)
|
|
||||||
;; Set input focus on a frame
|
|
||||||
(select-frame-set-input-focus exwm-workspace--current))))))))
|
|
||||||
|
|
||||||
(defun exwm-manage--scan ()
|
(defun exwm-manage--scan ()
|
||||||
"Search for existing windows and try to manage them."
|
"Search for existing windows and try to manage them."
|
||||||
|
|
|
@ -188,9 +188,6 @@ The optional FORCE option is for internal use only."
|
||||||
;; Move the window itself
|
;; Move the window itself
|
||||||
(bury-buffer)
|
(bury-buffer)
|
||||||
(exwm-layout--hide id)
|
(exwm-layout--hide id)
|
||||||
;; Force update input focus
|
|
||||||
(setq exwm-input--focus-id xcb:Window:None)
|
|
||||||
(exwm-input--update-focus)
|
|
||||||
(xcb:+request exwm--connection
|
(xcb:+request exwm--connection
|
||||||
(make-instance 'xcb:ReparentWindow
|
(make-instance 'xcb:ReparentWindow
|
||||||
:window id
|
:window id
|
||||||
|
|
18
exwm.el
18
exwm.el
|
@ -195,15 +195,9 @@
|
||||||
(defun exwm-reset ()
|
(defun exwm-reset ()
|
||||||
"Reset window to standard state: non-fullscreen, line-mode."
|
"Reset window to standard state: non-fullscreen, line-mode."
|
||||||
(interactive)
|
(interactive)
|
||||||
(unless (frame-parameter nil 'exwm-window-id)
|
|
||||||
;; Move focus away form a non-EXWM frame
|
|
||||||
(x-focus-frame exwm-workspace--current))
|
|
||||||
(with-current-buffer (window-buffer)
|
(with-current-buffer (window-buffer)
|
||||||
(when (eq major-mode 'exwm-mode)
|
(when (eq major-mode 'exwm-mode)
|
||||||
(when exwm--fullscreen (exwm-layout-unset-fullscreen))
|
(when exwm--fullscreen (exwm-layout-unset-fullscreen))
|
||||||
;; Force update input focus
|
|
||||||
(setq exwm-input--focus-id xcb:Window:None)
|
|
||||||
(exwm-input--update-focus)
|
|
||||||
;; Force refresh
|
;; Force refresh
|
||||||
(exwm-layout--refresh)
|
(exwm-layout--refresh)
|
||||||
(exwm-input-grab-keyboard))))
|
(exwm-input-grab-keyboard))))
|
||||||
|
@ -709,12 +703,12 @@
|
||||||
|
|
||||||
(defun exwm--ido-buffer-window-other-frame (orig-fun buffer)
|
(defun exwm--ido-buffer-window-other-frame (orig-fun buffer)
|
||||||
"Wrapper for `ido-buffer-window-other-frame' to exclude invisible windows."
|
"Wrapper for `ido-buffer-window-other-frame' to exclude invisible windows."
|
||||||
(let* ((window (funcall orig-fun buffer))
|
(with-current-buffer buffer
|
||||||
(frame (window-frame window)))
|
(if (eq major-mode 'exwm-mode)
|
||||||
;; Exclude windows on other workspaces
|
;; `ido-mode' works well with `exwm-mode' buffers
|
||||||
(unless (and (memq frame exwm-workspace--list)
|
(funcall orig-fun buffer)
|
||||||
(not (eq frame exwm-workspace--current)))
|
;; Other buffers should be selected within the same workspace
|
||||||
window)))
|
(get-buffer-window buffer exwm-workspace--current))))
|
||||||
|
|
||||||
(defun exwm--fix-ido-buffer-window-other-frame ()
|
(defun exwm--fix-ido-buffer-window-other-frame ()
|
||||||
"Fix `ido-buffer-window-other-frame'."
|
"Fix `ido-buffer-window-other-frame'."
|
||||||
|
|
Loading…
Reference in a new issue