emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/exwm 76ced38 4/5: Fix input focus issues revealed by re


From: Chris Feng
Subject: [elpa] externals/exwm 76ced38 4/5: Fix input focus issues revealed by recent commits
Date: Thu, 21 Jul 2016 05:06:45 +0000 (UTC)

branch: externals/exwm
commit 76ced38ae43a9192ed97ca35dd1cc83c62b2a073
Author: Chris Feng <address@hidden>
Commit: Chris Feng <address@hidden>

    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.
---
 exwm-input.el     |   79 +++++++++++++++++++++++++++++++++++++----------------
 exwm-layout.el    |    4 +--
 exwm-workspace.el |    1 +
 3 files changed, 57 insertions(+), 27 deletions(-)

diff --git a/exwm-input.el b/exwm-input.el
index c1028ac..b79a551 100644
--- a/exwm-input.el
+++ b/exwm-input.el
@@ -79,21 +79,51 @@ It's updated in several occasions, and only used by 
`exwm-input--set-focus'.")
       (exwm-input--set-active-window id)
       (xcb:flush exwm--connection))))
 
-(defvar exwm-input--focus-window nil "The (Emacs) window to be focused.")
-(defvar exwm-input--timer nil "Currently running timer.")
+(defvar exwm-input--update-focus-window nil "The (Emacs) window to be focused.
+
+This value should always be overwritten.")
 
 (defun exwm-input--on-buffer-list-update ()
-  "Run in buffer-list-update-hook to track input focus."
-  (let ((frame (selected-frame))
-        (window (selected-window))
-        (buffer (current-buffer)))
-    (when (and (not (minibufferp buffer))
-               (frame-parameter frame 'exwm-outer-id) ;e.g. emacsclient frame
-               (eq buffer (window-buffer))) ;e.g. `with-temp-buffer'
-      (when exwm-input--timer (cancel-timer exwm-input--timer))
-      (setq exwm-input--focus-window window
-            exwm-input--timer
-            (run-with-idle-timer 0.01 nil #'exwm-input--update-focus)))))
+  "Run in `buffer-list-update-hook' to track input focus."
+  (when (and (not (minibufferp)) ;Do not set input focus on minibuffer window.
+             (eq (current-buffer) (window-buffer)) ;e.g. `with-temp-buffer'.
+             (frame-parameter nil 'exwm-outer-id)) ;e.g. emacsclient frame.
+    (setq exwm-input--update-focus-window (selected-window))
+    (exwm-input--update-focus-defer)))
+
+;; Input focus update requests should be accumulated for a short time
+;; interval so that only the last one need to be processed.  This not
+;; improves the overall performance, but avoids the problem of input
+;; 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--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"
                   (frame-or-index &optional force))
 
-(defun exwm-input--update-focus ()
+(defun exwm-input--update-focus (window)
   "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.
              (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 (not (eq exwm--frame exwm-workspace--current))
-              ;; Do not focus X windows on other workspace
+              ;; Do not focus X windows on other workspace.
               (progn
                 (set-frame-parameter exwm--frame 'exwm-urgency t)
                 (setq exwm-workspace--switch-history-outdated t)
                 (force-mode-line-update)
                 ;; 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-input--set-focus exwm--id)
             (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
                                         xcb:icccm:WM_STATE:NormalState))
               (xcb:flush exwm--connection)))
-        (when (eq (selected-window) exwm-input--focus-window)
-          (exwm--log "Focus on %s" exwm-input--focus-window)
-          (select-frame-set-input-focus (window-frame exwm-input--focus-window)
-                                        t)
+        (when (eq (selected-window) window)
+          (exwm--log "Focus on %s" window)
+          (select-frame-set-input-focus (window-frame window) t)
           (exwm-input--set-active-window)
-          (xcb:flush exwm--connection)))
-      (setq exwm-input--focus-window nil))))
+          (xcb:flush exwm--connection)))))
+  (setq exwm-input--update-focus-lock nil))
 
 (defun exwm-input--set-active-window (&optional id)
   "Set _NET_ACTIVE_WINDOW."
diff --git a/exwm-layout.el b/exwm-layout.el
index 667e2fa..905a1e3 100644
--- a/exwm-layout.el
+++ b/exwm-layout.el
@@ -381,9 +381,7 @@ selected by `other-buffer'."
     (run-with-idle-timer 0.01 nil         ;FIXME
                          (lambda ()
                            (when (< 1 (window-height (minibuffer-window)))
-                             (exwm-layout--refresh))))
-    ;; Set input focus on the Emacs frame
-    (x-focus-frame (window-frame (minibuffer-selected-window)))))
+                             (exwm-layout--refresh))))))
 
 (defun exwm-layout--on-echo-area-change (&optional dirty)
   "Run when message arrives or in `echo-area-clear-hook' to refresh layout."
diff --git a/exwm-workspace.el b/exwm-workspace.el
index 0d63639..2ff5e0c 100644
--- a/exwm-workspace.el
+++ b/exwm-workspace.el
@@ -460,6 +460,7 @@ The optional FORCE option is for internal use only."
         (set-frame-parameter (buffer-local-value 'exwm--frame (window-buffer))
                              'exwm-selected-window (selected-window)))
       (select-window window)
+      (x-focus-frame frame)    ;essential for transferring input focus
       (set-frame-parameter frame 'exwm-selected-window nil)
       ;; Close the (possible) active minibuffer
       (when (active-minibuffer-window)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]