about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--exwm-floating.el16
-rw-r--r--exwm-input.el95
-rw-r--r--exwm-manage.el11
-rw-r--r--exwm-workspace.el3
-rw-r--r--exwm.el18
5 files changed, 62 insertions, 81 deletions
diff --git a/exwm-floating.el b/exwm-floating.el
index 7888fd2d0b4f..e1d8738270d5 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 4acacdf5725c..454521f09483 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 fc61e5074478..d1736ff9a4cf 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 bcac91702317..09112d2d6556 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 7e909cdef681..989bf88156b5 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'."