about summary refs log tree commit diff
path: root/exwm-input.el
diff options
context:
space:
mode:
Diffstat (limited to 'exwm-input.el')
-rw-r--r--exwm-input.el154
1 files changed, 85 insertions, 69 deletions
diff --git a/exwm-input.el b/exwm-input.el
index d399fbbd8f5a..a5899d5c4eda 100644
--- a/exwm-input.el
+++ b/exwm-input.el
@@ -79,8 +79,6 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
       (xcb:flush exwm--connection))))
 
 (defvar exwm-input--focus-window nil "The (Emacs) window 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 ()
@@ -89,25 +87,12 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
         (window (selected-window))
         (buffer (current-buffer)))
     (when (and (not (minibufferp buffer))
-               (frame-parameter frame 'exwm-window-id) ;e.g. emacsclient frame
+               (frame-parameter frame 'exwm-outer-id) ;e.g. emacsclient frame
                (eq buffer (window-buffer))) ;e.g. `with-temp-buffer'
-      (unless (and exwm-input--redirected
-                   exwm-input--focus-window
-                   (with-current-buffer (window-buffer
-                                         exwm-input--focus-window)
-                     exwm--floating-frame))
-        (setq exwm-input--focus-window window)
-        (when exwm-input--timer (cancel-timer exwm-input--timer))
-        (setq exwm-input--timer
-              (run-with-idle-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))))
+      (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)))))
 
 (defun exwm-input--update-focus ()
   "Update input focus."
@@ -122,22 +107,56 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
                 (force-mode-line-update)
                 ;; The application may have changed its input focus
                 (exwm-workspace-switch exwm-workspace-current-index t))
-            (when exwm--floating-frame
-              (redirect-frame-focus exwm--floating-frame nil)
-              (select-frame-set-input-focus exwm--floating-frame t))
             (exwm--log "Set focus on #x%x" exwm--id)
-            (exwm-input--set-focus exwm--id))
+            (exwm-input--set-focus exwm--id)
+            ;; Adjust stacking orders
+            (if exwm--floating-frame
+                ;; Put this floating X window at top.
+                (xcb:+request exwm--connection
+                    (make-instance 'xcb:ConfigureWindow
+                                   :window exwm--container
+                                   :value-mask xcb:ConfigWindow:StackMode
+                                   :stack-mode xcb:StackMode:TopIf))
+              ;; This should be the last X window but one in the siblings.
+              (with-slots (children)
+                  (xcb:+request-unchecked+reply exwm--connection
+                      (make-instance 'xcb:QueryTree
+                                     :window
+                                     (frame-parameter exwm--frame
+                                                      'exwm-workspace)))
+                (unless (eq (cadr children) exwm--container)
+                  (xcb:+request exwm--connection
+                      (make-instance 'xcb:ConfigureWindow
+                                     :window exwm--container
+                                     :value-mask xcb:ConfigWindow:StackMode
+                                     :stack-mode xcb:StackMode:Below)))))
+            ;; Make sure Emacs frames are at bottom.
+            (xcb:+request exwm--connection
+                (make-instance 'xcb:ConfigureWindow
+                               :window (frame-parameter
+                                        (or exwm--floating-frame exwm--frame)
+                                        'exwm-outer-id)
+                               :value-mask xcb:ConfigWindow:StackMode
+                               :stack-mode xcb:StackMode:BottomIf))
+            (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)
-          (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))))))
+          (xcb:+request exwm--connection
+              (make-instance 'xcb:ConfigureWindow
+                             :window (frame-parameter
+                                      (window-frame exwm-input--focus-window)
+                                      'exwm-outer-id)
+                             :value-mask xcb:ConfigWindow:StackMode
+                             :stack-mode xcb:StackMode:Below))
+          (xcb:flush exwm--connection)))
       (setq exwm-input--focus-window nil))))
 
+(defun exwm-input--on-minibuffer-setup ()
+  "Run in minibuffer-setup-hook to set input focus to the frame."
+  (x-focus-frame (selected-frame)))
+
 (defvar exwm-input--during-key-sequence nil
   "Non-nil indicates Emacs is waiting for more keys to form a key sequence.")
 (defvar exwm-input--temp-line-mode nil
@@ -221,32 +240,38 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
   "Update `exwm-input--global-prefix-keys'."
   (when exwm--connection
     (let ((original exwm-input--global-prefix-keys)
-          keysym keycode)
+          keysym keycode ungrab-key grab-key workspace)
       (setq exwm-input--global-prefix-keys nil)
       (dolist (i exwm-input--global-keys)
         (cl-pushnew (elt i 0) exwm-input--global-prefix-keys))
       (unless (equal original exwm-input--global-prefix-keys)
-        ;; Grab global keys on root window
-        (if (xcb:+request-checked+request-check exwm--connection
-                (make-instance 'xcb:UngrabKey
-                               :key xcb:Grab:Any :grab-window exwm--root
-                               :modifiers xcb:ModMask:Any))
-            (exwm--log "Failed to ungrab keys")
-          (dolist (i exwm-input--global-prefix-keys)
-            (setq keysym (xcb:keysyms:event->keysym exwm--connection i))
-            (when (or (not keysym)
-                      (not (setq keycode (xcb:keysyms:keysym->keycode
-                                          exwm--connection (car keysym))))
-                      (xcb:+request-checked+request-check exwm--connection
-                          (make-instance 'xcb:GrabKey
-                                         :owner-events 0
-                                         :grab-window exwm--root
-                                         :modifiers (cadr keysym)
-                                         :key keycode
-                                         :pointer-mode xcb:GrabMode:Async
-                                         :keyboard-mode xcb:GrabMode:Async)))
-              (user-error "[EXWM] Failed to grab key: %s"
-                          (single-key-description i)))))))))
+        (setq ungrab-key (make-instance 'xcb:UngrabKey
+                                        :key xcb:Grab:Any :grab-window nil
+                                        :modifiers xcb:ModMask:Any)
+              grab-key (make-instance 'xcb:GrabKey
+                                      :owner-events 0
+                                      :grab-window nil
+                                      :modifiers nil
+                                      :key nil
+                                      :pointer-mode xcb:GrabMode:Async
+                                      :keyboard-mode xcb:GrabMode:Async))
+        (dolist (w exwm-workspace--list)
+          (setq workspace (frame-parameter w 'exwm-workspace))
+          (setf (slot-value ungrab-key 'grab-window) workspace)
+          (if (xcb:+request-checked+request-check exwm--connection ungrab-key)
+              (exwm--log "Failed to ungrab keys")
+            (dolist (k exwm-input--global-prefix-keys)
+              (setq keysym (xcb:keysyms:event->keysym exwm--connection k)
+                    keycode (xcb:keysyms:keysym->keycode exwm--connection
+                                                         (car keysym)))
+              (setf (slot-value grab-key 'grab-window) workspace
+                    (slot-value grab-key 'modifiers) (cadr keysym)
+                    (slot-value grab-key 'key) keycode)
+              (when (or (not keycode)
+                        (xcb:+request-checked+request-check exwm--connection
+                            grab-key))
+                (user-error "[EXWM] Failed to grab key: %s"
+                            (single-key-description k))))))))))
 
 (defun exwm-input-set-key (key command)
   "Set a global key binding."
@@ -289,21 +314,6 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
   (with-slots (detail state) key-press
     (let ((keysym (xcb:keysyms:keycode->keysym exwm--connection detail state))
           event)
-      ;; Compensate FocusOut event (prevent cursor style change)
-      (unless (eq major-mode 'exwm-mode)
-        (let ((id (frame-parameter nil 'exwm-window-id)))
-          (xcb:+request exwm--connection
-              (make-instance 'xcb:SendEvent
-                             :propagate 0
-                             :destination id
-                             :event-mask xcb:EventMask:StructureNotify
-                             :event
-                             (xcb:marshal
-                              (make-instance 'xcb:FocusIn
-                                             :detail xcb:NotifyDetail:Inferior
-                                             :event id
-                                             :mode xcb:NotifyMode:Normal)
-                              exwm--connection)))))
       (when (and keysym
                  (setq event (xcb:keysyms:keysym->event exwm--connection
                                                         keysym state)))
@@ -324,7 +334,10 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
   (when id
     (when (xcb:+request-checked+request-check exwm--connection
               (make-instance 'xcb:GrabKey
-                             :owner-events 0 :grab-window id
+                             :owner-events 0
+                             :grab-window
+                             (with-current-buffer (exwm--id->buffer id)
+                               exwm--container)
                              :modifiers xcb:ModMask:Any
                              :key xcb:Grab:Any
                              :pointer-mode xcb:GrabMode:Async
@@ -338,7 +351,10 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
   (when id
     (when (xcb:+request-checked+request-check exwm--connection
               (make-instance 'xcb:UngrabKey
-                             :key xcb:Grab:Any :grab-window id
+                             :key xcb:Grab:Any
+                             :grab-window
+                             (with-current-buffer (exwm--id->buffer id)
+                               exwm--container)
                              :modifiers xcb:ModMask:Any))
       (exwm--log "Failed to release keyboard for #x%x" id))
     (setq exwm--on-KeyPress #'exwm-input--on-KeyPress-char-mode)))
@@ -487,7 +503,7 @@ SIMULATION-KEYS is a list of alist (key-sequence1 . key-sequence2)."
   (add-hook 'pre-command-hook #'exwm-input--finish-key-sequence)
   ;; Update focus when buffer list updates
   (add-hook 'buffer-list-update-hook #'exwm-input--on-buffer-list-update)
-  (add-hook 'focus-in-hook #'exwm-input--on-focus-in)
+  (add-hook 'minibuffer-setup-hook #'exwm-input--on-minibuffer-setup)
   ;; Update prefix keys for global keys
   (exwm-input--update-global-prefix-keys))