about summary refs log tree commit diff
diff options
context:
space:
mode:
authorChris Feng <chris.w.feng@gmail.com>2017-11-24T14·47+0800
committerChris Feng <chris.w.feng@gmail.com>2017-11-24T14·47+0800
commitdd6596b1f41a02021d5b60e823a3ae7e5664c92a (patch)
treea305ba8809974bcc8c8fb1c23835402c86651825
parent589b84040980504f0de7d80771b4ccfd63af4eef (diff)
Another fix for input focus issues
* exwm-core.el (exwm--defer):
* exwm-input.el (exwm-input--update-focus-defer): Avoid unnecessarily
long delay.

* exwm-input.el (exwm-input--on-FocusIn): Filter out FocusIn events
generated as a result of grab/ungrab or when the keyboard is grabbed.
-rw-r--r--exwm-core.el8
-rw-r--r--exwm-input.el29
2 files changed, 19 insertions, 18 deletions
diff --git a/exwm-core.el b/exwm-core.el
index 146594da0a16..2c810dfc647d 100644
--- a/exwm-core.el
+++ b/exwm-core.el
@@ -76,10 +76,12 @@
   (xcb:flush exwm--connection))
 
 (defmacro exwm--defer (secs function &rest args)
-  "Defer the action until SECS seconds later.
+  "Defer the execution of FUNCTION.
 
-The action is to call FUNCTION with arguments ARGS."
-  `(run-with-idle-timer (time-add (or (current-idle-time) 0) ,secs)
+The action is to call FUNCTION with arguments ARGS.  If Emacs is not idle,
+defer the action until Emacs is idle.  Otherwise, defer the action until at
+least SECS seconds later."
+  `(run-with-idle-timer (time-add (or (current-idle-time) (- ,secs)) ,secs)
                         nil
                         ,function
                         ,@args))
diff --git a/exwm-input.el b/exwm-input.el
index 6a60ac35d082..7bcbc9e4dcd2 100644
--- a/exwm-input.el
+++ b/exwm-input.el
@@ -116,18 +116,16 @@ ARGS are additional arguments to CALLBACK."
                (cdr exwm-input--timestamp-callback))
         (setq exwm-input--timestamp-callback nil)))))
 
-(defun exwm-input--on-FocusIn (&rest _args)
+(defun exwm-input--on-FocusIn (data _synthetic)
   "Handle FocusIn events."
-  ;; Not sure if this is the right thing to do but the point is the
-  ;; input focus should not stay at the root window or any container,
-  ;; or the result would be unpredictable.  `x-focus-frame' would
-  ;; first set the input focus to the (previously) selected frame, and
-  ;; then `select-window' would further update the input focus if the
-  ;; selected window is displaying an `exwm-mode' buffer.  Perhaps we
-  ;; should carefully filter out FocusIn events with certain 'detail'
-  ;; and 'mode' combinations, but this just works.
-  (x-focus-frame (selected-frame))
-  (select-window (selected-window)))
+  (let ((obj (make-instance 'xcb:FocusIn)))
+    (xcb:unmarshal obj data)
+    (with-slots (mode) obj
+      ;; Revert input focus back to Emacs frame / X window when it's set on
+      ;; the root window or some workspace container.
+      (when (eq mode xcb:NotifyMode:Normal)
+        (x-focus-frame (selected-frame))
+        (select-window (selected-window))))))
 
 (defun exwm-input--on-workspace-list-change ()
   "Run in `exwm-input--update-global-prefix-keys'."
@@ -139,7 +137,6 @@ ARGS are additional arguments to CALLBACK."
           (make-instance 'xcb:ChangeWindowAttributes
                          :window (frame-parameter f 'exwm-workspace)
                          :value-mask xcb:CW:EventMask
-                         ;; There should no other event selected there.
                          :event-mask xcb:EventMask:FocusChange))))
   (exwm-input--update-global-prefix-keys)
   (xcb:flush exwm--connection))
@@ -193,9 +190,11 @@ This value should always be overwritten.")
     (when exwm-input--update-focus-timer
       (cancel-timer exwm-input--update-focus-timer))
     (setq exwm-input--update-focus-timer
-          (exwm--defer exwm-input--update-focus-interval
-                       #'exwm-input--update-focus-commit
-                       exwm-input--update-focus-window))))
+          ;; Attempt to accumulate successive events close enough.
+          (run-with-timer exwm-input--update-focus-interval
+                          nil
+                          #'exwm-input--update-focus-commit
+                          exwm-input--update-focus-window))))
 
 (declare-function exwm-layout--iconic-state-p "exwm-layout.el" (&optional id))
 (declare-function exwm-layout--set-state "exwm-layout.el" (id state))