about summary refs log tree commit diff
diff options
context:
space:
mode:
authorChris Feng <chris.w.feng@gmail.com>2016-02-20T13·52+0800
committerChris Feng <chris.w.feng@gmail.com>2016-02-20T13·52+0800
commite3d33a4aad6b5748e9352501b2c6cb058379025f (patch)
tree0e3d16cfbbf04e7990fd18a6372ef6a582a773fd
parent1c79e1c2384128915357ea629fc2a0503bd36733 (diff)
Prevent Emacs frames from restacking themselves
Putting Emacs frames (workspace frames, floating frames) into dedicated
containers greatly simplifies the stacking order management and totally
fixes relevant issues.

* exwm-floating.el (exwm-floating--set-floating): Create floating frame
container.  Remove redundant stacking order modification code.
(exwm-floating--unset-floating): Destroy the floating frame container.
No need to reparent the X window container.
(exwm-floating--do-moveresize): Resize the floating frame container.
* exwm-input.el (exwm-input--update-focus): No need to restack frames.
* exwm-layout.el (exwm-layout--show, exwm-layout--set-frame-fullscreen)
(exwm-layout-enlarge-window): Resize the floating frame container.
* exwm-manage.el (exwm-manage--on-ConfigureRequest): Re-enable stacking
order modification on ConfigureRequest.

* exwm-workspace.el (exwm-workspace--confirm-kill-emacs): Reparent out all
frames on exit.  No need to remove selected events or created resources.
(exwm-workspace--init): Create workspace frame containers.

* exwm-layout.el (exwm-layout-set-fullscreen):
* exwm-manage.el (exwm-manage--unmanage-window): Remove a redundant call to
`xcb:flush'.

* exwm-manage.el (exwm-manage--unmanage-window): Force unmap the X window.
Unmap the floating frame before reparent it.
-rw-r--r--exwm-floating.el109
-rw-r--r--exwm-input.el14
-rw-r--r--exwm-layout.el88
-rw-r--r--exwm-manage.el42
-rw-r--r--exwm-workspace.el60
5 files changed, 192 insertions, 121 deletions
diff --git a/exwm-floating.el b/exwm-floating.el
index 276948801d95..1ec54d10fa71 100644
--- a/exwm-floating.el
+++ b/exwm-floating.el
@@ -90,6 +90,7 @@
          (outer-id (string-to-number (frame-parameter frame 'outer-window-id)))
          (container (with-current-buffer (exwm--id->buffer id)
                       exwm--container))
+         (frame-container (xcb:generate-id exwm--connection))
          (window (frame-first-window frame)) ;and it's the only window
          (x (slot-value exwm--geometry 'x))
          (y (slot-value exwm--geometry 'y))
@@ -103,8 +104,9 @@
             y (- y (slot-value frame-geometry 'y))))
     (exwm--log "Floating geometry (original, relative): %dx%d%+d%+d"
                width height x y)
-    ;; Save window IDs
+    ;; Save frame parameters.
     (set-frame-parameter frame 'exwm-outer-id outer-id)
+    (set-frame-parameter frame 'exwm-container frame-container)
     ;; Set urgency flag if it's not appear in the active workspace
     (let ((idx (cl-position original-frame exwm-workspace--list)))
       (when (/= idx exwm-workspace-current-index)
@@ -163,18 +165,43 @@
     ;; timely.
     ;; The frame will be made visible by `select-frame-set-input-focus'.
     (make-frame-invisible frame)
