about summary refs log tree commit diff
path: root/exwm-layout.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-layout.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-layout.el')
-rw-r--r--exwm-layout.el157
1 files changed, 75 insertions, 82 deletions
diff --git a/exwm-layout.el b/exwm-layout.el
index ffe1f1d0c4..c3bfcf8ef9 100644
--- a/exwm-layout.el
+++ b/exwm-layout.el
@@ -30,41 +30,72 @@
 
 (defvar exwm-floating-border-width)
 
+(defun exwm-layout--resize-container (id container x y width height
+                                         &optional container-only)
+  "Resize a container (and its content unless CONTAINER-ONLY is non-nil)."
+  (xcb:+request exwm--connection
+      (make-instance 'xcb:ConfigureWindow
+                     :window container
+                     :value-mask (eval-when-compile
+                                   (logior xcb:ConfigWindow:X
+                                           xcb:ConfigWindow:Y
+                                           xcb:ConfigWindow:Width
+                                           xcb:ConfigWindow:Height))
+                     :x x :y y :width width :height height))
+  (unless container-only
+    (xcb:+request exwm--connection
+        (make-instance 'xcb:ConfigureWindow
+                       :window id
+                       :value-mask (eval-when-compile
+                                     (logior xcb:ConfigWindow:Width
+                                             xcb:ConfigWindow:Height))
+                       :width width :height height))))
+
 ;;;###autoload
 (defun exwm-layout--show (id &optional window)
   "Show window ID exactly fit in the Emacs window WINDOW."
   (exwm--log "Show #x%x in %s" id window)
   (xcb:+request exwm--connection (make-instance 'xcb:MapWindow :window id))
+  (with-current-buffer (exwm--id->buffer id)
+    (xcb:+request exwm--connection
+        (make-instance 'xcb:MapWindow :window exwm--container)))
   (xcb:+request exwm--connection
       (make-instance 'xcb:icccm:set-WM_STATE
                      :window id :state xcb:icccm:WM_STATE:NormalState
                      :icon xcb:Window:None))
-  (let* ((buffer (exwm--id->buffer id))
-         (edges (or (and buffer
-                         (with-current-buffer buffer exwm--floating-edges))
-                    (window-inside-absolute-pixel-edges window)))
+  (let* ((edges (window-inside-absolute-pixel-edges window))
          (width (- (elt edges 2) (elt edges 0)))
-         (height (- (elt edges 3) (elt edges 1)))
-         x y)
-    (if exwm--floating-edges
-        ;; The relative position of a floating X window is determinate
-        (setq x exwm-floating-border-width
-              y exwm-floating-border-width)
-      (let ((relative-edges (window-inside-pixel-edges window)))
-        (setq x (elt relative-edges 0)
-              y (elt relative-edges 1))))
-    (xcb:+request exwm--connection
-        (make-instance 'xcb:ConfigureWindow
-                       :window id
-                       :value-mask (eval-when-compile
-                                     (logior xcb:ConfigWindow:X
-                                             xcb:ConfigWindow:Y
-                                             xcb:ConfigWindow:Width
-                                             xcb:ConfigWindow:Height
-                                             xcb:ConfigWindow:StackMode))
-                       :x x :y y :width width :height height
-                       ;; In order to put non-floating window at bottom
-                       :stack-mode xcb:StackMode:Below))
+         (height (- (elt edges 3) (elt edges 1))))
+    (with-current-buffer (exwm--id->buffer id)
+      (if exwm--floating-frame
+          ;; A floating X window is of the same size as the Emacs window,
+          ;; whereas its container is of the same size as the Emacs frame.
+          (progn
+            (xcb:+request exwm--connection
+                (make-instance 'xcb:ConfigureWindow
+                               :window exwm--container
+                               :value-mask (logior xcb:ConfigWindow:Width
+                                                   xcb:ConfigWindow:Height)
+                               :width (frame-pixel-width exwm--floating-frame)
+                               :height (frame-pixel-height
+                                        exwm--floating-frame)))
+            (xcb:+request exwm--connection
+                (make-instance 'xcb:ConfigureWindow
+                               :window exwm--id
+                               :value-mask (logior xcb:ConfigWindow:X
+                                                   xcb:ConfigWindow:Y
+                                                   xcb:ConfigWindow:Width
+                                                   xcb:ConfigWindow:Height)
+                               :x exwm-floating-border-width
+                               :y exwm-floating-border-width
+                               :width width
+                               :height height)))
+        (let ((relative-edges (window-inside-pixel-edges window)))
+          (exwm-layout--resize-container id exwm--container
+                                         (elt relative-edges 0)
+                                         (elt relative-edges 1)
+                                         width height
+                                         (active-minibuffer-window)))))
     (xcb:+request exwm--connection
         (make-instance 'xcb:SendEvent
                        :propagate 0 :destination id
@@ -96,6 +127,9 @@
         (make-instance 'xcb:ChangeWindowAttributes
                        :window id :value-mask xcb:CW:EventMask
                        :event-mask exwm--client-event-mask))
+    (with-current-buffer (exwm--id->buffer id)
+      (xcb:+request exwm--connection
+          (make-instance 'xcb:UnmapWindow :window exwm--container)))
     (xcb:+request exwm--connection
         (make-instance 'xcb:icccm:set-WM_STATE
                        :window id
@@ -112,38 +146,16 @@
       (user-error "Already in full-screen mode."))
     ;; Set the floating frame fullscreen first when the client is floating
     (when exwm--floating-frame
-      (let* ((outer-id (frame-parameter exwm--floating-frame 'exwm-outer-id))
-             (geometry (xcb:+request-unchecked+reply exwm--connection
+      (let* ((geometry (xcb:+request-unchecked+reply exwm--connection
                            (make-instance 'xcb:GetGeometry
-                                          :drawable outer-id))))
-        (setq exwm--floating-frame-geometry
-              (vector (slot-value geometry 'x) (slot-value geometry 'y)
-                      (slot-value geometry 'width)
-                      (slot-value geometry 'height)))
-        (xcb:+request exwm--connection
-            (make-instance 'xcb:ConfigureWindow
-                           :window outer-id
-                           :value-mask (eval-when-compile
-                                         (logior xcb:ConfigWindow:X
-                                                 xcb:ConfigWindow:Y
-                                                 xcb:ConfigWindow:Width
-                                                 xcb:ConfigWindow:Height))
-                           :x 0 :y 0
-                           :width (frame-pixel-width exwm-workspace--current)
-                           :height (frame-pixel-height
-                                    exwm-workspace--current))))
+                                          :drawable exwm--container))))
+        (setq exwm--floating-frame-position
+              (vector (slot-value geometry 'x) (slot-value geometry 'y))))
       (xcb:flush exwm--connection))
-    (xcb:+request exwm--connection
-        (make-instance 'xcb:ConfigureWindow
-                       :window exwm--id
-                       :value-mask (eval-when-compile
-                                     (logior xcb:ConfigWindow:X
-                                             xcb:ConfigWindow:Y
-                                             xcb:ConfigWindow:Width
-                                             xcb:ConfigWindow:Height))
-                       :x 0 :y 0
-                       :width (frame-pixel-width exwm-workspace--current)
-                       :height (frame-pixel-height exwm-workspace--current)))
+    (exwm-layout--resize-container exwm--id exwm--container 0 0
+                                   (frame-pixel-width exwm-workspace--current)
+                                   (frame-pixel-height
+                                    exwm-workspace--current))
     (xcb:+request exwm--connection
         (make-instance 'xcb:ewmh:set-_NET_WM_STATE
                        :window exwm--id
@@ -162,17 +174,12 @@
     (when exwm--floating-frame
       (xcb:+request exwm--connection
           (make-instance 'xcb:ConfigureWindow
-                         :window (frame-parameter exwm--floating-frame
-                                                  'exwm-outer-id)
+                         :window exwm--container
                          :value-mask (eval-when-compile
                                        (logior xcb:ConfigWindow:X
-                                               xcb:ConfigWindow:Y
-                                               xcb:ConfigWindow:Width
-                                               xcb:ConfigWindow:Height))
-                         :x (elt exwm--floating-frame-geometry 0)
-                         :y (elt exwm--floating-frame-geometry 1)
-                         :width (elt exwm--floating-frame-geometry 2)
-                         :height (elt exwm--floating-frame-geometry 3))))
+                                               xcb:ConfigWindow:Y))
+                         :x (elt exwm--floating-frame-position 0)
+                         :y (elt exwm--floating-frame-position 1))))
     (exwm-layout--show exwm--id)
     (xcb:+request exwm--connection
         (make-instance 'xcb:ewmh:set-_NET_WM_STATE :window exwm--id :data []))
@@ -193,19 +200,10 @@
                       (make-instance 'xcb:RECTANGLE :x 0 :y 0
                                      :width (x-display-pixel-width)
                                      :height (x-display-pixel-height))))
-        (id (frame-parameter frame 'exwm-outer-id)))
+        (id (frame-parameter frame 'exwm-outer-id))
+        (workspace (frame-parameter frame 'exwm-workspace)))
     (with-slots (x y width height) geometry
-      (xcb:+request exwm--connection
-          (make-instance 'xcb:ConfigureWindow
-                         :window id
-                         :value-mask (eval-when-compile
-                                       (logior xcb:ConfigWindow:X
-                                               xcb:ConfigWindow:Y
-                                               xcb:ConfigWindow:Width
-                                               xcb:ConfigWindow:Height))
-                         :x x :y y
-                         :width width
-                         :height height))
+      (exwm-layout--resize-container id workspace x y width height)
       (xcb:flush exwm--connection))))
 
 (defvar exwm-layout-show-all-buffers nil
@@ -221,7 +219,7 @@
                            (get-buffer "*scratch*"))))
         windows)
     (if (not (memq frame exwm-workspace--list))
-        (if (frame-parameter frame 'exwm-window-id)
+        (if (frame-parameter frame 'exwm-outer-id)
             ;; Refresh a floating frame
             (when (eq major-mode 'exwm-mode)
               (let ((window (frame-first-window frame)))
@@ -230,9 +228,6 @@
                   (exwm-layout--show exwm--id window))))
           ;; Other frames (e.g. terminal/graphical frame of emacsclient)
           ;; We shall bury all `exwm-mode' buffers in this case
-          (unless placeholder ;create the *scratch* buffer if it's killed
-            (setq placeholder (get-buffer-create "*scratch*"))
-            (set-buffer-major-mode placeholder))
           (setq windows (window-list frame 0)) ;exclude minibuffer
           (dolist (window windows)
             (with-current-buffer (window-buffer window)
@@ -329,7 +324,6 @@ windows."
             (setq width (max (+ exwm--normal-hints-min-width margin)
                              (+ width delta))))))
       (when width
-        (setq exwm--floating-edges nil) ;invalid from now on
         (xcb:+request exwm--connection
             (make-instance 'xcb:ConfigureWindow
                            :window (frame-parameter exwm--floating-frame
@@ -356,7 +350,6 @@ windows."
             (setq height (max (+ exwm--normal-hints-min-height margin)
                               (+ height delta))))))
       (when height
-        (setq exwm--floating-edges nil) ;invalid from now on
         (xcb:+request exwm--connection
             (make-instance 'xcb:ConfigureWindow
                            :window (frame-parameter exwm--floating-frame