about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--exwm-floating.el74
-rw-r--r--exwm-layout.el9
-rw-r--r--exwm-manage.el26
-rw-r--r--exwm-systemtray.el26
-rw-r--r--exwm-workspace.el105
5 files changed, 131 insertions, 109 deletions
diff --git a/exwm-floating.el b/exwm-floating.el
index 8cd0491beae8..5a2c61e878d1 100644
--- a/exwm-floating.el
+++ b/exwm-floating.el
@@ -129,52 +129,22 @@ This is also used by X window containers.")
          (y (slot-value exwm--geometry 'y))
          (width (slot-value exwm--geometry 'width))
          (height (slot-value exwm--geometry 'height)))
-    (exwm--log "Floating geometry (original, absolute): %dx%d%+d%+d"
-               width height x y)
-    (when (and (/= x 0)
-               (/= y 0))
-      (let ((workarea (elt exwm-workspace--workareas
-                           (exwm-workspace--position original-frame))))
-        (setq x (- x (aref workarea 0))
-              y (- y (aref workarea 1)))))
-    (exwm--log "Floating geometry (original, relative): %dx%d%+d%+d"
-               width height x y)
+    (exwm--log "Floating geometry (original): %dx%d%+d%+d" width height x y)
     ;; Save frame parameters.
     (set-frame-parameter frame 'exwm-outer-id outer-id)
     (set-frame-parameter frame 'exwm-id window-id)
     (set-frame-parameter frame 'exwm-container frame-container)
     ;; Fix illegal parameters
     ;; FIXME: check normal hints restrictions
-    (let* ((display-width (frame-pixel-width original-frame))
-           (display-height (- (frame-pixel-height original-frame)
-                              (if (exwm-workspace--minibuffer-own-frame-p)
-                                  0
-                                (window-pixel-height (minibuffer-window
-                                                      original-frame)))
-                              (* 2 (window-mode-line-height))
-                              (window-header-line-height window)))
-           (display-height (* 2 (/ display-height 2)))) ;round to even
-      (if (> width display-width)
-          ;; Too wide
-          (progn (setq x 0
-                       width display-width))
-        ;; Invalid width
-        (when (= 0 width) (setq width (/ display-width 2)))
-        ;; Make sure at least half of the window is visible
-        (when (or (> (+ x (/ width 2)) display-width) (> 0 (+ x (/ width 2))))
-          (setq x (/ (- display-width width) 2))))
-      (if (> height display-height)
-          ;; Too tall
-          (setq y 0
-                height display-height)
-        ;; Invalid height
-        (when (= 0 height) (setq height (/ display-height 2)))
-        ;; Make sure at least half of the window is visible
-        (when (or (> (+ y (/ height 2)) display-height)
-                  (> 0 (+ y (/ height 2))))
-          (setq y (/ (- display-height height) 2))))
+    (let* ((workarea (elt exwm-workspace--workareas
+                          (exwm-workspace--position original-frame)))
+           (x* (aref workarea 0))
+           (y* (aref workarea 1))
+           (width* (aref workarea 2))
+           (height* (aref workarea 3)))
       ;; Center floating windows
-      (when (and (= x 0) (= y 0))
+      (when (and (or (= x 0) (= x x*))
+                 (or (= y 0) (= y y*)))
         (let ((buffer (exwm--id->buffer exwm-transient-for))
               window edges)
           (when (and buffer (setq window (get-buffer-window buffer)))
@@ -184,11 +154,29 @@ This is also used by X window containers.")
               (setq edges nil)))
           (if edges
               ;; Put at the center of leading window
-              (setq x (/ (- (elt edges 2) (elt edges 0) width) 2)
-                    y (/ (- (elt edges 3) (elt edges 1) height) 2))
+              (setq x (+ x* (/ (- (elt edges 2) (elt edges 0) width) 2))
+                    y (+ y* (/ (- (elt edges 3) (elt edges 1) height) 2)))
             ;; Put at the center of screen
-            (setq x (/ (- display-width width) 2)
-                  y (/ (- display-height height) 2))))))
+            (setq x (/ (- width* width) 2)
+                  y (/ (- height* height) 2)))))
+      (if (> width width*)
+          ;; Too wide
+          (progn (setq x x*
+                       width width*))
+        ;; Invalid width
+        (when (= 0 width) (setq width (/ width* 2)))
+        ;; Make sure at least half of the window is visible
+        (unless (< x* (+ x (/ width 2)) (+ x* width*))
+          (setq x (+ x* (/ (- width* width) 2)))))
+      (if (> height height*)
+          ;; Too tall
+          (setq y y*
+                height height*)
+        ;; Invalid height
+        (when (= 0 height) (setq height (/ height* 2)))
+        ;; Make sure at least half of the window is visible
+        (unless (< y* (+ y (/ height 2)) (+ y* height*))
+          (setq y (+ y* (/ (- height* height) 2))))))
     (exwm--set-geometry id x y nil nil)
     (xcb:flush exwm--connection)
     (exwm--log "Floating geometry (corrected): %dx%d%+d%+d" width height x y)
diff --git a/exwm-layout.el b/exwm-layout.el
index 3f624ad7fe4d..5a01f900323d 100644
--- a/exwm-layout.el
+++ b/exwm-layout.el
@@ -49,8 +49,6 @@
 (declare-function exwm-input-release-keyboard "exwm-input.el")
 (declare-function exwm-workspace--client-p "exwm-workspace.el"
                   (&optional frame))
-(declare-function exwm-workspace--current-height "exwm-workspace.el")
-(declare-function exwm-workspace--current-width  "exwm-workspace.el")
 (declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el")
 (declare-function exwm-workspace--workspace-p "exwm-workspace.el"
                   (workspace))
@@ -137,11 +135,8 @@
     (cl-return-from 'exwm-layout-set-fullscreen))
   (with-current-buffer (if id (exwm--id->buffer id) (window-buffer))
     ;; 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--set-geometry exwm--id 0 0
-                        (exwm-workspace--current-width)
-                        (exwm-workspace--current-height))
+    (with-slots (x y width height) (exwm-workspace--get-geometry exwm--frame)
+      (exwm--set-geometry exwm--id x y width height))
     ;; Raise the X window.
     (xcb:+request exwm--connection
         (make-instance 'xcb:ConfigureWindow
diff --git a/exwm-manage.el b/exwm-manage.el
index 790b6f147904..dd7c2e3953c9 100644
--- a/exwm-manage.el
+++ b/exwm-manage.el
@@ -65,6 +65,7 @@ You can still make the X windows floating afterwards."
 (defvar exwm-workspace--id-struts-alist)
 (defvar exwm-workspace--list)
 (defvar exwm-workspace--switch-history-outdated)
+(defvar exwm-workspace--workareas)
 (defvar exwm-workspace-current-index)
 (declare-function exwm--update-class "exwm.el" (id &optional force))
 (declare-function exwm--update-hints "exwm.el" (id &optional force))
@@ -80,8 +81,7 @@ You can still make the X windows floating afterwards."
 (declare-function exwm-input-grab-keyboard "exwm-input.el")
 (declare-function exwm-layout--iconic-state-p "exwm-layout.el" (&optional id))
 (declare-function exwm-workspace--count "exwm-workspace.el" ())
-(declare-function exwm-workspace--current-height "exwm-workspace.el")
-(declare-function exwm-workspace--current-width  "exwm-workspace.el")
+(declare-function exwm-workspace--position "exwm-workspace.el" (frame))
 (declare-function exwm-workspace--set-desktop "exwm-workspace.el" (id))
 (declare-function exwm-workspace--set-fullscreen "exwm-workspace.el" (frame))
 (declare-function exwm-workspace--update-struts "exwm-workspace.el" ())
@@ -204,11 +204,17 @@ You can still make the X windows floating afterwards."
         (with-slots (x y width height) exwm--geometry
           ;; Center window of type _NET_WM_WINDOW_TYPE_SPLASH
           (when (memq xcb:Atom:_NET_WM_WINDOW_TYPE_SPLASH exwm-window-type)
-            (exwm--set-geometry id
-                                (/ (- (exwm-workspace--current-width) width) 2)
-                                (/ (- (exwm-workspace--current-height) height)
-                                   2)
-                                nil nil)))
+            (let* ((workarea (elt exwm-workspace--workareas
+                                  (exwm-workspace--position exwm--frame)))
+                   (x* (aref workarea 0))
+                   (y* (aref workarea 1))
+                   (width* (aref workarea 2))
+                   (height* (aref workarea 3)))
+              (exwm--set-geometry id
+                                  (+ x* (/ (- width* width) 2))
+                                  (+ y* (/ (- height* height) 2))
+                                  nil
+                                  nil))))
         ;; Check for desktop.
         (when (memq xcb:Atom:_NET_WM_WINDOW_TYPE_DESKTOP exwm-window-type)
           ;; There should be only one desktop X window.
@@ -501,9 +507,9 @@ border-width: %d; sibling: #x%x; stack-mode: %d"
           (with-current-buffer buffer
             (setq edges
                   (if (memq xcb:Atom:_NET_WM_STATE_FULLSCREEN exwm--ewmh-state)
-                      (list 0 0
-                            (exwm-workspace--current-width)
-                            (exwm-workspace--current-height))
+                      (with-slots (x y width height)
+                          (exwm-workspace--get-geometry exwm--frame)
+                        (list x y width height))
                     (window-inside-absolute-pixel-edges
                      (get-buffer-window buffer t))))
             (exwm--log "Reply with ConfigureNotify (edges): %s" edges)
diff --git a/exwm-systemtray.el b/exwm-systemtray.el
index 5377ef8ed617..d932032e5905 100644
--- a/exwm-systemtray.el
+++ b/exwm-systemtray.el
@@ -82,8 +82,6 @@ You shall use the default value if using auto-hide minibuffer."
 (defvar exwm-workspace--workareas)
 (defvar exwm-workspace-current-index)
 (defvar xcb:Atom:_NET_SYSTEM_TRAY_S0)
-(declare-function exwm-workspace--current-height "exwm-workspace.el")
-(declare-function exwm-workspace--current-width  "exwm-workspace.el")
 (declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el")
 
 (defun exwm-systemtray--embed (icon)
@@ -205,13 +203,15 @@ You shall use the default value if using auto-hide minibuffer."
         (setq x (+ x (slot-value (cdr pair) 'width)
                    exwm-systemtray-icon-gap))
         (setq map t)))
-    (xcb:+request exwm-systemtray--connection
-        (make-instance 'xcb:ConfigureWindow
-                       :window exwm-systemtray--embedder
-                       :value-mask (logior xcb:ConfigWindow:X
-                                           xcb:ConfigWindow:Width)
-                       :x (- (exwm-workspace--current-width) x)
-                       :width x))
+    (let ((workarea (elt exwm-workspace--workareas
+                         exwm-workspace-current-index)))
+      (xcb:+request exwm-systemtray--connection
+          (make-instance 'xcb:ConfigureWindow
+                         :window exwm-systemtray--embedder
+                         :value-mask (logior xcb:ConfigWindow:X
+                                             xcb:ConfigWindow:Width)
+                         :x (- (aref workarea 2) x)
+                         :width x)))
     (when map
       (xcb:+request exwm-systemtray--connection
           (make-instance 'xcb:MapWindow :window exwm-systemtray--embedder))))
@@ -434,9 +434,11 @@ You shall use the default value if using auto-hide minibuffer."
                     (- (line-pixel-height) exwm-systemtray-height)
                   ;; Vertically centered.
                   (/ (- (line-pixel-height) exwm-systemtray-height) 2)))
-      (setq frame exwm-workspace--current
-            ;; Bottom aligned.
-            y (- (exwm-workspace--current-height) exwm-systemtray-height)))
+      (let ((workarea (elt exwm-workspace--workareas
+                           exwm-workspace-current-index)))
+        (setq frame exwm-workspace--current
+              ;; Bottom aligned.
+              y (- (aref workarea 3) exwm-systemtray-height))))
     (setq parent (string-to-number (frame-parameter frame 'window-id))
           depth (slot-value (xcb:+request-unchecked+reply
                                 exwm-systemtray--connection
diff --git a/exwm-workspace.el b/exwm-workspace.el
index e2dfa232f8b6..9b0bfeb3387d 100644
--- a/exwm-workspace.el
+++ b/exwm-workspace.el
@@ -273,14 +273,6 @@ NIL if FRAME is not a workspace"
                      :height (x-display-pixel-height))))
 
 ;;;###autoload
-(defun exwm-workspace--current-width ()
-  "Return the width of current workspace."
-  (let ((geometry (frame-parameter exwm-workspace--current 'exwm-geometry)))
-    (if geometry
-        (slot-value geometry 'width)
-      (x-display-pixel-width))))
-
-;;;###autoload
 (defun exwm-workspace--current-height ()
   "Return the height of current workspace."
   (let ((geometry (frame-parameter exwm-workspace--current 'exwm-geometry)))
@@ -536,14 +528,23 @@ for internal use only."
         ;; Set a default minibuffer frame.
         (setq default-minibuffer-frame frame))
       ;; Show/Hide X windows.
-      (dolist (i exwm--id-buffer-alist)
-        (with-current-buffer (cdr i)
-          (if (eq old-frame exwm--frame)
-              (exwm-layout--hide exwm--id)
-            (when (eq frame exwm--frame)
-              (let ((window (get-buffer-window nil t)))
-                (when window
-                  (exwm-layout--show exwm--id window)))))))
+      (let ((hide-x-windows-on-old-frame
+             (with-slots ((x1 x)
+                          (y1 y))
+                 (exwm-workspace--get-geometry frame)
+               (with-slots ((x2 x)
+                            (y2 y))
+                   (exwm-workspace--get-geometry old-frame)
+                 (and (= x1 x2) (= y1 y2))))))
+        (dolist (i exwm--id-buffer-alist)
+          (with-current-buffer (cdr i)
+            (if (eq old-frame exwm--frame)
+                (when hide-x-windows-on-old-frame
+                  (exwm-layout--hide exwm--id))
+              (when (eq frame exwm--frame)
+                (let ((window (get-buffer-window nil t)))
+                  (when window
+                    (exwm-layout--show exwm--id window))))))))
       ;; Hide windows in other workspaces by preprending a space
       (unless exwm-workspace-show-all-buffers
         (dolist (i exwm--id-buffer-alist)
@@ -553,6 +554,8 @@ for internal use only."
               (exwm-workspace-rename-buffer (if (eq frame exwm--frame)
                                                 name
                                               (concat " " name)))))))
+      ;; Update frame's timestamp.
+      (set-frame-parameter frame 'exwm-timestamp (float-time))
       ;; Update demands attention flag
       (set-frame-parameter frame 'exwm-urgency nil)
       ;; Update switch workspace history
@@ -700,7 +703,7 @@ INDEX must not exceed the current number of workspaces."
                       (exwm-workspace--prompt-delete-allowed t))
                   (exwm-workspace--prompt-for-workspace "Move to [+/-]: "))))
   (let ((frame (exwm-workspace--workspace-from-frame-or-index frame-or-index))
-        old-frame container)
+        x-old y-old x-new y-new should-hide old-frame container)
     (unless id (setq id (exwm--buffer->id (window-buffer))))
     (with-current-buffer (exwm--id->buffer id)
       (unless (eq exwm--frame frame)
@@ -712,6 +715,36 @@ INDEX must not exceed the current number of workspaces."
                (concat " " name)))))
         (setq old-frame exwm--frame
               exwm--frame frame)
+        ;; Save the positions of new & old frames.
+        (with-slots ((x1 x)
+                     (y1 y))
+            (exwm-workspace--get-geometry old-frame)
+          (with-slots ((x2 x)
+                       (y2 y))
+              (exwm-workspace--get-geometry frame)
+            (setq x-old x1
+                  y-old y1
+                  x-new x2
+                  y-new y2)))
+        (if (and (= x-old x-new)
+                 (= y-old y-new))
+            ;; Switch to a workspace on the same output.
+            (setq should-hide t)
+          ;; Check if this frame has the largest timestamp of that output.
+          (let ((timestamp (frame-parameter frame 'exwm-timestamp))
+                (timestamp-active
+                 (apply #'max
+                        (mapcar (lambda (w)
+                                  (with-slots (x y)
+                                      (exwm-workspace--get-geometry w)
+                                    (if (and (= x x-new)
+                                             (= y y-new))
+                                        (frame-parameter w 'exwm-timestamp)
+                                      -1)))
+                                exwm-workspace--list))))
+            (when (< timestamp timestamp-active)
+              ;; Switch to a workspace not active on another output.
+              (setq should-hide t))))
         (if (not exwm--floating-frame)
             ;; Tiling.
             (progn
@@ -724,31 +757,27 @@ INDEX must not exceed the current number of workspaces."
                                  (exwm--id->buffer id))
               (if (eq frame exwm-workspace--current)
                   (select-window (frame-selected-window frame))
-                (exwm-layout--hide id)))
+                (when should-hide
+                  (exwm-layout--hide id))))
           ;; Floating.
           (setq container (frame-parameter exwm--floating-frame
                                            'exwm-container))
-          (with-slots ((x1 x)
-                       (y1 y))
-              (exwm-workspace--get-geometry old-frame)
-            (with-slots ((x2 x)
-                         (y2 y))
-                (exwm-workspace--get-geometry frame)
-              (unless (and (= x1 x2)
-                           (= y1 y2))
-                (with-slots (x y)
-                    (xcb:+request-unchecked+reply exwm--connection
-                        (make-instance 'xcb:GetGeometry
-                                       :drawable container))
-                  (setq x (+ x (- x2 x1))
-                        y (+ y (- y2 y1)))
-                  (exwm--set-geometry id x y nil nil)
-                  (exwm--set-geometry container x y nil nil)))))
+          (unless (and (= x-old x-new)
+                       (= y-old y-new))
+            (with-slots (x y)
+                (xcb:+request-unchecked+reply exwm--connection
+                    (make-instance 'xcb:GetGeometry
+                                   :drawable container))
+              (setq x (+ x (- x-new x-old))
+                    y (+ y (- y-new y-old)))
+              (exwm--set-geometry id x y nil nil)
+              (exwm--set-geometry container x y nil nil)))
           (if (exwm-workspace--minibuffer-own-frame-p)
               (if (eq frame exwm-workspace--current)
                   (select-window (frame-root-window exwm--floating-frame))
                 (select-window (frame-selected-window exwm-workspace--current))
-                (exwm-layout--hide id))
+                (when should-hide
+                  (exwm-layout--hide id)))
             ;; The frame needs to be recreated since it won't use the
             ;; minibuffer on the new workspace.
             ;; The code is mostly copied from `exwm-floating--set-floating'.
@@ -808,7 +837,8 @@ INDEX must not exceed the current number of workspaces."
               (if (eq frame exwm-workspace--current)
                   (with-current-buffer (exwm--id->buffer id)
                     (select-window (frame-root-window exwm--floating-frame)))
-                (exwm-layout--hide id))))
+                (when should-hide
+                  (exwm-layout--hide id)))))
           ;; Update the 'exwm-selected-window' frame parameter.
           (when (not (eq frame exwm-workspace--current))
             (with-current-buffer (exwm--id->buffer id)
@@ -1486,7 +1516,8 @@ applied to all subsequently created X frames."
   ;; Prevent frame parameters introduced by this module from being
   ;; saved/restored.
   (dolist (i '(exwm-outer-id exwm-id exwm-container exwm-geometry
-                             fullscreen exwm-selected-window exwm-urgency))
+                             exwm-selected-window exwm-timestamp exwm-urgency
+                             fullscreen))
     (push (cons i :never) frameset-filter-alist)))
 
 (defun exwm-workspace--exit ()