Work with workspace frames instead of indices

* exwm.el (exwm--on-ClientMessage):
	* exwm-workspace.el (exwm-workspace-switch)
	(exwm-workspace-move-window, exwm-workspace-switch-to-buffer):
	* exwm-layout.el (exwm-layout--refresh):
	* exwm-input.el (exwm-input--update-focus)
	(exwm-input--on-ButtonPress): Accept frame as well as workspace
	index as argument.
	* exwm-workspace.el
	(exwm-workspace--workspace-from-frame-or-index): New function.
This commit is contained in:
Adrián Medraño Calvo 2016-07-17 12:00:00 +00:00
parent 35e1655dc5
commit 07120a0562
6 changed files with 114 additions and 110 deletions

View file

@ -126,7 +126,7 @@
(declare-function exwm-layout-set-fullscreen "exwm-layout.el" (&optional id)) (declare-function exwm-layout-set-fullscreen "exwm-layout.el" (&optional id))
(declare-function exwm-layout-toggle-mode-line "exwm-layout.el") (declare-function exwm-layout-toggle-mode-line "exwm-layout.el")
(declare-function exwm-workspace-move-window "exwm-workspace.el" (declare-function exwm-workspace-move-window "exwm-workspace.el"
(index &optional id)) (frame-or-index &optional id))
(defvar exwm-mode-map (defvar exwm-mode-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))

View file