-    (let ((edges (window-inside-pixel-edges window)))
-      (set-frame-size frame
-                      (+ width (- (frame-pixel-width frame)
-                                  (- (elt edges 2) (elt edges 0))))
-                      (+ height (- (frame-pixel-height frame)
-                                   (- (elt edges 3) (elt edges 1))))
-                      t))
-    ;; Reparent this frame to the container
+    (let* ((edges (window-inside-pixel-edges window))
+           (frame-width (+ width (- (frame-pixel-width frame)
+                                    (- (elt edges 2) (elt edges 0)))))
+           (frame-height (+ height (- (frame-pixel-height frame)
+                                      (- (elt edges 3) (elt edges 1))))))
+      (set-frame-size frame frame-width frame-height t)
+      ;; Create the frame container as the parent of the frame and
+      ;; a child of the X window container.
+      (xcb:+request exwm--connection
+          (make-instance 'xcb:CreateWindow
+                         :depth 0 :wid frame-container
+                         :parent container
+                         :x 0 :y 0 :width width :height height :border-width 0
+                         :class xcb:WindowClass:CopyFromParent
+                         :visual 0      ;CopyFromParent
+                         :value-mask xcb:CW:OverrideRedirect
+                         :override-redirect 1))
+      ;; Put it at bottom.
+      (xcb:+request exwm--connection
+          (make-instance 'xcb:ConfigureWindow
+                         :window frame-container
+                         :value-mask xcb:ConfigWindow:StackMode
+                         :stack-mode xcb:StackMode:Below))
+      ;; Map it.
+      (xcb:+request exwm--connection
+          (make-instance 'xcb:MapWindow :window frame-container))
+      (exwm--debug
+       (xcb:+request exwm--connection
+           (make-instance 'xcb:ewmh:set-_NET_WM_NAME
+                          :window frame-container
+                          :data
+                          (format "floating frame container for 0x%x" id)))))
+    ;; Reparent this frame to its container.
     (xcb:+request exwm--connection
         (make-instance 'xcb:ReparentWindow
-                       :window outer-id :parent container :x 0 :y 0))
-    ;; Place the container
+                       :window outer-id :parent frame-container :x 0 :y 0))
+    ;; Place the X window container.
     (xcb:+request exwm--connection
         (make-instance 'xcb:ConfigureWindow
                        :window container
@@ -193,16 +220,9 @@
       (remove-hook 'window-configuration-change-hook #'exwm-layout--refresh)
       (set-window-buffer window (current-buffer)) ;this changes current buffer
       (add-hook 'window-configuration-change-hook #'exwm-layout--refresh)
-      (set-window-dedicated-p window t))
-    (select-frame-set-input-focus frame)
-    ;; `x_make_frame_visible' autoraises the frame.  Force lowering it.
-    (xcb:+request exwm--connection
-        (make-instance 'xcb:ConfigureWindow
-                       :window outer-id
-                       :value-mask xcb:ConfigWindow:StackMode
-                       :stack-mode xcb:StackMode:Below))
-    ;; Show the X window with its container (and flush).
-    (exwm-layout--show id window))
+      (set-window-dedicated-p window t)
+      (exwm-layout--show id window))
+    (select-frame-set-input-focus frame))
   (run-hooks 'exwm-floating-setup-hook)
   ;; Redraw the frame.
   (redisplay))
@@ -229,29 +249,28 @@
                            :window id :value-mask xcb:CW:EventMask
                            :event-mask exwm--client-event-mask))
         ;; Reparent the floating frame back to the root window.
-        (let ((frame-id (frame-parameter exwm--floating-frame 'exwm-outer-id)))
+        (let ((frame-id (frame-parameter exwm--floating-frame 'exwm-outer-id))
+              (frame-container (frame-parameter exwm--floating-frame
+                                                'exwm-container)))
           (xcb:+request exwm--connection
               (make-instance 'xcb:UnmapWindow :window frame-id))
           (xcb:+request exwm--connection
               (make-instance 'xcb:ReparentWindow
                              :window frame-id
                              :parent exwm--root
-                             :x 0 :y 0))))
-      ;; Reparent the container to the workspace
-      (xcb:+request exwm--connection
-          (make-instance 'xcb:ReparentWindow
-                         :window exwm--container
-                         :parent (frame-parameter exwm-workspace--current
-                                                  'exwm-workspace)
-                         :x 0 :y 0))    ;temporary position
-      ;; Put the container just above the Emacs frame
+                             :x 0 :y 0))
+          ;; Also destroy its container.
+          (xcb:+request exwm--connection
+              (make-instance 'xcb:DestroyWindow :window frame-container))))
+      ;; Put the X window container just above the Emacs frame container
+      ;; (the stacking order won't change from now on).
       (xcb:+request exwm--connection
           (make-instance 'xcb:ConfigureWindow
                          :window exwm--container
                          :value-mask (logior xcb:ConfigWindow:Sibling
                                              xcb:ConfigWindow:StackMode)
                          :sibling (frame-parameter exwm-workspace--current
-                                                   'exwm-outer-id)
+                                                   'exwm-container)
                          :stack-mode xcb:StackMode:Above)))
     (xcb:flush exwm--connection)
     (with-current-buffer buffer
@@ -466,13 +485,19 @@
           (geometry (frame-parameter exwm-workspace--current 'exwm-geometry))
           (frame-x 0)
           (frame-y 0)
-          result)
+          result value-mask width height)
       (when geometry
         (setq frame-x (slot-value geometry 'x)
               frame-y (slot-value geometry 'y)))
       (xcb:unmarshal obj data)
       (setq result (funcall exwm-floating--moveresize-calculate
-                            (slot-value obj 'root-x) (slot-value obj 'root-y)))
+                            (slot-value obj 'root-x) (slot-value obj 'root-y))
+            value-mask (logand (aref result 1)
+                               (eval-when-compile
+                                 (logior xcb:ConfigWindow:Width
+                                         xcb:ConfigWindow:Height)))
+            width (aref result 4)
+            height (aref result 5))
       (with-current-buffer (aref result 0)
         (xcb:+request exwm--connection
             (make-instance 'xcb:ConfigureWindow
@@ -486,13 +511,17 @@
         (xcb:+request exwm--connection
             (make-instance 'xcb:ConfigureWindow
                            :window (frame-parameter exwm--floating-frame
+                                                    'exwm-container)
+                           :value-mask value-mask
+                           :width width
+                           :height height))
+        (xcb:+request exwm--connection
+            (make-instance 'xcb:ConfigureWindow
+                           :window (frame-parameter exwm--floating-frame
                                                     'exwm-outer-id)
-                           :value-mask
-                           (logand (aref result 1)
-                                   (eval-when-compile
-                                     (logior xcb:ConfigWindow:Width
-                                             xcb:ConfigWindow:Height)))
-                           :width (aref result 4) :height (aref result 5))))
+                           :value-mask value-mask
+                           :width width
+                           :height height)))
       (xcb:flush exwm--connection))))
 
 (defun exwm-floating-move (&optional delta-x delta-y)
diff --git a/exwm-input.el b/exwm-input.el
index 5e078030c2ef..0a50bef26203 100644
--- a/exwm-input.el
+++ b/exwm-input.el
@@ -113,8 +113,8 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
                 (exwm-workspace-switch exwm-workspace-current-index t))
             (exwm--log "Set focus on #x%x" exwm--id)
             (exwm-input--set-focus exwm--id)
-            ;; Adjust stacking orders
             (when exwm--floating-frame
+              ;; Adjust stacking orders of the floating container.
               (if (exwm-workspace--minibuffer-own-frame-p)
                   ;; Put this floating X window just below the minibuffer.
                   (xcb:+request exwm--connection
@@ -132,16 +132,8 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
                     (make-instance 'xcb:ConfigureWindow
                                    :window exwm--container
                                    :value-mask xcb:ConfigWindow:StackMode
-                                   :stack-mode xcb:StackMode:Above))))
-            ;; 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))
+                                   :stack-mode xcb:StackMode:Above)))
+              (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)
diff --git a/exwm-layout.el b/exwm-layout.el
index e3c1febc4478..c9146de3714e 100644
--- a/exwm-layout.el
+++ b/exwm-layout.el
@@ -55,37 +55,46 @@
   (exwm--log "Show #x%x in %s" id window)
   (let* ((edges (window-inside-absolute-pixel-edges window))
          (width (- (elt edges 2) (elt edges 0)))
-         (height (- (elt edges 3) (elt edges 1))))
+         (height (- (elt edges 3) (elt edges 1)))
+         frame-width frame-height)
     (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))))
+      (if (not exwm--floating-frame)
+          (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)))
+        ;; 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.
+        (setq frame-width (frame-pixel-width exwm--floating-frame)
+              frame-height (frame-pixel-height exwm--floating-frame))
+        (xcb:+request exwm--connection
+            (make-instance 'xcb:ConfigureWindow
+                           :window exwm--container
+                           :value-mask (logior xcb:ConfigWindow:Width
+                                               xcb:ConfigWindow:Height)
+                           :width frame-width
+                           :height frame-height))
+        (xcb:+request exwm--connection
+            (make-instance 'xcb:ConfigureWindow
+                           :window (frame-parameter exwm--floating-frame
+                                                    'exwm-container)
+                           :value-mask (logior xcb:ConfigWindow:Width
+                                               xcb:ConfigWindow:Height)
+                           :width frame-width
+                           :height frame-height))
+        (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)))
       ;; Make the resizing take effect.
       (xcb:flush exwm--connection)
       (xcb:+request exwm--connection (make-instance 'xcb:MapWindow :window id))
@@ -151,8 +160,7 @@
                            (make-instance 'xcb:GetGeometry
                                           :drawable exwm--container))))
         (setq exwm--floating-frame-position
-              (vector (slot-value geometry 'x) (slot-value geometry 'y))))
-      (xcb:flush exwm--connection))
+              (vector (slot-value geometry 'x) (slot-value geometry 'y)))))
     (exwm-layout--resize-container exwm--id exwm--container 0 0
                                    (exwm-workspace--current-width)
                                    (exwm-workspace--current-height))
@@ -205,12 +213,14 @@
                                      :width (x-display-pixel-width)
                                      :height (x-display-pixel-height))))
         (id (frame-parameter frame 'exwm-outer-id))
+        (container (frame-parameter frame 'exwm-container))
         (workspace (frame-parameter frame 'exwm-workspace)))
     (with-slots (x y width height) geometry
       (when (and (eq frame exwm-workspace--current)
                  (exwm-workspace--minibuffer-own-frame-p))
         (exwm-workspace--resize-minibuffer-frame width height))
-      (exwm-layout--resize-container id workspace x y width height)
+      (exwm-layout--resize-container id container 0 0 width height)
+      (exwm-layout--resize-container nil workspace x y width height t)
       (xcb:flush exwm--connection)))
   (cl-incf exwm-layout--fullscreen-frame-count))
 
@@ -349,6 +359,12 @@ windows."
                                                     'exwm-outer-id)
                            :value-mask xcb:ConfigWindow:Width
                            :width width))
+        (xcb:+request exwm--connection
+            (make-instance 'xcb:ConfigureWindow
+                           :window (frame-parameter exwm--floating-frame
+                                                    'exwm-container)
+                           :value-mask xcb:ConfigWindow:Width
+                           :width width))
         (xcb:flush exwm--connection))))
    (t
     (let* ((height (frame-pixel-height))
@@ -375,6 +391,12 @@ windows."
                                                     'exwm-outer-id)
                            :value-mask xcb:ConfigWindow:Height
                            :height height))
+        (xcb:+request exwm--connection
+            (make-instance 'xcb:ConfigureWindow
+                           :window (frame-parameter exwm--floating-frame
+                                                    'exwm-container)
+                           :value-mask xcb:ConfigWindow:Height
+                           :height height))
         (xcb:flush exwm--connection))))))
 
 ;;;###autoload
diff --git a/exwm-manage.el b/exwm-manage.el
index c9c6ff9d2c6c..fd1d64bafd3b 100644
--- a/exwm-manage.el
+++ b/exwm-manage.el
@@ -224,6 +224,9 @@ corresponding buffer.")
         (xcb:+request exwm--connection
             (make-instance 'xcb:UnmapWindow :window exwm--container))
         (xcb:flush exwm--connection)
+        ;; Unmap the X window.
+        (xcb:+request exwm--connection
+            (make-instance 'xcb:UnmapWindow :window id))
         ;;
         (setq exwm-workspace--switch-history-outdated t)
         ;;
@@ -256,18 +259,17 @@ corresponding buffer.")
           (xcb:+request exwm--connection
               (make-instance 'xcb:DeleteProperty
                              :window id :property xcb:Atom:WM_STATE)))
-        ;; Destroy the container (it seems it has to be delayed).
         (when exwm--floating-frame
-          ;; Unmap the floating frame.
+          ;; Unmap the floating frame before destroying the containers.
           (let ((window (frame-parameter exwm--floating-frame 'exwm-outer-id)))
             (xcb:+request exwm--connection
                 (make-instance 'xcb:UnmapWindow :window window))
             (xcb:+request exwm--connection
                 (make-instance 'xcb:ReparentWindow
                                :window window :parent exwm--root :x 0 :y 0))))
+        ;; Destroy the X window container (and the frame container if any).
         (xcb:+request exwm--connection
             (make-instance 'xcb:DestroyWindow :window exwm--container))
-        (xcb:flush exwm--connection)
         (let ((kill-buffer-query-functions nil)
               (floating exwm--floating-frame))
           (kill-buffer)
@@ -310,12 +312,14 @@ corresponding buffer.")
           (make-instance 'xcb:UnmapWindow :window exwm--container))
       (xcb:flush exwm--connection)
       (when exwm--floating-frame
-        (xcb:+request exwm--connection
-            (make-instance 'xcb:ReparentWindow
-                           :window (frame-parameter exwm--floating-frame
-                                                    'exwm-outer-id)
-                           :parent exwm--root
-                           :x 0 :y 0)))
+        (let ((window (frame-parameter exwm--floating-frame 'exwm-outer-id)))
+          (xcb:+request exwm--connection
+              (make-instance 'xcb:UnmapWindow :window window))
+          (xcb:+request exwm--connection
+              (make-instance 'xcb:ReparentWindow
+                             :window window
+                             :parent exwm--root
+                             :x 0 :y 0))))
       (xcb:+request exwm--connection
           (make-instance 'xcb:DestroyWindow :window exwm--container))
       (xcb:flush exwm--connection)
@@ -410,10 +414,13 @@ Would you like to kill it? "
   (let ((obj (make-instance 'xcb:ConfigureRequest))
         buffer edges)
     (xcb:unmarshal obj data)
-    (with-slots (window x y width height border-width value-mask)
+    (with-slots (window x y width height
+                        border-width sibling stack-mode value-mask)
         obj
-      (exwm--log "ConfigureRequest from #x%x (#x%x) @%dx%d%+d%+d, border: %d"
-                 window value-mask width height x y border-width)
+      (exwm--log "ConfigureRequest from #x%x (#x%x) @%dx%d%+d%+d; \
+border-width: %d; sibling: #x%x; stack-mode: %d"
+                 window value-mask width height x y
+                 border-width sibling stack-mode)
       (if (setq buffer (exwm--id->buffer window))
           ;; Send client message for managed windows
           (with-current-buffer buffer
@@ -440,16 +447,15 @@ Would you like to kill it? "
                                         :border-width 0 :override-redirect 0)
                                        exwm--connection))))
         (exwm--log "ConfigureWindow (preserve geometry)")
-        ;; Configure the unmanaged window without changing the stacking order.
+        ;; Configure the unmanaged window.
         (xcb:+request exwm--connection
             (make-instance 'xcb:ConfigureWindow
                            :window window
-                           :value-mask
-                           (logand value-mask
-                                   (lognot xcb:ConfigWindow:Sibling)
-                                   (lognot xcb:ConfigWindow:StackMode))
+                           :value-mask value-mask
                            :x x :y y :width width :height height
-                           :border-width border-width)))))
+                           :border-width border-width
+                           :sibling sibling
+                           :stack-mode stack-mode)))))
   (xcb:flush exwm--connection))
 
 (defun exwm-manage--on-MapRequest (data _synthetic)
diff --git a/exwm-workspace.el b/exwm-workspace.el
index 99e3b5510ea5..42c081820eb5 100644
--- a/exwm-workspace.el
+++ b/exwm-workspace.el
@@ -252,7 +252,7 @@ The optional FORCE option is for internal use only."
                (concat " " name)))))
         (setq exwm--frame frame)
         (if exwm--floating-frame
-            ;; Move the floating frame is enough
+            ;; Move the floating container.
             (progn
               (xcb:+request exwm--connection
                   (make-instance 'xcb:ReparentWindow
@@ -261,7 +261,7 @@ The optional FORCE option is for internal use only."
                                  (frame-parameter frame 'exwm-workspace)
                                  :x 0 :y 0))
               (xcb:flush exwm--connection))
-          ;; Move the window itself
+          ;; Move the X window container.
           (if (/= index exwm-workspace-current-index)
               (bury-buffer)
             (set-window-buffer (get-buffer-window (current-buffer) t)
@@ -483,28 +483,30 @@ This functions is modified from `display-buffer-reuse-window' and
           (0 (y-or-n-p prompt))
           (x (yes-or-no-p (format "[EXWM] %d window%s currently alive. %s"
                                   x (if (= x 1) "" "s") prompt))))
