Fix various issues with multi-monitor support
* exwm-workspace.el (exwm-workspace-switch): Do not hide X windows when switching to a workspace on another output; update the timestamp (last switched to) of a workspace frame. (exwm-workspace-move-window): Do not hide an X window when moving it to an active workspace on another output. * exwm-floating.el (exwm-floating--set-floating): * exwm-layout.el (exwm-layout-set-fullscreen): * exwm-manage.el (exwm-manage--manage-window) (exwm-manage--on-ConfigureRequest): * exwm-systemtray.el (exwm-systemtray--refresh) (exwm-systemtray--init): Correct coordinate calculations. * exwm-workspace.el (exwm-workspace--current-width): Removed since no longer used.
This commit is contained in:
parent
b8ce20b4f3
commit
5c5729c0d4
5 changed files with 131 additions and 109 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -272,14 +272,6 @@ NIL if FRAME is not a workspace"
|
|||
:width (x-display-pixel-width)
|
||||
: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."
|
||||
|
@ -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 ()
|
||||
|
|
Loading…
Reference in a new issue