@ -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-layout--set-state "exwm-layout.el" (id state))
(declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el") (declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el")
(declare-function exwm-workspace-switch "exwm-workspace.el" (declare-function exwm-workspace-switch "exwm-workspace.el"
(index &optional force)) (frame-or-index &optional force))
(defun exwm-input--update-focus () (defun exwm-input--update-focus ()
"Update input 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) (setq exwm-workspace--switch-history-outdated t)
(force-mode-line-update) (force-mode-line-update)
;; The application may have changed its input focus ;; 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--log "Set focus on #x%x" exwm--id)
(exwm-input--set-focus exwm--id) (exwm-input--set-focus exwm--id)
(when exwm--floating-frame (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) (unless (eq frame exwm-workspace--current)
(if (exwm-workspace--workspace-p frame) (if (exwm-workspace--workspace-p frame)
;; The X window is on another workspace ;; The X window is on another workspace
(exwm-workspace-switch (exwm-workspace-switch frame)
(exwm-workspace--position frame))
(with-current-buffer (window-buffer window) (with-current-buffer (window-buffer window)
(when (and (eq major-mode 'exwm-mode) (when (and (eq major-mode 'exwm-mode)
(not (eq exwm--frame (not (eq exwm--frame
exwm-workspace--current))) exwm-workspace--current)))
;; The floating X window is on another workspace ;; The floating X window is on another workspace
(exwm-workspace-switch (exwm-workspace-switch exwm--frame)))))
(exwm-workspace--position exwm--frame))))))
;; It has been reported that the `window' may have be deleted ;; It has been reported that the `window' may have be deleted
(if (window-live-p window) (if (window-live-p window)
(select-window window) (select-window window)

View file

@ -160,10 +160,9 @@
(declare-function exwm-workspace--current-width "exwm-workspace.el") (declare-function exwm-workspace--current-width "exwm-workspace.el")
(declare-function exwm-workspace--get-geometry "exwm-workspace.el" (frame)) (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--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--set-fullscreen "exwm-workspace.el" (frame))
(declare-function exwm-workspace-move-window "exwm-workspace.el" (declare-function exwm-workspace-move-window "exwm-workspace.el"
(index &optional id)) (frame-or-index &optional id))
;;;###autoload ;;;###autoload
(defun exwm-layout-set-fullscreen (&optional id) (defun exwm-layout-set-fullscreen (&optional id)
@ -347,8 +346,7 @@ selected by `other-buffer'."
(let ((window (car windows))) (let ((window (car windows)))
(if (eq frame exwm--frame) (if (eq frame exwm--frame)
(exwm-layout--show exwm--id window) (exwm-layout--show exwm--id window)
(exwm-workspace-move-window (exwm-workspace-move-window frame exwm--id))
(exwm-workspace--position frame) exwm--id))
;; Make sure this buffer is not displayed elsewhere. Note down ;; Make sure this buffer is not displayed elsewhere. Note down
;; windows displaying an EXWM-buffer now displayed elsewhere; we ;; windows displaying an EXWM-buffer now displayed elsewhere; we
;; need to display with some other buffer there. ;; need to display with some other buffer there.

View file

@ -94,7 +94,7 @@ corresponding buffer.")
(declare-function exwm-workspace--current-width "exwm-workspace.el") (declare-function exwm-workspace--current-width "exwm-workspace.el")
(declare-function exwm-workspace--set-desktop "exwm-workspace.el" (id)) (declare-function exwm-workspace--set-desktop "exwm-workspace.el" (id))
(declare-function exwm-workspace-move-window "exwm-workspace.el" (declare-function exwm-workspace-move-window "exwm-workspace.el"
(index &optional id)) (frame-or-index &optional id))
(defun exwm-manage--manage-window (id) (defun exwm-manage--manage-window (id)
"Manage window ID." "Manage window ID."

View file

@ -46,6 +46,19 @@ NIL if FRAME is not a workspace"
"Return t if FRAME is a workspace." "Return t if FRAME is a workspace."
(memq frame exwm-workspace--list)) (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 (defvar exwm-workspace--switch-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(define-key map [t] (lambda () (interactive))) (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.") "Normal hook run after switching workspace.")
;;;###autoload ;;;###autoload
(defun exwm-workspace-switch (index &optional force) (defun exwm-workspace-switch (frame-or-index &optional force)
"Switch to workspace INDEX. Query for INDEX if it's not specified. "Switch to workspace INDEX. Query for FRAME-OR-INDEX if it's not specified.
The optional FORCE option is for internal use only." The optional FORCE option is for internal use only."
(interactive (interactive
(list (list
(unless (and (eq major-mode 'exwm-mode) exwm--fullscreen) ;it's invisible (unless (and (eq major-mode 'exwm-mode) exwm--fullscreen) ;it's invisible
(exwm-workspace--update-switch-history) (exwm-workspace--update-switch-history)
(let* ((history-add-new-input nil) ;prevent modifying history (let* ((current-idx (exwm-workspace--position exwm-workspace--current))
(idx (read-from-minibuffer (history-add-new-input nil) ;prevent modifying history
"Workspace: " (elt exwm-workspace--switch-history (history-idx (read-from-minibuffer
exwm-workspace-current-index) "Workspace: " (elt exwm-workspace--switch-history current-idx)
exwm-workspace--switch-map nil exwm-workspace--switch-map nil
`(exwm-workspace--switch-history `(exwm-workspace--switch-history . ,(1+ current-idx))))
. ,(1+ exwm-workspace-current-index))))) (workspace-idx (cl-position history-idx exwm-workspace--switch-history :test #'equal)))
(cl-position idx exwm-workspace--switch-history :test #'equal))))) (elt exwm-workspace--list workspace-idx)))))
(when index (let* ((frame (exwm-workspace--workspace-from-frame-or-index frame-or-index))
(unless (and (<= 0 index) (< index (exwm-workspace--count))) (index (exwm-workspace--position frame))
(user-error "[EXWM] Workspace index out of range: %d" index)) (workspace (frame-parameter frame 'exwm-workspace))
(when (or force (/= exwm-workspace-current-index index)) (window (frame-parameter frame 'exwm-selected-window)))
(let* ((frame (elt exwm-workspace--list index)) (when (or force (not (eq frame exwm-workspace--current)))
(workspace (frame-parameter frame 'exwm-workspace)) (unless (window-live-p window)
(window (frame-parameter frame 'exwm-selected-window))) (setq window (frame-selected-window frame)))
(unless (window-live-p window) ;; Raise the workspace container.
(setq window (frame-selected-window frame))) (xcb:+request exwm--connection
;; Raise the workspace container. (make-instance 'xcb:ConfigureWindow
(xcb:+request exwm--connection :window workspace
(make-instance 'xcb:ConfigureWindow :value-mask xcb:ConfigWindow:StackMode
:window workspace :stack-mode xcb:StackMode:Above))
:value-mask xcb:ConfigWindow:StackMode ;; Raise X windows with struts set if there's no fullscreen X window.
:stack-mode xcb:StackMode:Above)) (unless (buffer-local-value 'exwm--fullscreen (window-buffer window))
;; Raise X windows with struts set if there's no fullscreen X window. (dolist (pair exwm-workspace--id-struts-alist)
(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
(xcb:+request exwm--connection (xcb:+request exwm--connection
(make-instance 'xcb:ReparentWindow (make-instance 'xcb:ConfigureWindow
:window :window (car pair)
(frame-parameter exwm-workspace--minibuffer :value-mask xcb:ConfigWindow:StackMode
'exwm-container) :stack-mode xcb:StackMode:Above))))
:parent (frame-parameter frame 'exwm-workspace) (setq exwm-workspace--current frame
:x 0 :y 0)) exwm-workspace-current-index index)
(exwm-workspace--resize-minibuffer-frame)) (unless (exwm-workspace--workspace-p (selected-frame))
;; Hide windows in other workspaces by preprending a space ;; Save the floating frame window selected on the previous workspace.
(unless exwm-workspace-show-all-buffers (set-frame-parameter (with-current-buffer (window-buffer)
(dolist (i exwm--id-buffer-alist) exwm--frame)
(with-current-buffer (cdr i) 'exwm-selected-window (selected-window)))
(let ((name (replace-regexp-in-string "^\\s-*" "" (select-window window)
(buffer-name)))) (set-frame-parameter frame 'exwm-selected-window nil)
(exwm-workspace-rename-buffer (if (eq frame exwm--frame) ;; Close the (possible) active minibuffer
name (when (active-minibuffer-window)
(concat " " name))))))) (run-with-idle-timer 0 nil (lambda () (abort-recursive-edit))))
;; Update demands attention flag (if (not (exwm-workspace--minibuffer-own-frame-p))
(set-frame-parameter frame 'exwm--urgency nil) (setq default-minibuffer-frame frame)
;; Update switch workspace history ;; Resize/reposition the minibuffer frame
(setq exwm-workspace--switch-history-outdated t)
;; Set _NET_CURRENT_DESKTOP.
(xcb:+request exwm--connection (xcb:+request exwm--connection
(make-instance 'xcb:ewmh:set-_NET_CURRENT_DESKTOP (make-instance 'xcb:ReparentWindow
:window exwm--root :data index)) :window
(xcb:flush exwm--connection)) (frame-parameter exwm-workspace--minibuffer
(run-hooks 'exwm-workspace-switch-hook)))) '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 () (defun exwm-workspace--on-focus-in ()
"Handle unexpected frame switch." "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)) (declare-function exwm-layout--other-buffer-predicate "exwm-layout.el" (buffer))
;;;###autoload ;;;###autoload
(defun exwm-workspace-move-window (index &optional id) (defun exwm-workspace-move-window (frame-or-index &optional id)
"Move window ID to workspace INDEX." "Move window ID to workspace FRAME-OR-INDEX."
(interactive (interactive
(list (list
(progn (progn
(exwm-workspace--update-switch-history) (exwm-workspace--update-switch-history)
(let* ((history-add-new-input nil) ;prevent modifying history (let* ((current-idx (exwm-workspace--position exwm-workspace--current))
(idx (read-from-minibuffer (history-add-new-input nil) ;prevent modifying history
"Workspace: " (elt exwm-workspace--switch-history (history-idx (read-from-minibuffer
exwm-workspace-current-index) "Workspace: " (elt exwm-workspace--switch-history current-idx)
exwm-workspace--switch-map nil exwm-workspace--switch-map nil
`(exwm-workspace--switch-history `(exwm-workspace--switch-history . ,(1+ current-idx))))
. ,(1+ exwm-workspace-current-index))))) (workspace-idx (cl-position history-idx exwm-workspace--switch-history :test #'equal)))
(cl-position idx exwm-workspace--switch-history :test #'equal))))) (elt exwm-workspace--list workspace-idx)))))
(unless id (setq id (exwm--buffer->id (window-buffer)))) (let ((frame (exwm-workspace--workspace-from-frame-or-index frame-or-index)))
(unless (and (<= 0 index) (< index (exwm-workspace--count))) (unless id (setq id (exwm--buffer->id (window-buffer))))
(user-error "[EXWM] Workspace index out of range: %d" index)) (with-current-buffer (exwm--id->buffer id)
(with-current-buffer (exwm--id->buffer id)
(let ((frame (elt exwm-workspace--list index)))
(unless (eq exwm--frame frame) (unless (eq exwm--frame frame)
(unless exwm-workspace-show-all-buffers (unless exwm-workspace-show-all-buffers
(let ((name (replace-regexp-in-string "^\\s-*" "" (buffer-name)))) (let ((name (replace-regexp-in-string "^\\s-*" "" (buffer-name))))
(exwm-workspace-rename-buffer (exwm-workspace-rename-buffer
(if (= index exwm-workspace-current-index) (if (eq frame exwm-workspace--current)
name name
(concat " " name))))) (concat " " name)))))
(setq exwm--frame frame) (setq exwm--frame frame)
@ -446,7 +455,7 @@ The optional FORCE option is for internal use only."
:x x :y y)) :x x :y y))
(xcb:flush exwm--connection) (xcb:flush exwm--connection)
(if (exwm-workspace--minibuffer-own-frame-p) (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) (select-frame-set-input-focus exwm--floating-frame)
(exwm-layout--refresh)) (exwm-layout--refresh))
;; The frame needs to be recreated since it won't use the ;; 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) (delete-frame old-frame)
(set-window-dedicated-p window t) (set-window-dedicated-p window t)
(exwm-layout--show id window)) (exwm-layout--show id window))
(if (/= index exwm-workspace-current-index) (if (not (eq frame exwm-workspace--current))
(make-frame-visible new-frame) (make-frame-visible new-frame)
(select-frame-set-input-focus new-frame) (select-frame-set-input-focus new-frame)
(redisplay)))) (redisplay))))
;; Update the 'exwm-selected-window' frame parameter. ;; 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) (with-current-buffer (exwm--id->buffer id)
(set-frame-parameter frame 'exwm-selected-window (set-frame-parameter frame 'exwm-selected-window
(frame-root-window (frame-root-window
exwm--floating-frame))))) exwm--floating-frame)))))
;; Move the X window container. ;; 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) (set-window-buffer (get-buffer-window (current-buffer) t)
(other-buffer)) (other-buffer))
(bury-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-frame-set-input-focus exwm--floating-frame)
(select-window (frame-root-window exwm--floating-frame))) (select-window (frame-root-window exwm--floating-frame)))
;; On another workspace. ;; On another workspace.
(exwm-workspace-move-window exwm-workspace-current-index (exwm-workspace-move-window exwm-workspace--current
exwm--id)) exwm--id))
;; Ordinary buffer. ;; Ordinary buffer.
(switch-to-buffer buffer-or-name))))) (switch-to-buffer buffer-or-name)))))

View file

@ -438,10 +438,9 @@
;; FIXME: check (may require other properties set) ;; FIXME: check (may require other properties set)
(when (memq xcb:Atom:_NET_WM_STATE_DEMANDS_ATTENTION props) (when (memq xcb:Atom:_NET_WM_STATE_DEMANDS_ATTENTION props)
(when (= action xcb:ewmh:_NET_WM_STATE_ADD) (when (= action xcb:ewmh:_NET_WM_STATE_ADD)
(let ((idx (exwm-workspace--position exwm--frame))) (unless (eq exwm--frame exwm-workspace--current)
(unless (= idx exwm-workspace-current-index) (set-frame-parameter exwm--frame 'exwm--urgency t)
(set-frame-parameter exwm--frame 'exwm--urgency t) (setq exwm-workspace--switch-history-outdated t)))
(setq exwm-workspace--switch-history-outdated t))))
;; xcb:ewmh:_NET_WM_STATE_REMOVE? ;; xcb:ewmh:_NET_WM_STATE_REMOVE?
;; xcb:ewmh:_NET_WM_STATE_TOGGLE? ;; xcb:ewmh:_NET_WM_STATE_TOGGLE?
) )