-    ;; Remove SubstructureRedirect event.
-    (xcb:+request exwm--connection
-        (make-instance 'xcb:ChangeWindowAttributes
-                       :window exwm--root :value-mask xcb:CW:EventMask
-                       :event-mask 0))
-    ;; Remove the _NET_SUPPORTING_WM_CHECK X window.
-    (with-slots (value)
-        (xcb:+request-unchecked+reply exwm--connection
-            (make-instance 'xcb:ewmh:get-_NET_SUPPORTING_WM_CHECK
-                           :window exwm--root))
-      (xcb:+request exwm--connection
-          (make-instance 'xcb:DeleteProperty
-                         :window exwm--root
-                         :property xcb:Atom:_NET_SUPPORTING_WM_CHECK))
-      (xcb:+request exwm--connection
-          (make-instance 'xcb:DestroyWindow :window value)))
     ;; Unmanage all X windows.
     (dolist (i exwm--id-buffer-alist)
       (exwm-manage--unmanage-window (car i) t)
       (xcb:+request exwm--connection
           (make-instance 'xcb:MapWindow :window (car i))))
+    ;; Reparent out the minibuffer frame.
+    (when exwm-workspace-minibuffer-position
+      (xcb:+request exwm--connection
+          (make-instance 'xcb:ReparentWindow
+                         :window (frame-parameter exwm-workspace--minibuffer
+                                                  'exwm-outer-id)
+                         :parent exwm--root
+                         :x 0
+                         :y 0)))
+    ;; Reparent out all workspace frames.
+    (dolist (f exwm-workspace--list)
+      (xcb:+request exwm--connection
+          (make-instance 'xcb:ReparentWindow
+                         :window (frame-parameter f 'exwm-outer-id)
+                         :parent exwm--root
+                         :x 0
+                         :y 0)))
     (xcb:flush exwm--connection)
+    ;; Destroy all resources created by this connection.
     (xcb:disconnect exwm--connection)
     t))
 
@@ -589,9 +591,11 @@ This functions is modified from `display-buffer-reuse-window' and
   ;; Configure workspaces
   (dolist (i exwm-workspace--list)
     (let ((outer-id (string-to-number (frame-parameter i 'outer-window-id)))
+          (container (xcb:generate-id exwm--connection))
           (workspace (xcb:generate-id exwm--connection)))
       ;; Save window IDs
       (set-frame-parameter i 'exwm-outer-id outer-id)
+      (set-frame-parameter i 'exwm-container container)
       (set-frame-parameter i 'exwm-workspace workspace)
       (xcb:+request exwm--connection
           (make-instance 'xcb:CreateWindow
@@ -605,16 +609,34 @@ This functions is modified from `display-buffer-reuse-window' and
                                              xcb:CW:EventMask)
                          :override-redirect 1
                          :event-mask xcb:EventMask:SubstructureRedirect))
+      (xcb:+request exwm--connection
+          (make-instance 'xcb:CreateWindow
+                         :depth 0 :wid container :parent workspace
+                         :x 0 :y 0
+                         :width (x-display-pixel-width)
+                         :height (x-display-pixel-height)
+                         :border-width 0 :class xcb:WindowClass:CopyFromParent
+                         :visual 0      ;CopyFromParent
+                         :value-mask xcb:CW:OverrideRedirect
+                         :override-redirect 1))
       (exwm--debug
        (xcb:+request exwm--connection
            (make-instance 'xcb:ewmh:set-_NET_WM_NAME
                           :window workspace
                           :data
                           (format "EXWM workspace %d"
+                                  (cl-position i exwm-workspace--list))))
+       (xcb:+request exwm--connection
+           (make-instance 'xcb:ewmh:set-_NET_WM_NAME
+                          :window container
+                          :data
+                          (format "EXWM workspace %d frame container"
                                   (cl-position i exwm-workspace--list)))))
       (xcb:+request exwm--connection
           (make-instance 'xcb:ReparentWindow
-                         :window outer-id :parent workspace :x 0 :y 0))
+                         :window outer-id :parent container :x 0 :y 0))
+      (xcb:+request exwm--connection
+          (make-instance 'xcb:MapWindow :window container))
       (xcb:+request exwm--connection
           (make-instance 'xcb:MapWindow :window workspace))))
   (xcb:flush exwm--connection)