about summary refs log tree commit diff
path: root/exwm-layout.el
diff options
context:
space:
mode:
authorChris Feng <chris.w.feng@gmail.com>2018-02-17T17·04+0800
committerChris Feng <chris.w.feng@gmail.com>2018-02-17T17·04+0800
commit7823eb988c22f5dc804ef862d91a0fcf474ca718 (patch)
treec7a5428f6e195f5205750c9ad922b5f05bc6c407 /exwm-layout.el
parent83c0a2db3448091e44cded075104a0b7df636431 (diff)
Make X windows container-less
; This is an attempt to make (managed) X windows container-less, i.e. direct children of the root window.  This is mainly to make EXWM compatible with third-party compositors.  Other issues like wrong absolute position should also get resolved by the way.  The workspace containers ("virtual roots") are also removed.  However Emacs frames are still wrapped in containers to avoid unexpected stack reordering.

* exwm-cm.el: Make this module obsolete as EXWM supports third-party compositors now.

* exwm-core.el (exwm--container):
* exwm-floating.el (exwm-floating--set-floating)
(exwm-floating--unset-floating, exwm-floating-hide)
(exwm-floating--start-moveresize, exwm-floating--stop-moveresize)
(exwm-floating--do-moveresize, exwm-floating-move):
* exwm-input.el (exwm-input--update-focus):
* exwm-layout.el (exwm-layout--show, exwm-layout--hide)
(exwm-layout-set-fullscreen, exwm-layout-unset-fullscreen):
* exwm-manage.el (exwm-manage--manage-window, exwm-manage--unmanage-window)
(exwm-manage--kill-buffer-query-function, exwm-manage--kill-client):
* exwm-workspace.el (exwm-workspace--set-fullscreen, exwm-workspace-switch)
(exwm-workspace-move-window, exwm-workspace--add-frame-as-workspace)
(exwm-workspace--remove-frame-as-workspace): Make adaptions for container-less X windows.

* exwm-workspace.el (exwm-workspace--update-ewmh-props):
* exwm.el (exwm--init-icccm-ewmh, exwm--exit-icccm-ewmh): No longer use virtual roots.

* exwm-input.el (exwm-input--on-workspace-list-change)
(exwm-input--update-global-prefix-keys, exwm-input--init, exwm-input--exit): From now on global key bindings are grabbed on the root window so it's no long required to re-grab them each time the workspace list changes.  As a result `exwm-input--on-workspace-list-change' and its corresponding references are discarded.  It remains to be seen if this change will raise input focus issues.

* exwm-manage.el (exwm-manage--manage-window): Explicitly set the workspace for newly managed X windows.
* exwm-floating.el (exwm-floating--set-floating): Avoid implicit reference to the current workspace.

