From 7116b01b0c9b7efda105487a17192470c466b9c4 Mon Sep 17 00:00:00 2001 From: Chris Feng Date: Sun, 21 Feb 2016 16:39:34 +0800 Subject: [PATCH] Various fixes for floating X windows * exwm-floating.el (exwm-floating--set-floating): Always create floating X windows on current workspace. * exwm-workspace.el (exwm-workspace-switch): Restore selected floating frames. * exwm-workspace.el (exwm-workspace-move-window): Restore the position of floating X windows. Recreate floating frames when using fixed minibuffer. Restack tiling X windows. --- exwm-floating.el | 16 +------- exwm-workspace.el | 100 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 91 insertions(+), 25 deletions(-) diff --git a/exwm-floating.el b/exwm-floating.el index 1ec54d1..97d673c 100644 --- a/exwm-floating.el +++ b/exwm-floating.el @@ -63,14 +63,7 @@ (let ((window (get-buffer-window (exwm--id->buffer id)))) (when window ;window in non-floating state (set-window-buffer window (other-buffer)))) ;hide it first - (let* ((original-frame - (with-current-buffer (exwm--id->buffer id) - (if (and exwm-transient-for (exwm--id->buffer exwm-transient-for)) - ;; Place a modal in the same workspace with its leading window - (with-current-buffer (exwm--id->buffer exwm-transient-for) - exwm--frame) - ;; Fallback to current workspace - exwm-workspace--current))) + (let* ((original-frame exwm-workspace--current) ;; Create new frame (frame (with-current-buffer (or (get-buffer "*scratch*") @@ -79,7 +72,7 @@ (get-buffer-create "*scratch*")) (get-buffer "*scratch*"))) (make-frame - `((minibuffer . nil) ;use the one on workspace + `((minibuffer . nil) ;use the default minibuffer. (background-color . ,exwm-floating-border-color) (internal-border-width . ,exwm-floating-border-width) (left . 10000) @@ -107,11 +100,6 @@ ;; 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) - (set-frame-parameter original-frame 'exwm--urgency t) - (setq exwm-workspace--switch-history-outdated t))) ;; Fix illegal parameters ;; FIXME: check normal hints restrictions (let* ((display-width (frame-pixel-width original-frame)) diff --git a/exwm-workspace.el b/exwm-workspace.el index 42c0818..99bc605 100644 --- a/exwm-workspace.el +++ b/exwm-workspace.el @@ -186,7 +186,14 @@ The optional FORCE option is for internal use only." :stack-mode xcb:StackMode:Above)) (setq exwm-workspace--current frame exwm-workspace-current-index index) - (select-window (frame-selected-window frame)) + (unless (memq (selected-frame) exwm-workspace--list) + ;; Save the floating frame window selected on the previous workspace. + (set-frame-parameter (with-current-buffer (window-buffer) + exwm--frame) + 'exwm-selected-window (selected-window))) + (select-window (or (frame-parameter frame 'exwm-selected-window) + (frame-selected-window frame))) + (set-frame-parameter frame 'exwm-selected-window nil) ;; Close the (possible) active minibuffer (when (active-minibuffer-window) (run-with-idle-timer 0 nil (lambda () (abort-recursive-edit)))) @@ -221,7 +228,11 @@ The optional FORCE option is for internal use only." (xcb:flush exwm--connection)) (run-hooks 'exwm-workspace-switch-hook)))) +(defvar exwm-floating-border-width) +(defvar exwm-floating-border-color) + (declare-function exwm-layout--hide "exwm-layout.el" (id)) +(declare-function exwm-layout--refresh "exwm-layout.el") ;;;###autoload (defun exwm-workspace-move-window (index &optional id) @@ -253,14 +264,72 @@ The optional FORCE option is for internal use only." (setq exwm--frame frame) (if exwm--floating-frame ;; Move the floating container. - (progn + (with-slots (x y) + (xcb:+request-unchecked+reply exwm--connection + (make-instance 'xcb:GetGeometry :drawable exwm--container)) (xcb:+request exwm--connection (make-instance 'xcb:ReparentWindow :window exwm--container :parent (frame-parameter frame 'exwm-workspace) - :x 0 :y 0)) - (xcb:flush exwm--connection)) + :x x :y y)) + (xcb:flush exwm--connection) + (unless exwm-workspace-minibuffer-position + ;; The frame needs to be recreated since it won't use the + ;; minibuffer on the new workspace. + (let* ((old-frame exwm--floating-frame) + (new-frame + (with-current-buffer + (or (get-buffer "*scratch*") + (progn + (set-buffer-major-mode + (get-buffer-create "*scratch*")) + (get-buffer "*scratch*"))) + (make-frame + `((minibuffer . ,(minibuffer-window frame)) + (background-color . ,exwm-floating-border-color) + (internal-border-width + . ,exwm-floating-border-width) + (left . 10000) + (top . 10000) + (width . ,window-min-width) + (height . ,window-min-height) + (unsplittable . t))))) + (outer-id (string-to-number + (frame-parameter new-frame + 'outer-window-id))) + (frame-container (frame-parameter old-frame + 'exwm-container)) + (window (frame-root-window new-frame))) + (set-frame-parameter new-frame 'exwm-outer-id outer-id) + (set-frame-parameter new-frame 'exwm-container + frame-container) + (make-frame-invisible new-frame) + (set-frame-size new-frame + (frame-pixel-width old-frame) + (frame-pixel-height old-frame) + t) + (xcb:+request exwm--connection + (make-instance 'xcb:ReparentWindow + :window outer-id + :parent frame-container + :x 0 :y 0)) + (xcb:flush exwm--connection) + (with-current-buffer (exwm--id->buffer id) + (setq window-size-fixed nil + exwm--frame frame + exwm--floating-frame new-frame) + (set-window-dedicated-p (frame-root-window old-frame) nil) + (remove-hook 'window-configuration-change-hook + #'exwm-layout--refresh) + (set-window-buffer window (current-buffer)) + (add-hook 'window-configuration-change-hook + #'exwm-layout--refresh) + (delete-frame old-frame) + (set-window-dedicated-p window t)) + (make-frame-visible new-frame) + (with-selected-frame new-frame + (exwm-layout--refresh))))) ;; Move the X window container. (if (/= index exwm-workspace-current-index) (bury-buffer) @@ -271,13 +340,22 @@ The optional FORCE option is for internal use only." (get-buffer-create "*scratch*")) (get-buffer "*scratch*"))))) (exwm-layout--hide id) - (xcb:+request exwm--connection - (make-instance 'xcb:ReparentWindow - ;; (current-buffer) is changed. - :window (with-current-buffer (exwm--id->buffer id) - exwm--container) - :parent (frame-parameter frame 'exwm-workspace) - :x 0 :y 0)) + ;; (current-buffer) is changed. + (with-current-buffer (exwm--id->buffer id) + ;; Reparent to the destination workspace. + (xcb:+request exwm--connection + (make-instance 'xcb:ReparentWindow + :window exwm--container + :parent (frame-parameter frame 'exwm-workspace) + :x 0 :y 0)) + ;; Place it just above the destination frame container. + (xcb:+request exwm--connection + (make-instance 'xcb:ConfigureWindow + :window exwm--container + :value-mask (logior xcb:ConfigWindow:Sibling + xcb:ConfigWindow:StackMode) + :sibling (frame-parameter frame 'exwm-container) + :stack-mode xcb:StackMode:Above))) (xcb:flush exwm--connection) (set-window-buffer (frame-selected-window frame) (exwm--id->buffer id)))))