diff --git a/exwm-core.el b/exwm-core.el index 9f869fe..70a759c 100644 --- a/exwm-core.el +++ b/exwm-core.el @@ -126,7 +126,7 @@ (declare-function exwm-layout-set-fullscreen "exwm-layout.el" (&optional id)) (declare-function exwm-layout-toggle-mode-line "exwm-layout.el") (declare-function exwm-workspace-move-window "exwm-workspace.el" - (index &optional id)) + (frame-or-index &optional id)) (defvar exwm-mode-map (let ((map (make-sparse-keymap))) diff --git a/exwm-input.el b/exwm-input.el index 22c7a36..b9e4705 100644 --- a/exwm-input.el +++ b/exwm-input.el @@ -104,7 +104,7 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.") (declare-function exwm-layout--set-state "exwm-layout.el" (id state)) (declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el") (declare-function exwm-workspace-switch "exwm-workspace.el" - (index &optional force)) + (frame-or-index &optional force)) (defun exwm-input--update-focus () "Update input focus." @@ -120,7 +120,7 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.") (setq exwm-workspace--switch-history-outdated t) (force-mode-line-update) ;; The application may have changed its input focus - (exwm-workspace-switch exwm-workspace-current-index t)) + (exwm-workspace-switch exwm-workspace--current t)) (exwm--log "Set focus on #x%x" exwm--id) (exwm-input--set-focus exwm--id) (when exwm--floating-frame @@ -209,15 +209,13 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.") (unless (eq frame exwm-workspace--current) (if (exwm-workspace--workspace-p frame) ;; The X window is on another workspace - (exwm-workspace-switch - (exwm-workspace--position frame)) + (exwm-workspace-switch frame) (with-current-buffer (window-buffer window) (when (and (eq major-mode 'exwm-mode) (not (eq exwm--frame exwm-workspace--current))) ;; The floating X window is on another workspace - (exwm-workspace-switch - (exwm-workspace--position exwm--frame)))))) + (exwm-workspace-switch exwm--frame))))) ;; It has been reported that the `window' may have be deleted (if (window-live-p window) (select-window window) diff --git a/exwm-layout.el b/exwm-layout.el index 4d85390..e3d1d74 100644 --- a/exwm-layout.el +++ b/exwm-layout.el @@ -160,10 +160,9 @@ (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--position "exwm-workspace.el" (frame)) (declare-function exwm-workspace--set-fullscreen "exwm-workspace.el" (frame)) (declare-function exwm-workspace-move-window "exwm-workspace.el" - (index &optional id)) + (frame-or-index &optional id)) ;;;###autoload (defun exwm-layout-set-fullscreen (&optional id) @@ -347,8 +346,7 @@ selected by `other-buffer'." (let ((window (car windows))) (if (eq frame exwm--frame) (exwm-layout--show exwm--id window) - (exwm-workspace-move-window - (exwm-workspace--position frame) exwm--id)) + (exwm-workspace-move-window frame exwm--id)) ;; Make sure this buffer is not displayed elsewhere. Note down ;; windows displaying an EXWM-buffer now displayed elsewhere; we ;; need to display with some other buffer there. diff --git a/exwm-manage.el b/exwm-manage.el index 01d00b1..d67929a 100644 --- a/exwm-manage.el +++ b/exwm-manage.el @@ -94,7 +94,7 @@ corresponding buffer.") (declare-function exwm-workspace--current-width "exwm-workspace.el") (declare-function exwm-workspace--set-desktop "exwm-workspace.el" (id)) (declare-function exwm-workspace-move-window "exwm-workspace.el" - (index &optional id)) + (frame-or-index &optional id)) (defun exwm-manage--manage-window (id) "Manage window ID." diff --git a/exwm-workspace.el b/exwm-workspace.el index 4d8380d..346e898 100644 --- a/exwm-workspace.el +++ b/exwm-workspace.el @@ -46,6 +46,19 @@ NIL if FRAME is not a workspace" "Return t if FRAME is a workspace." (memq frame exwm-workspace--list)) +(defun exwm-workspace--workspace-from-frame-or-index (frame-or-index) + "Retrieve the workspace frame from FRAME-OR-INDEX." + (cond + ((framep frame-or-index) + (unless (exwm-workspace--position frame-or-index) + (user-error "[EXWM] Frame is not a workspace %S" frame-or-index)) + frame-or-index) + ((integerp frame-or-index) + (unless (and (<= 0 frame-or-index) (< frame-or-index (exwm-workspace--count))) + (user-error "[EXWM] Workspace index out of range: %d" frame-or-index)) + (elt exwm-workspace--list frame-or-index)) + (t (user-error "[EXWM] Invalid workspace: %s" frame-or-index)))) + (defvar exwm-workspace--switch-map (let ((map (make-sparse-keymap))) (define-key map [t] (lambda () (interactive))) @@ -297,87 +310,85 @@ Value nil means to use the default position which is fixed at bottom, while "Normal hook run after switching workspace.") ;;;###autoload -(defun exwm-workspace-switch (index &optional force) - "Switch to workspace INDEX. Query for INDEX if it's not specified. +(defun exwm-workspace-switch (frame-or-index &optional force) + "Switch to workspace INDEX. Query for FRAME-OR-INDEX if it's not specified. The optional FORCE option is for internal use only." (interactive (list (unless (and (eq major-mode 'exwm-mode) exwm--fullscreen) ;it's invisible (exwm-workspace--update-switch-history) - (let* ((history-add-new-input nil) ;prevent modifying history - (idx (read-from-minibuffer - "Workspace: " (elt exwm-workspace--switch-history - exwm-workspace-current-index) - exwm-workspace--switch-map nil - `(exwm-workspace--switch-history - . ,(1+ exwm-workspace-current-index))))) - (cl-position idx exwm-workspace--switch-history :test #'equal))))) - (when index - (unless (and (<= 0 index) (< index (exwm-workspace--count))) - (user-error "[EXWM] Workspace index out of range: %d" index)) - (when (or force (/= exwm-workspace-current-index index)) - (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 (exwm-workspace--workspace-p (selected-frame)) - ;; 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 window) - (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)))) - (if (not (exwm-workspace--minibuffer-own-frame-p)) - (setq default-minibuffer-frame frame) - ;; Resize/reposition the minibuffer frame + (let* ((current-idx (exwm-workspace--position exwm-workspace--current)) + (history-add-new-input nil) ;prevent modifying history + (history-idx (read-from-minibuffer + "Workspace: " (elt exwm-workspace--switch-history current-idx) + exwm-workspace--switch-map nil + `(exwm-workspace--switch-history . ,(1+ current-idx)))) + (workspace-idx (cl-position history-idx exwm-workspace--switch-history :test #'equal))) + (elt exwm-workspace--list workspace-idx))))) + (let* ((frame (exwm-workspace--workspace-from-frame-or-index frame-or-index)) + (index (exwm-workspace--position frame)) + (workspace (frame-parameter frame 'exwm-workspace)) + (window (frame-parameter frame 'exwm-selected-window))) + (when (or force (not (eq frame exwm-workspace--current))) + (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:ReparentWindow - :window - (frame-parameter exwm-workspace--minibuffer - 'exwm-container) - :parent (frame-parameter frame 'exwm-workspace) - :x 0 :y 0)) - (exwm-workspace--resize-minibuffer-frame)) - ;; Hide windows in other workspaces by preprending a space - (unless exwm-workspace-show-all-buffers - (dolist (i exwm--id-buffer-alist) - (with-current-buffer (cdr i) - (let ((name (replace-regexp-in-string "^\\s-*" "" - (buffer-name)))) - (exwm-workspace-rename-buffer (if (eq frame exwm--frame) - name - (concat " " name))))))) - ;; Update demands attention flag - (set-frame-parameter frame 'exwm--urgency nil) - ;; Update switch workspace history - (setq exwm-workspace--switch-history-outdated t) - ;; Set _NET_CURRENT_DESKTOP. + (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 (exwm-workspace--workspace-p (selected-frame)) + ;; 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 window) + (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)))) + (if (not (exwm-workspace--minibuffer-own-frame-p)) + (setq default-minibuffer-frame frame) + ;; Resize/reposition the minibuffer frame (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_CURRENT_DESKTOP - :window exwm--root :data index)) - (xcb:flush exwm--connection)) - (run-hooks 'exwm-workspace-switch-hook)))) + (make-instance 'xcb:ReparentWindow + :window + (frame-parameter exwm-workspace--minibuffer + 'exwm-container) + :parent (frame-parameter frame 'exwm-workspace) + :x 0 :y 0)) + (exwm-workspace--resize-minibuffer-frame)) + ;; Hide windows in other workspaces by preprending a space + (unless exwm-workspace-show-all-buffers + (dolist (i exwm--id-buffer-alist) + (with-current-buffer (cdr i) + (let ((name (replace-regexp-in-string "^\\s-*" "" + (buffer-name)))) + (exwm-workspace-rename-buffer (if (eq frame exwm--frame) + name + (concat " " name))))))) + ;; Update demands attention flag + (set-frame-parameter frame 'exwm--urgency nil) + ;; Update switch workspace history + (setq exwm-workspace--switch-history-outdated t) + ;; Set _NET_CURRENT_DESKTOP + (xcb:+request exwm--connection + (make-instance 'xcb:ewmh:set-_NET_CURRENT_DESKTOP + :window exwm--root :data index)) + (xcb:flush exwm--connection)) + (run-hooks 'exwm-workspace-switch-hook))) (defun exwm-workspace--on-focus-in () "Handle unexpected frame switch." @@ -406,30 +417,28 @@ The optional FORCE option is for internal use only." (declare-function exwm-layout--other-buffer-predicate "exwm-layout.el" (buffer)) ;;;###autoload -(defun exwm-workspace-move-window (index &optional id) - "Move window ID to workspace INDEX." +(defun exwm-workspace-move-window (frame-or-index &optional id) + "Move window ID to workspace FRAME-OR-INDEX." (interactive (list (progn (exwm-workspace--update-switch-history) - (let* ((history-add-new-input nil) ;prevent modifying history - (idx (read-from-minibuffer - "Workspace: " (elt exwm-workspace--switch-history - exwm-workspace-current-index) - exwm-workspace--switch-map nil - `(exwm-workspace--switch-history - . ,(1+ exwm-workspace-current-index))))) - (cl-position idx exwm-workspace--switch-history :test #'equal))))) - (unless id (setq id (exwm--buffer->id (window-buffer)))) - (unless (and (<= 0 index) (< index (exwm-workspace--count))) - (user-error "[EXWM] Workspace index out of range: %d" index)) - (with-current-buffer (exwm--id->buffer id) - (let ((frame (elt exwm-workspace--list index))) + (let* ((current-idx (exwm-workspace--position exwm-workspace--current)) + (history-add-new-input nil) ;prevent modifying history + (history-idx (read-from-minibuffer + "Workspace: " (elt exwm-workspace--switch-history current-idx) + exwm-workspace--switch-map nil + `(exwm-workspace--switch-history . ,(1+ current-idx)))) + (workspace-idx (cl-position history-idx exwm-workspace--switch-history :test #'equal))) + (elt exwm-workspace--list workspace-idx))))) + (let ((frame (exwm-workspace--workspace-from-frame-or-index frame-or-index))) + (unless id (setq id (exwm--buffer->id (window-buffer)))) + (with-current-buffer (exwm--id->buffer id) (unless (eq exwm--frame frame) (unless exwm-workspace-show-all-buffers (let ((name (replace-regexp-in-string "^\\s-*" "" (buffer-name)))) (exwm-workspace-rename-buffer - (if (= index exwm-workspace-current-index) + (if (eq frame exwm-workspace--current) name (concat " " name))))) (setq exwm--frame frame) @@ -446,7 +455,7 @@ The optional FORCE option is for internal use only." :x x :y y)) (xcb:flush exwm--connection) (if (exwm-workspace--minibuffer-own-frame-p) - (when (= index exwm-workspace-current-index) + (when (eq frame exwm-workspace--current) (select-frame-set-input-focus exwm--floating-frame) (exwm-layout--refresh)) ;; The frame needs to be recreated since it won't use the @@ -502,18 +511,18 @@ The optional FORCE option is for internal use only." (delete-frame old-frame) (set-window-dedicated-p window t) (exwm-layout--show id window)) - (if (/= index exwm-workspace-current-index) + (if (not (eq frame exwm-workspace--current)) (make-frame-visible new-frame) (select-frame-set-input-focus new-frame) (redisplay)))) ;; Update the 'exwm-selected-window' frame parameter. - (when (/= index exwm-workspace-current-index) + (when (not (eq frame exwm-workspace--current)) (with-current-buffer (exwm--id->buffer id) (set-frame-parameter frame 'exwm-selected-window (frame-root-window exwm--floating-frame))))) ;; Move the X window container. - (if (= index exwm-workspace-current-index) + (if (eq frame exwm-workspace--current) (set-window-buffer (get-buffer-window (current-buffer) t) (other-buffer)) (bury-buffer) @@ -577,7 +586,7 @@ The optional FORCE option is for internal use only." (select-frame-set-input-focus exwm--floating-frame) (select-window (frame-root-window exwm--floating-frame))) ;; On another workspace. - (exwm-workspace-move-window exwm-workspace-current-index + (exwm-workspace-move-window exwm-workspace--current exwm--id)) ;; Ordinary buffer. (switch-to-buffer buffer-or-name))))) diff --git a/exwm.el b/exwm.el index 4a6e9fd..9151fdc 100644 --- a/exwm.el +++ b/exwm.el @@ -438,10 +438,9 @@ ;; FIXME: check (may require other properties set) (when (memq xcb:Atom:_NET_WM_STATE_DEMANDS_ATTENTION props) (when (= action xcb:ewmh:_NET_WM_STATE_ADD) - (let ((idx (exwm-workspace--position exwm--frame))) - (unless (= idx exwm-workspace-current-index) - (set-frame-parameter exwm--frame 'exwm--urgency t) - (setq exwm-workspace--switch-history-outdated t)))) + (unless (eq exwm--frame exwm-workspace--current) + (set-frame-parameter exwm--frame 'exwm--urgency t) + (setq exwm-workspace--switch-history-outdated t))) ;; xcb:ewmh:_NET_WM_STATE_REMOVE? ;; xcb:ewmh:_NET_WM_STATE_TOGGLE? )