Improve the handling of workspaces

* exwm-workspace.el (exwm-workspace--prompt-for-workspace):
Add an optional argument to modify prompt.
(exwm-workspace-switch, exwm-workspace-swap)
(exwm-workspace-move, exwm-workspace-move-window): Use it.

* exwm-workspace.el (exwm-workspace-number): Re-introduce the variable
(now it stands for the initial workspace number).
(exwm-workspace--init): Create remaining initial workspaces.

* exwm-workspace.el (exwm-workspace-add, exwm-workspace-delete):
New commands for adding/deleting workspaces.
(exwm-workspace--switch-map): Add "+"/"-" to increase/descrease
workspace number.

* exwm-workspace.el (exwm-workspace-switch): Automatically add missing
workspaces.

* exwm.el (exwm--on-ClientMessage): Support _NET_NUMBER_OF_DESKTOPS
client message for adjusting workspace number.
This commit is contained in:
Chris Feng 2016-07-19 10:30:21 +08:00
parent 73d890aad4
commit 622618ac6e
2 changed files with 76 additions and 10 deletions

View file

@ -27,6 +27,7 @@
(require 'exwm-core) (require 'exwm-core)
(defvar exwm-workspace-number 1 "Initial number of workspaces.")
(defvar exwm-workspace--list nil "List of all workspaces (Emacs frames).") (defvar exwm-workspace--list nil "List of all workspaces (Emacs frames).")
(defvar exwm-workspace--current nil "Current active workspace.") (defvar exwm-workspace--current nil "Current active workspace.")
(defvar exwm-workspace-current-index 0 "Index of current active workspace.") (defvar exwm-workspace-current-index 0 "Index of current active workspace.")
@ -62,6 +63,8 @@ NIL if FRAME is not a workspace"
(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)))
(define-key map "+" #'exwm-workspace-add)
(define-key map "-" #'exwm-workspace-delete)
(dotimes (i 10) (dotimes (i 10)
(define-key map (int-to-string i) (define-key map (int-to-string i)
#'exwm-workspace--switch-map-nth-prefix)) #'exwm-workspace--switch-map-nth-prefix))
@ -88,13 +91,14 @@ NIL if FRAME is not a workspace"
(defvar exwm-workspace--switch-history-outdated nil (defvar exwm-workspace--switch-history-outdated nil
"Non-nil to indicate `exwm-workspace--switch-history' is outdated.") "Non-nil to indicate `exwm-workspace--switch-history' is outdated.")
(defun exwm-workspace--prompt-for-workspace () (defun exwm-workspace--prompt-for-workspace (&optional prompt)
"Prompt for a workspace, returning the workspace frame." "Prompt for a workspace, returning the workspace frame."
(exwm-workspace--update-switch-history) (exwm-workspace--update-switch-history)
(let* ((current-idx (exwm-workspace--position exwm-workspace--current)) (let* ((current-idx (exwm-workspace--position exwm-workspace--current))
(history-add-new-input nil) ;prevent modifying history (history-add-new-input nil) ;prevent modifying history
(history-idx (read-from-minibuffer (history-idx (read-from-minibuffer
"Workspace: " (elt exwm-workspace--switch-history current-idx) (or prompt "Workspace: ")
(elt exwm-workspace--switch-history current-idx)
exwm-workspace--switch-map nil exwm-workspace--switch-map nil
`(exwm-workspace--switch-history . ,(1+ current-idx)))) `(exwm-workspace--switch-history . ,(1+ current-idx))))
(workspace-idx (cl-position history-idx exwm-workspace--switch-history (workspace-idx (cl-position history-idx exwm-workspace--switch-history
@ -359,14 +363,25 @@ PREFIX-DIGITS is a list of the digits introduced so far."
"Normal hook run after switching workspace.") "Normal hook run after switching workspace.")
;;;###autoload ;;;###autoload
(defun exwm-workspace-switch (frame-or-index &optional force) (cl-defun exwm-workspace-switch (frame-or-index &optional force)
"Switch to workspace INDEX. Query for FRAME-OR-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--prompt-for-workspace)))) (exwm-workspace--prompt-for-workspace "Workspace [+/-]: "))))
;; Try to create workspace(s) when INDEX is out-of-range.
(when (and (integerp frame-or-index)
(>= frame-or-index (exwm-workspace--count)))
(run-with-idle-timer 0 nil
(lambda (times)
(dotimes (_ times)
(make-frame)))
;; Create no more than 9 workspaces.
(min 9
(1+ (- frame-or-index (exwm-workspace--count)))))
(cl-return-from exwm-workspace-switch))
(let* ((frame (exwm-workspace--workspace-from-frame-or-index frame-or-index)) (let* ((frame (exwm-workspace--workspace-from-frame-or-index frame-or-index))
(index (exwm-workspace--position frame)) (index (exwm-workspace--position frame))
(workspace (frame-parameter frame 'exwm-workspace)) (workspace (frame-parameter frame 'exwm-workspace))
@ -440,9 +455,11 @@ The optional FORCE option is for internal use only."
"Interchange position of WORKSPACE1 with that of WORKSPACE2." "Interchange position of WORKSPACE1 with that of WORKSPACE2."
(interactive (interactive
(unless (and (eq major-mode 'exwm-mode) exwm--fullscreen) ;it's invisible (unless (and (eq major-mode 'exwm-mode) exwm--fullscreen) ;it's invisible
(list (let* ((w1 (exwm-workspace--prompt-for-workspace "Pick a workspace: "))
(exwm-workspace--prompt-for-workspace) (w2 (exwm-workspace--prompt-for-workspace
(exwm-workspace--prompt-for-workspace)))) (format "Swap workspace %d with: "
(exwm-workspace--position w1)))))
(list w1 w2))))
(let ((pos1 (exwm-workspace--position workspace1)) (let ((pos1 (exwm-workspace--position workspace1))
(pos2 (exwm-workspace--position workspace2))) (pos2 (exwm-workspace--position workspace2)))
(if (or (not pos1) (not pos2) (= pos1 pos2)) (if (or (not pos1) (not pos2) (= pos1 pos2))
@ -469,8 +486,8 @@ before it."
(interactive (interactive
(unless (and (eq major-mode 'exwm-mode) exwm--fullscreen) ;it's invisible (unless (and (eq major-mode 'exwm-mode) exwm--fullscreen) ;it's invisible
(list exwm-workspace--current (list exwm-workspace--current
(exwm-workspace--position (exwm-workspace--prompt-for-workspace))))) (exwm-workspace--position
(let ((pos (exwm-workspace--position workspace))) (exwm-workspace--prompt-for-workspace "Move workspace to: ")))))
(let ((pos (exwm-workspace--position workspace)) (let ((pos (exwm-workspace--position workspace))
flag start end index) flag start end index)
(if (= nth pos) (if (= nth pos)
@ -496,6 +513,38 @@ before it."
(selected-window)) (selected-window))
(exwm-workspace-switch exwm-workspace--current t))))) (exwm-workspace-switch exwm-workspace--current t)))))
;;;###autoload
(defun exwm-workspace-add (&optional index)
"Add a workspace as the INDEX-th workspace, or the last one if INDEX is nil.
INDEX must not exceed the current number of workspaces."
(interactive)
(run-with-idle-timer
0 nil
(lambda (index)
(if (and index
;; No need to move if it's the last one.
(< index (exwm-workspace--count)))
(exwm-workspace-move (make-frame) index)
(make-frame)))
index)
(when (active-minibuffer-window)
(abort-recursive-edit)))
;;;###autoload
(defun exwm-workspace-delete (&optional frame-or-index)
"Delete the workspace FRAME-OR-INDEX."
(interactive)
(run-with-idle-timer 0 nil #'delete-frame
;; We should not simply delete the selected frame
;; since it can be e.g. a floating frame.
(if frame-or-index
(exwm-workspace--workspace-from-frame-or-index
frame-or-index)
exwm-workspace--current))
(when (active-minibuffer-window)
(abort-recursive-edit)))
(defun exwm-workspace--on-focus-in () (defun exwm-workspace--on-focus-in ()
"Handle unexpected frame switch." "Handle unexpected frame switch."
;; `focus-in-hook' is run by `handle-switch-frame'. ;; `focus-in-hook' is run by `handle-switch-frame'.
@ -526,7 +575,8 @@ before it."
;;;###autoload ;;;###autoload
(defun exwm-workspace-move-window (frame-or-index &optional id) (defun exwm-workspace-move-window (frame-or-index &optional id)
"Move window ID to workspace FRAME-OR-INDEX." "Move window ID to workspace FRAME-OR-INDEX."
(interactive (list (exwm-workspace--prompt-for-workspace))) (interactive (list
(exwm-workspace--prompt-for-workspace "Move to: ")))
(let ((frame (exwm-workspace--workspace-from-frame-or-index frame-or-index))) (let ((frame (exwm-workspace--workspace-from-frame-or-index frame-or-index)))
(unless id (setq id (exwm--buffer->id (window-buffer)))) (unless id (setq id (exwm--buffer->id (window-buffer))))
(with-current-buffer (exwm--id->buffer id) (with-current-buffer (exwm--id->buffer id)
@ -1178,6 +1228,11 @@ applied to all subsequently created X frames."
;; Prevent `other-buffer' from selecting already displayed EXWM buffers. ;; Prevent `other-buffer' from selecting already displayed EXWM buffers.
(modify-all-frames-parameters (modify-all-frames-parameters
'((buffer-predicate . exwm-layout--other-buffer-predicate))) '((buffer-predicate . exwm-layout--other-buffer-predicate)))
;; Create remaining workspaces.
(dotimes (_ (- exwm-workspace-number (length initial-workspaces)))
(nconc initial-workspaces (list (make-frame '((window-system . x)
(internal-border-width . 0)
(client . nil))))))
;; Configure workspaces ;; Configure workspaces
(dolist (i initial-workspaces) (dolist (i initial-workspaces)
(exwm-workspace--add-frame-as-workspace i))) (exwm-workspace--add-frame-as-workspace i)))

11
exwm.el
View file

@ -325,6 +325,17 @@
id (slot-value obj 'window) id (slot-value obj 'window)
data (slot-value (slot-value obj 'data) 'data32)) data (slot-value (slot-value obj 'data) 'data32))
(cond (cond
;; _NET_NUMBER_OF_DESKTOPS.
((= type xcb:Atom:_NET_NUMBER_OF_DESKTOPS)
(let ((current (exwm-workspace--count))
(requested (elt data 0)))
;; Only allow increasing/decreasing the workspace number by 1.
(cond
((< current requested)
(make-frame))
((and (> current requested)
(> current 1))
(delete-frame (car (last exwm-workspace--list)))))))
;; _NET_CURRENT_DESKTOP. ;; _NET_CURRENT_DESKTOP.
((= type xcb:Atom:_NET_CURRENT_DESKTOP) ((= type xcb:Atom:_NET_CURRENT_DESKTOP)
(exwm-workspace-switch (elt data 0))) (exwm-workspace-switch (elt data 0)))