about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--exwm-layout.el25
-rw-r--r--exwm-manage.el29
-rw-r--r--exwm-randr.el3
-rw-r--r--exwm-workspace.el105
-rw-r--r--exwm.el52
5 files changed, 149 insertions, 65 deletions
diff --git a/exwm-layout.el b/exwm-layout.el
index 259788f66c26..b79e42e641ca 100644
--- a/exwm-layout.el
+++ b/exwm-layout.el
@@ -155,6 +155,9 @@
 (defvar exwm-workspace--current)
 (defvar exwm-workspace--list)
 
+(declare-function exwm-workspace--set-fullscreen "exwm-workspace.el"
+                  (frame &optional no-struts container-only))
+
 ;;;###autoload
 (defun exwm-layout-set-fullscreen (&optional id)
   "Make window ID fullscreen."
@@ -169,9 +172,25 @@
                                           :drawable exwm--container))))
         (setq exwm--floating-frame-position
               (vector (slot-value geometry 'x) (slot-value geometry 'y)))))
-    (exwm-layout--resize-container exwm--id exwm--container 0 0
+    ;; Expand the workspace frame & its container to fill the whole screen.
+    (exwm-workspace--set-fullscreen exwm--frame t 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.
+    ;; 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))
+                                   (exwm-workspace--current-height)
+                                   t)
     ;; Raise the X window.
     (xcb:+request exwm--connection
         (make-instance 'xcb:ConfigureWindow
@@ -193,6 +212,8 @@
   (with-current-buffer (if id (exwm--id->buffer id) (window-buffer))
     (unless exwm--fullscreen
       (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
diff --git a/exwm-manage.el b/exwm-manage.el
index 13948902d281..359782229de2 100644
--- a/exwm-manage.el
+++ b/exwm-manage.el
@@ -86,7 +86,7 @@ corresponding buffer.")
 (declare-function exwm--update-title "exwm.el" (id))
 (declare-function exwm--update-hints "exwm.el" (id &optional force))
 (declare-function exwm--update-protocols "exwm.el" (id &optional force))
-(declare-function exwm--update-strut "exwm.el" (id))
+(declare-function exwm--update-struts "exwm.el" (id))
 (declare-function exwm-floating--set-floating "exwm-floating.el" (id))
 (declare-function exwm-floating--unset-floating "exwm-floating.el" (id))
 (declare-function exwm-workspace--set-desktop "exwm-workspace.el" (id))
@@ -133,7 +133,7 @@ corresponding buffer.")
         (exwm--log "No need to manage #x%x" id)
         ;; Update struts.
         (when (memq xcb:Atom:_NET_WM_WINDOW_TYPE_DOCK exwm-window-type)
-          (exwm--update-strut id))
+          (exwm--update-struts id))
         ;; Remove all events
         (xcb:+request exwm--connection
             (make-instance 'xcb:ChangeWindowAttributes
@@ -141,8 +141,9 @@ corresponding buffer.")
                            :event-mask
                            (if (memq xcb:Atom:_NET_WM_WINDOW_TYPE_DOCK
                                      exwm-window-type)
-                               ;; Listen for change of struts property of dock.
-                               xcb:EventMask:PropertyChange
+                               ;; Listen for PropertyChange (struts) and
+                               ;; UnmapNotify/DestroyNotify event of the dock.
+                               exwm--client-event-mask
                              xcb:EventMask:NoEvent)))
         ;; The window needs to be mapped
         (xcb:+request exwm--connection
@@ -247,6 +248,15 @@ corresponding buffer.")
       (with-current-buffer (exwm--id->buffer id)
         (run-hooks 'exwm-manage-finish-hook)))))
 
+(defvar exwm-workspace--id-struts-alist)
+(defvar exwm-workspace--list)
+
+(declare-function exwm-workspace--update-struts "exwm-workspace.el" ())
+(declare-function exwm-workspace--set-fullscreen "exwm-workspace.el"
+                  (frame &optional no-struts container-only))
+(declare-function exwm-workspace--set-workareas "exwm-workspace.el"
+                  (&optional workareas))
+
 (defun exwm-manage--unmanage-window (id &optional withdraw-only)
   "Unmanage window ID.
 
@@ -257,6 +267,14 @@ manager is shutting down."
     (exwm--log "Unmanage #x%x (buffer: %s, widthdraw: %s)"
                id buffer withdraw-only)
     (setq exwm--id-buffer-alist (assq-delete-all id exwm--id-buffer-alist))
+    ;; Update workspaces when a dock is destroyed.
+    (when (assq id exwm-workspace--id-struts-alist)
+      (setq exwm-workspace--id-struts-alist
+            (assq-delete-all id exwm-workspace--id-struts-alist))
+      (exwm-workspace--update-struts)
+      (dolist (f exwm-workspace--list)
+        (exwm-workspace--set-fullscreen f))
+      (exwm-workspace--set-workareas))
     (when (buffer-live-p buffer)
       (with-current-buffer buffer
         ;; Flickering seems unavoidable here if the DestroyWindow request is
@@ -314,6 +332,9 @@ manager is shutting down."
             (xcb:+request exwm--connection
                 (make-instance 'xcb:ReparentWindow
                                :window window :parent exwm--root :x 0 :y 0))))
+        ;; Restore the workspace if this X window is currently fullscreen.
+        (when exwm--fullscreen
+          (exwm-workspace--set-fullscreen exwm--frame))
         ;; Destroy the X window container (and the frame container if any).
         (xcb:+request exwm--connection
             (make-instance 'xcb:DestroyWindow :window exwm--container))
diff --git a/exwm-randr.el b/exwm-randr.el
index f71120a4bb36..9f6be782f9a4 100644
--- a/exwm-randr.el
+++ b/exwm-randr.el
@@ -58,7 +58,8 @@
 (defvar exwm-workspace-number)
 (defvar exwm-workspace--list)
 
-(declare-function exwm-workspace--set-fullscreen "exwm-workspace.el" (frame))
+(declare-function exwm-workspace--set-fullscreen "exwm-workspace.el"
+                  (frame &optional no-struts container-only))
 (declare-function exwm-workspace--set-workareas "exwm-workspace.el"
                   (&optional workareas))
 (declare-function exwm-workspace--set-desktop-geometry "exwm-workspace.el" ())
diff --git a/exwm-workspace.el b/exwm-workspace.el
index 6902151f4246..cfbe02afd258 100644
--- a/exwm-workspace.el
+++ b/exwm-workspace.el
@@ -128,10 +128,30 @@ Value nil means to use the default position which is fixed at bottom, while
   "Reports whether the minibuffer is displayed in its own frame."
   (memq exwm-workspace-minibuffer-position '(top bottom)))
 
-;; FIXME: RandR and multiple docks.
-(defvar exwm-workspace--strut nil "Areas occupied by struts.")
-(defvar exwm-workspace--strut-is-partial nil
-  "Whether the struts are from _NET_WM_STRUT_PARTIAL.")
+(defvar exwm-workspace--id-struts-alist nil "Alist of X window and struts.")
+(defvar exwm-workspace--struts nil "Areas occupied by struts.")
+
+(defun exwm-workspace--update-struts ()
+  "Update `exwm-workspace--struts'."
+  (let ((left 0)
+        (right 0)
+        (top 0)
+        (bottom 0)
+        struts)
+    (dolist (pair exwm-workspace--id-struts-alist)
+      (setq struts (cdr pair))
+      (when struts
+        (when (< left (aref struts 0))
+          (setq left (aref struts 0)))
+        (when (< right (aref struts 1))
+          (setq right (aref struts 1)))
+        (when (< top (aref struts 2))
+          (setq top (aref struts 2)))
+        (when (< bottom (aref struts 3))
+          (setq bottom (aref struts 3)))))
+    (setq exwm-workspace--struts (vector left right top bottom))
+    (when (equal exwm-workspace--struts [0 0 0 0])
+      (setq exwm-workspace--struts nil))))
 
 (defvar exwm-workspace--fullscreen-frame-count 0
   "Count the fullscreen workspace frames.")
@@ -139,8 +159,12 @@ Value nil means to use the default position which is fixed at bottom, while
 (declare-function exwm-layout--resize-container "exwm-layout.el"
                   (id container x y width height &optional container-only))
 
-(defun exwm-workspace--set-fullscreen (frame)
-  "Make frame FRAME fullscreen, with regard to its RandR output if applicable."
+(defun exwm-workspace--set-fullscreen (frame &optional no-struts
+                                             container-only)
+  "Make frame FRAME fullscreen, with regard to its RandR output if applicable.
+
+If NO-STRUTS is non-nil, struts are ignored.  If CONTAINER-ONLY is non-nil, the
+workspace frame and its container is not resized."
   (let ((geometry (or (frame-parameter frame 'exwm-geometry)
                       (xcb:+request-unchecked+reply exwm--connection
                           (make-instance 'xcb:GetGeometry
@@ -153,24 +177,27 @@ Value nil means to use the default position which is fixed at bottom, while
         (workspace (frame-parameter frame 'exwm-workspace))
         x* y* width* height*)
     (with-slots (x y width height) geometry
-      (if exwm-workspace--strut
-          (setq x* (+ x (aref exwm-workspace--strut 0))
-                y* (+ y (aref exwm-workspace--strut 2))
-                width* (- width (aref exwm-workspace--strut 0)
-                          (aref exwm-workspace--strut 1))
-                height* (- height (aref exwm-workspace--strut 2)
-                           (aref exwm-workspace--strut 3)))
+      (if (and exwm-workspace--struts (not no-struts))
+          (setq x* (+ x (aref exwm-workspace--struts 0))
+                y* (+ y (aref exwm-workspace--struts 2))
+                width* (- width (aref exwm-workspace--struts 0)
+                          (aref exwm-workspace--struts 1))
+                height* (- height (aref exwm-workspace--struts 2)
+                           (aref exwm-workspace--struts 3)))
         (setq x* x
               y* y
               width* width
               height* height))
       (when (and (eq frame exwm-workspace--current)
-                 (exwm-workspace--minibuffer-own-frame-p))
+                 (exwm-workspace--minibuffer-own-frame-p)
+                 (not container-only))
         (exwm-workspace--resize-minibuffer-frame width height))
-      (exwm-layout--resize-container id container 0 0 width* height*)
+      (unless container-only
+        (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-workspace--fullscreen-frame-count))
+  (unless container-only
+    (cl-incf exwm-workspace--fullscreen-frame-count)))
 
 ;;;###autoload
 (defun exwm-workspace--resize-minibuffer-frame (&optional width height)
@@ -182,19 +209,19 @@ workspace frame."
   (let ((y (if (eq exwm-workspace-minibuffer-position 'top)
                0
              (- (or height (exwm-workspace--current-height))
-                (if exwm-workspace--strut
-                    (+ (aref exwm-workspace--strut 2)
-                       (aref exwm-workspace--strut 3))
+                (if exwm-workspace--struts
+                    (+ (aref exwm-workspace--struts 2)
+                       (aref exwm-workspace--struts 3))
                   0)
                 (frame-pixel-height exwm-workspace--minibuffer))))
         (container (frame-parameter exwm-workspace--minibuffer
                                     'exwm-container)))
     (unless width
       (setq width (exwm-workspace--current-width)))
-    (when exwm-workspace--strut
+    (when exwm-workspace--struts
       (setq width (- width
-                     (aref exwm-workspace--strut 0)
-                     (aref exwm-workspace--strut 1))))
+                     (aref exwm-workspace--struts 0)
+                     (aref exwm-workspace--struts 1))))
     (xcb:+request exwm--connection
         (make-instance 'xcb:ConfigureWindow
                        :window container
@@ -233,11 +260,22 @@ The optional FORCE option is for internal use only."
       (let* ((frame (elt exwm-workspace--list index))
              (workspace (frame-parameter frame 'exwm-workspace))
              (window (frame-parameter frame 'exwm-selected-window)))
+        (unless (window-live-p window)
+          (setq window (frame-selected-window frame)))
+        ;; Raise the workspace container.
         (xcb:+request exwm--connection
             (make-instance 'xcb:ConfigureWindow
                            :window workspace
                            :value-mask xcb:ConfigWindow:StackMode
                            :stack-mode xcb:StackMode:Above))
+        ;; Raise X windows with struts set if there's no fullscreen X window.
+        (unless (buffer-local-value 'exwm--fullscreen (window-buffer window))
+          (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))))
         (setq exwm-workspace--current frame
               exwm-workspace-current-index index)
         (unless (memq (selected-frame) exwm-workspace--list)
@@ -245,8 +283,7 @@ The optional FORCE option is for internal use only."
           (set-frame-parameter (with-current-buffer (window-buffer)
                                  exwm--frame)
                                'exwm-selected-window (selected-window)))
-        (select-window (or (when (window-live-p window) window)
-                           (frame-selected-window frame)))
+        (select-window window)
         (set-frame-parameter frame 'exwm-selected-window nil)
         ;; Close the (possible) active minibuffer
         (when (active-minibuffer-window)
@@ -556,9 +593,9 @@ The optional FORCE option is for internal use only."
                   y 0)
           (setq value-mask (logior xcb:ConfigWindow:Y xcb:ConfigWindow:Height)
                 y (- (exwm-workspace--current-height)
-                     (if exwm-workspace--strut
-                         (+ (aref exwm-workspace--strut 2)
-                            (aref exwm-workspace--strut 3))
+                     (if exwm-workspace--struts
+                         (+ (aref exwm-workspace--struts 2)
+                            (aref exwm-workspace--struts 3))
                        0)
                      height)))
         (xcb:+request exwm--connection
@@ -731,13 +768,13 @@ The optional FORCE option is for internal use only."
           (setq workareas (vconcat workareas workarea))))))
   ;; Exclude areas occupied by struts.
   ;; FIXME: RandR.
-  (when exwm-workspace--strut
-    (let ((dx (aref exwm-workspace--strut 0))
-          (dy (aref exwm-workspace--strut 2))
-          (dw (- (+ (aref exwm-workspace--strut 0)
-                    (aref exwm-workspace--strut 1))))
-          (dh (- (+ (aref exwm-workspace--strut 2)
-                    (aref exwm-workspace--strut 3)))))
+  (when exwm-workspace--struts
+    (let ((dx (aref exwm-workspace--struts 0))
+          (dy (aref exwm-workspace--struts 2))
+          (dw (- (+ (aref exwm-workspace--struts 0)
+                    (aref exwm-workspace--struts 1))))
+          (dh (- (+ (aref exwm-workspace--struts 2)
+                    (aref exwm-workspace--struts 3)))))
       (dotimes (i exwm-workspace-number)
         (cl-incf (aref workareas (* i 4)) dx)
         (cl-incf (aref workareas (+ (* i 4))) dy)
diff --git a/exwm.el b/exwm.el
index 3d7edcfeac16..59f43136f786 100644
--- a/exwm.el
+++ b/exwm.el
@@ -227,45 +227,49 @@
         (when reply                     ;nil when destroyed
           (setq exwm--protocols (append (slot-value reply 'value) nil)))))))
 
-(defun exwm--update-strut-legacy (id)
+(defun exwm--update-struts-legacy (id)
   "Update _NET_WM_STRUT."
-  (unless exwm-workspace--strut-is-partial
-    (let ((reply (xcb:+request-unchecked+reply exwm--connection
-                     (make-instance 'xcb:ewmh:get-_NET_WM_STRUT
-                                    :window id))))
-      (setq exwm-workspace--strut (when reply (slot-value reply 'value)))
+  (let ((pair (assq id exwm-workspace--id-struts-alist))
+        reply struts)
+    (unless (and pair (< 4 (length (cdr pair))))
+      (setq reply (xcb:+request-unchecked+reply exwm--connection
+                      (make-instance 'xcb:ewmh:get-_NET_WM_STRUT
+                                     :window id)))
+      (when reply
+        (setq struts (slot-value reply 'value))
+        (if pair
+            (setcdr pair struts)
+          (push (cons id struts) exwm-workspace--id-struts-alist))
+        (exwm-workspace--update-struts))
       ;; Update workspaces.
       (dolist (f exwm-workspace--list)
         (exwm-workspace--set-fullscreen f))
-      ;; Resize the minibuffer frame.
-      (when (exwm-workspace--minibuffer-own-frame-p)
-        (exwm-workspace--resize-minibuffer-frame))
       ;; Update _NET_WORKAREA.
       (exwm-workspace--set-workareas))))
 
-(defun exwm--update-strut-partial (id)
+(defun exwm--update-struts-partial (id)
   "Update _NET_WM_STRUT_PARTIAL."
   (let ((reply (xcb:+request-unchecked+reply exwm--connection
                    (make-instance 'xcb:ewmh:get-_NET_WM_STRUT_PARTIAL
-                                  :window id))))
-    (setq exwm-workspace--strut (when reply (slot-value reply 'value)))
-    (if (not exwm-workspace--strut)
-        (setq exwm-workspace--strut-is-partial nil)
-      (setq exwm-workspace--strut (substring exwm-workspace--strut 0 4))
-      (setq exwm-workspace--strut-is-partial t))
+                                  :window id)))
+        struts pair)
+    (when reply
+      (setq struts (slot-value reply 'value)
+            pair (assq id exwm-workspace--id-struts-alist))
+      (if pair
+          (setcdr pair struts)
+        (push (cons id struts) exwm-workspace--id-struts-alist))
+      (exwm-workspace--update-struts))
     ;; Update workspaces.
     (dolist (f exwm-workspace--list)
       (exwm-workspace--set-fullscreen f))
-    ;; Resize the minibuffer frame.
-    (when (exwm-workspace--minibuffer-own-frame-p)
-      (exwm-workspace--resize-minibuffer-frame))
     ;; Update _NET_WORKAREA.
     (exwm-workspace--set-workareas)))
 
-(defun exwm--update-strut (id)
+(defun exwm--update-struts (id)
   "Update _NET_WM_STRUT_PARTIAL or _NET_WM_STRUT."
-  (exwm--update-strut-partial id)
-  (exwm--update-strut-legacy id))
+  (exwm--update-struts-partial id)
+  (exwm--update-struts-legacy id))
 
 (defun exwm--on-PropertyNotify (data _synthetic)
   "Handle PropertyNotify event."
@@ -279,9 +283,9 @@
     (if (not (buffer-live-p buffer))
         ;; Properties of unmanaged X windows.
         (cond ((= atom xcb:Atom:_NET_WM_STRUT)
-               (exwm--update-strut-legacy id))
+               (exwm--update-struts-legacy id))
               ((= atom xcb:Atom:_NET_WM_STRUT_PARTIAL)
-               (exwm--update-strut-partial id)))
+               (exwm--update-struts-partial id)))
       (with-current-buffer buffer
         (cond ((= atom xcb:Atom:_NET_WM_WINDOW_TYPE)
                (exwm--update-window-type id t))