diff --git a/exwm-floating.el b/exwm-floating.el index 7888fd2d0..e1d873827 100644 --- a/exwm-floating.el +++ b/exwm-floating.el @@ -179,12 +179,7 @@ exwm--floating-frame frame) (set-window-buffer window (current-buffer)) ;this changes current buffer (set-window-dedicated-p window t)) - (with-current-buffer (exwm--id->buffer id) - ;; 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))))) + (select-window window))) (defun exwm-floating--unset-floating (id) "Make window ID non-floating." @@ -212,11 +207,12 @@ (set-window-dedicated-p (frame-first-window exwm--floating-frame) nil) (delete-frame exwm--floating-frame))) ;remove the floating frame (with-current-buffer buffer - (setq exwm--floating-frame nil + (setq window-size-fixed nil + exwm--floating-frame nil exwm--frame exwm-workspace--current)) - (select-frame exwm-workspace--current t) - (set-window-buffer nil buffer) - (exwm-input--set-focus id))) + (let ((window (frame-selected-window exwm-workspace--current))) + (set-window-buffer window buffer) + (select-window window)))) (defun exwm-floating-toggle-floating () "Toggle the current window between floating and non-floating states." diff --git a/exwm-input.el b/exwm-input.el index 4acacdf57..454521f09 100644 --- a/exwm-input.el +++ b/exwm-input.el @@ -57,8 +57,6 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.") (defun exwm-input--set-focus (id) "Set input focus to window ID in a proper way." (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) (memq xcb:Atom:WM_TAKE_FOCUS exwm--protocols)) (progn @@ -79,45 +77,53 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.") :time xcb:Time:CurrentTime))) (xcb:flush exwm--connection))) -(defvar exwm-input--focus-id xcb:Window:None - "The window that is theoretically focused.") +(defvar exwm-input--focus-buffer nil "The buffer to be 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 () "Update input focus." - (when (and (frame-parameter nil 'exwm-window-id) ;e.g. emacsclient frame - (eq (current-buffer) (window-buffer))) ;e.g. `with-temp-buffer' - (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 - (exwm--log "Cancel input focus redirection on %s" - exwm--floating-frame) - (redirect-frame-focus exwm--floating-frame nil)) - ;; Focus the floating frame - (exwm--log "Focus on floating frame %s" - exwm--floating-frame) - (x-focus-frame exwm--floating-frame))) - ;; Finally focus the window - (when (exwm--id->buffer exwm-input--focus-id) - (exwm-input--set-focus exwm-input--focus-id))) - (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)))))))) + (when exwm-input--focus-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) + (progn + (when exwm--floating-frame + (redirect-frame-focus exwm--floating-frame nil) + (select-frame-set-input-focus exwm--floating-frame t)) + (exwm-input--set-focus exwm--id)) + (select-frame-set-input-focus exwm-workspace--current t) + (dolist (pair exwm--id-buffer-alist) + (with-current-buffer (cdr pair) + (when (and exwm--floating-frame + (eq exwm--frame exwm-workspace--current)) + (redirect-frame-focus exwm--floating-frame exwm--frame)))))))) (defun exwm-input--finish-key-sequence () "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 (exwm-floating--start-moveresize event)) (t - ;; Click to focus - (unless (and (boundp 'exwm--id) (= event exwm--id)) - (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)))) + (select-window (get-buffer-window (exwm--id->buffer event) + 'visible)) ;; The event should be replayed (setq mode xcb:Allow:ReplayPointer)))) (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 ;; (setq event (xcb:keysyms:keysym->event keysym state)) ;; (or exwm-input--during-key-sequence -;; (= exwm-input--focus-id xcb:Window:None) ;; (setq window (active-minibuffer-window)) ;; (eq event ?\C-c) ;mode-specific key ;; (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 (setq event (xcb:keysyms:keysym->event keysym state)) (or exwm-input--during-key-sequence - (= exwm-input--focus-id xcb:Window:None) (setq minibuffer-window (active-minibuffer-window)) (eq event ?\C-c) ;mode-specific key (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) (add-hook 'pre-command-hook 'exwm-input--finish-key-sequence) ;; 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 (exwm-input--update-global-prefix-keys)) diff --git a/exwm-manage.el b/exwm-manage.el index fc61e5074..d1736ff9a 100644 --- a/exwm-manage.el +++ b/exwm-manage.el @@ -183,15 +183,8 @@ corresponding buffer.") (let ((floating exwm--floating-frame)) (kill-buffer) (when floating - (if (eq 'exwm-mode - (with-current-buffer - (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)))))))) + (select-window + (frame-selected-window exwm-workspace--current)))))))) (defun exwm-manage--scan () "Search for existing windows and try to manage them." diff --git a/exwm-workspace.el b/exwm-workspace.el index bcac91702..09112d2d6 100644 --- a/exwm-workspace.el +++ b/exwm-workspace.el @@ -188,9 +188,6 @@ The optional FORCE option is for internal use only." ;; Move the window itself (bury-buffer) (exwm-layout--hide id) - ;; Force update input focus - (setq exwm-input--focus-id xcb:Window:None) - (exwm-input--update-focus) (xcb:+request exwm--connection (make-instance 'xcb:ReparentWindow :window id diff --git a/exwm.el b/exwm.el index 7e909cdef..989bf8815 100644 --- a/exwm.el +++ b/exwm.el @@ -195,15 +195,9 @@ (defun exwm-reset () "Reset window to standard state: non-fullscreen, line-mode." (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) (when (eq major-mode 'exwm-mode) (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 (exwm-layout--refresh) (exwm-input-grab-keyboard)))) @@ -709,12 +703,12 @@ (defun exwm--ido-buffer-window-other-frame (orig-fun buffer) "Wrapper for `ido-buffer-window-other-frame' to exclude invisible windows." - (let* ((window (funcall orig-fun buffer)) - (frame (window-frame window))) - ;; Exclude windows on other workspaces - (unless (and (memq frame exwm-workspace--list) - (not (eq frame exwm-workspace--current))) - window))) + (with-current-buffer buffer + (if (eq major-mode 'exwm-mode) + ;; `ido-mode' works well with `exwm-mode' buffers + (funcall orig-fun buffer) + ;; Other buffers should be selected within the same workspace + (get-buffer-window buffer exwm-workspace--current)))) (defun exwm--fix-ido-buffer-window-other-frame () "Fix `ido-buffer-window-other-frame'."