about summary refs log tree commit diff
path: root/exwm-input.el
diff options
context:
space:
mode:
authorChris Feng <chris.w.feng@gmail.com>2016-02-03T04·12+0800
committerChris Feng <chris.w.feng@gmail.com>2016-02-03T04·12+0800
commit9c95c03e18f6d5cf78bcd54bf00f8055a3863336 (patch)
tree1733a55d18719fd8eba91055cacfd6de5c63bcad /exwm-input.el
parent07921a3731c3b951d7d5ecc35b808c40d1d15bd4 (diff)
Rework the X windows hierarchy model
This commit add workspace and X window containers support to avoid using
Emacs frames as the parents of X windows.  This should make it easier to
set input focus.

* exwm-core.el (exwm--container, exwm--floating-frame-position): New file
local variables.
(exwm--floating-frame-geometry): Removed file local variable.
* exwm-floating.el (exwm-floating--set-floating)
(exwm-floating--unset-floating, exwm-floating--do-moveresize)
(exwm-floating-move): Use container.
(exwm-floating--fit-frame-to-window): No longer adjust stacking order.
(exwm-floating--fit-frame-to-window): The first member is changed to
buffer.
(exwm-floating--start-moveresize): Use container.  Correctly set input
focus.
* exwm-input.el (exwm-input--redirected, exwm-input--on-focus-in): Removed.
(exwm-input--on-buffer-list-update): Remove the restriction on floating
frames which is no longer valid.
(exwm-input--update-focus): Adjust stacking order.
(exwm-input--on-minibuffer-setup): New function for setting focus on the
Emacs frame when entering minibuffer.
(exwm-input--on-KeyPress-line-mode): No longer compensate FocusOut event.
(exwm-input--grab-keyboard, exwm-input--release-keyboard): Local keys are
now grabbed on the X window container.
(exwm-input--init): Add `exwm-input--on-minibuffer-setup' to
`minibuffer-setup-hook'.
* exwm-layout.el (exwm-layout--resize-container): New function to
resize/reposition both the X window and its container.
(exwm-layout--show, exwm-layout--hide): Use container.
(exwm-layout-set-fullscreen): Use container.  No longer save width and
height.
(exwm-layout-unset-fullscreen, exwm-layout--set-frame-fullscreen): Use
container.
(exwm-layout--refresh): Update a frame parameter.  Remove dead code.
* exwm-manage.el (exwm-manage--manage-window): Reparent unmanaged X windows
to the workspace.  Create X window container as the parent of the X window.
(exwm-manage--unmanage-window): Unmap/destroy container when appropriate.
Use the position of container.
(exwm-manage--unmanage-window): Destroy the container.
* exwm-randr.el (exwm-randr--refresh): Resize workspace using container.
* exwm-workspace.el (exwm-workspace-switch): Raise workspace.
Correctly set input focus.
(exwm-workspace--on-focus-in): Removed.
(exwm-workspace-move-window): Reparent to workspace container.
(exwm-workspace--init): Create workspace frames as visible.
Create workspace containers.
Remove exwm-workspace--on-focus-in from focus-in-hook.
Update _NET_VIRTUAL_ROOTS.
* exwm.el (exwm-init): No longer disable hourglass window.
Initialize workspace module before input.

* exwm-core.el (exwm--debug): New macro for setting debug forms.

* exwm-floating.el (exwm-floating--set-floating): No longer do `exwm--lock'
and `exwm--unlock' since `make-frame' is already adviced to take care of
everything.  Correctly set input focus to the newly created floating
X window.

* exwm-core.el (exwm--floating-edges): Removed file local variable.
* exwm-floating.el (exwm-floating--set-floating)
(exwm-floating--unset-floating):
* exwm-layout.el (exwm-layout--show, exwm-layout-enlarge-window):
* exwm-manage.el (exwm-manage--on-ConfigureRequest):
No longer use floating geometry.

* exwm-input.el (exwm-input--update-global-prefix-keys): Grab global keys
on workspaces containers instead of the root window (or input focus would
transfer to the workspace containing the pointer when the grab is active).
* exwm-workspace.el (exwm-workspace-switch): No longer move mouse.
Diffstat (limited to 'exwm-input.el')
-rw-r--r--exwm-input.el140
1 files changed, 71 insertions, 69 deletions
diff --git a/exwm-input.el b/exwm-input.el
index 99a4b8fa628e..156399c74486 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,42 @@ 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
+            (xcb:+request exwm--connection
+                (make-instance 'xcb:ConfigureWindow
+                               :window exwm--container
+                               :value-mask xcb:ConfigWindow:StackMode
+                               :stack-mode (if exwm--floating-frame
+                                               xcb:StackMode:Above
+                                             xcb:StackMode:Below)))
+            (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:Below))
+            (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 +226,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 +300,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 +320,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 +337,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 +489,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))