* exwm-core.el (exwm--set-geometry): New function for setting the geometry of an X window.
* exwm-layout.el (exwm-layout--resize-container): Replaced by `exwm-layout--resize-container'.

* exwm-core.el (exwm--guide-window): New global variable recording the guide X window.
* exwm.el (exwm--init-icccm-ewmh): Set it.

* exwm-input.el (exwm-input--post-init): New function containing staffs for initialization but should better get called after the event loop starts.
* exwm.el (exwm-init): Use it.
Diffstat (limited to 'exwm-layout.el')
-rw-r--r--exwm-layout.el178
1 files changed, 35 insertions, 143 deletions
diff --git a/exwm-layout.el b/exwm-layout.el
index bcf9c3a67f52..cda942e47df3 100644
--- a/exwm-layout.el
+++ b/exwm-layout.el
@@ -30,27 +30,6 @@
 (defvar exwm-floating-border-width)
 (defvar exwm-workspace--id-struts-alist)
 
-(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))))
-
 (defun exwm-layout--set-state (id state)
   "Set WM_STATE."
   (xcb:+request exwm--connection
@@ -73,72 +52,24 @@
          (y (pop edges))
          (width (- (pop edges) x))
          (height (- (pop edges) y))
-         (edges (window-inside-pixel-edges window))
-         (relative-x (pop edges))
-         (relative-y (pop edges))
-         frame-width frame-height)
+         frame-x frame-y frame-width frame-height)
     (with-current-buffer (exwm--id->buffer id)
-      (if (not exwm--floating-frame)
-          (exwm-layout--resize-container id exwm--container
-                                         relative-x relative-y width height
-                                         ;; Keep the size of the X window if
-                                         ;; it's the minibuffer that resized.
-                                         (and
-                                          (active-minibuffer-window)
-                                          (< 1 (window-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.
+      (when exwm--floating-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 relative-x
-                           :y relative-y
-                           :width width
-                           :height height)))
-      ;; Make the resizing take effect.
-      (xcb:flush exwm--connection)
+        (when exwm--floating-frame-position
+          (setq frame-x (elt exwm--floating-frame-position 0)
+                frame-y (elt exwm--floating-frame-position 1)
+                ;; The frame was placed at (-1, -1).
+                x (+ x frame-x 1)
+                y (+ y frame-y 1))
+          (setq exwm--floating-frame-position nil))
+        (exwm--set-geometry (frame-parameter exwm--floating-frame
+                                             'exwm-container)
+                            frame-x frame-y frame-width frame-height))
+      (exwm--set-geometry id x y width height)
       (xcb:+request exwm--connection (make-instance 'xcb:MapWindow :window id))
-      (xcb:+request exwm--connection
-          (make-instance 'xcb:MapWindow :window exwm--container))
-      (exwm-layout--set-state id xcb:icccm:WM_STATE:NormalState))
-    (xcb:+request exwm--connection
-        (make-instance 'xcb:SendEvent
-                       :propagate 0 :destination id
-                       :event-mask xcb:EventMask:StructureNotify
-                       :event (xcb:marshal
-                               (make-instance 'xcb:ConfigureNotify
-                                              :event id
-                                              :window id
-                                              :above-sibling xcb:Window:None
-                                              :x x
-                                              :y y
-                                              :width width
-                                              :height height
-                                              :border-width 0
-                                              :override-redirect 0)
-                               exwm--connection))))
+      (exwm-layout--set-state id xcb:icccm:WM_STATE:NormalState)))
   (xcb:flush exwm--connection))
 
 (defun exwm-layout--hide (id)
@@ -146,6 +77,15 @@
   (with-current-buffer (exwm--id->buffer id)
     (unless (exwm-layout--iconic-state-p) ;already hidden
       (exwm--log "Hide #x%x" id)
+      (when exwm--floating-frame
+        (let* ((container (frame-parameter exwm--floating-frame
+                                           'exwm-container))
+               (geometry (xcb:+request-unchecked+reply exwm--connection
+                             (make-instance 'xcb:GetGeometry
+                                            :drawable container))))
+          (setq exwm--floating-frame-position
+                (vector (slot-value geometry 'x) (slot-value geometry 'y)))
+          (exwm--set-geometry container -1 -1 1 1)))
       (xcb:+request exwm--connection
           (make-instance 'xcb:ChangeWindowAttributes
                          :window id :value-mask xcb:CW:EventMask
@@ -156,8 +96,6 @@
           (make-instance 'xcb:ChangeWindowAttributes
                          :window id :value-mask xcb:CW:EventMask
                          :event-mask exwm--client-event-mask))
-      (xcb:+request exwm--connection
-          (make-instance 'xcb:UnmapWindow :window exwm--container))
       (exwm-layout--set-state id xcb:icccm:WM_STATE:IconicState)
       (xcb:flush exwm--connection))))
 
@@ -167,9 +105,7 @@
 (declare-function exwm-input-release-keyboard "exwm-input.el")
 (declare-function exwm-workspace--current-height "exwm-workspace.el")
 (declare-function exwm-workspace--current-width  "exwm-workspace.el")
-(declare-function exwm-workspace--get-geometry "exwm-workspace.el" (frame))
 (declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el")
-(declare-function exwm-workspace--set-fullscreen "exwm-workspace.el" (frame))
 (declare-function exwm-workspace-move-window "exwm-workspace.el"
                   (frame-or-index &optional id))
 
@@ -180,41 +116,16 @@
   (with-current-buffer (if id (exwm--id->buffer id) (window-buffer))
     (when (memq xcb:Atom:_NET_WM_STATE_FULLSCREEN exwm--ewmh-state)
       (user-error "Already in full-screen mode"))
-    ;; Save the position of floating frame.
-    (when exwm--floating-frame
-      (let* ((geometry (xcb:+request-unchecked+reply exwm--connection
-                           (make-instance 'xcb:GetGeometry
-                                          :drawable exwm--container))))
-        (setq exwm--floating-frame-position
-              (vector (slot-value geometry 'x) (slot-value geometry 'y)))))
-    ;; Expand the workspace to fill the whole screen.
-    (with-slots (x y width height) (exwm-workspace--get-geometry exwm--frame)
-      (exwm-layout--resize-container nil
-                                     (frame-parameter exwm--frame
-                                                      'exwm-workspace)
-                                     x y width height
-                                     t))
-    ;; Raise the workspace container (in case there are docks).
-    (xcb:+request exwm--connection
-        (make-instance 'xcb:ConfigureWindow
-                       :window (frame-parameter exwm--frame 'exwm-workspace)
-                       :value-mask xcb:ConfigWindow:StackMode
-                       :stack-mode xcb:StackMode:Above))
-    ;; Expand the X window and its container to fill the whole screen.
+    ;; Expand the X window to fill the whole screen.
     ;; Rationale: Floating X windows may not be positioned at (0, 0)
     ;; due to the extra border.
-    (exwm-layout--resize-container nil exwm--container 0 0
-                                   (exwm-workspace--current-width)
-                                   (exwm-workspace--current-height)
-                                   t)
-    (exwm-layout--resize-container nil exwm--id 0 0
-                                   (exwm-workspace--current-width)
-                                   (exwm-workspace--current-height)
-                                   t)
+    (exwm--set-geometry exwm--id 0 0
+                        (exwm-workspace--current-width)
+                        (exwm-workspace--current-height))
     ;; Raise the X window.
     (xcb:+request exwm--connection
         (make-instance 'xcb:ConfigureWindow
-                       :window exwm--container
+                       :window exwm--id
                        :value-mask (logior xcb:ConfigWindow:BorderWidth
                                            xcb:ConfigWindow:StackMode)
                        :border-width 0
@@ -234,39 +145,20 @@
   (with-current-buffer (if id (exwm--id->buffer id) (window-buffer))
     (unless (memq xcb:Atom:_NET_WM_STATE_FULLSCREEN exwm--ewmh-state)
       (user-error "Not in full-screen mode"))
-    ;; Restore the size of this workspace.
-    (exwm-workspace--set-fullscreen exwm--frame)
     (if exwm--floating-frame
-        ;; Restore the floating frame.
-        (xcb:+request exwm--connection
-            (make-instance 'xcb:ConfigureWindow
-                           :window exwm--container
-                           :value-mask (eval-when-compile
-                                         (logior xcb:ConfigWindow:X
-                                                 xcb:ConfigWindow:Y
-                                                 xcb:ConfigWindow:BorderWidth))
-                           :x (elt exwm--floating-frame-position 0)
-                           :y (elt exwm--floating-frame-position 1)
-                           :border-width exwm-floating-border-width))
-      ;; Put the X window just above the Emacs frame.
+        (exwm-layout--show exwm--id (frame-root-window exwm--floating-frame))
       (xcb:+request exwm--connection
           (make-instance 'xcb:ConfigureWindow
-                         :window exwm--container
+                         :window exwm--id
                          :value-mask (logior xcb:ConfigWindow:Sibling
                                              xcb:ConfigWindow:StackMode)
-                         :sibling (frame-parameter exwm-workspace--current
-                                                   'exwm-container)
-                         :stack-mode xcb:StackMode:Above)))
-    (exwm-layout--show exwm--id)
+                         :sibling exwm--guide-window
+                         :stack-mode xcb:StackMode:Above))
+      (let ((window (get-buffer-window nil t)))
+        (when window
+          (exwm-layout--show exwm--id window))))
     (xcb:+request exwm--connection
         (make-instance 'xcb:ewmh:set-_NET_WM_STATE :window exwm--id :data []))
-    ;; Raise X windows with struts set again.
-    (dolist (pair exwm-workspace--id-struts-alist)
-      (xcb:+request exwm--connection
-          (make-instance 'xcb:ConfigureWindow
-                         :window (car pair)
-                         :value-mask xcb:ConfigWindow:StackMode
-                         :stack-mode xcb:StackMode:Above)))
     (xcb:flush exwm--connection)
     (setq exwm--ewmh-state
           (delq xcb:Atom:_NET_WM_STATE_FULLSCREEN exwm--ewmh-state))