about summary refs log tree commit diff
path: root/exwm-input.el
diff options
context:
space:
mode:
authorChris Feng <chris.w.feng@gmail.com>2015-08-12T10·09+0800
committerChris Feng <chris.w.feng@gmail.com>2015-08-12T10·09+0800
commit04e426961736c67046fa3809fc14f1ac027dae77 (patch)
tree7a7515c778e25f741ad98ca5aec3c22c9b0e9cee /exwm-input.el
parent1ce18afd0559bacc3a7c43f5a73342814a5b176f (diff)
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.
Diffstat (limited to 'exwm-input.el')
-rw-r--r--exwm-input.el95
1 files changed, 48 insertions, 47 deletions
diff --git a/exwm-input.el b/exwm-input.el
index 4acacdf572..454521f094 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))