about summary refs log tree commit diff
diff options
context:
space:
mode:
authorChris Feng <chris.w.feng@gmail.com>2016-07-19T02·30+0800
committerChris Feng <chris.w.feng@gmail.com>2016-07-19T02·30+0800
commit622618ac6e401857b335b7e5dd1969cb9e1f948b (patch)
tree3078eed712ceeec916d83ec951f6d3c50fcbb010
parent73d890aad4e06cc722a00ed40532a7df07a83550 (diff)
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.
-rw-r--r--exwm-workspace.el75
-rw-r--r--exwm.el11
2 files changed, 76 insertions, 10 deletions
diff --git a/exwm-workspace.el b/exwm-workspace.el
index 629f940214b4..0843c27e92c6 100644
--- a/exwm-workspace.el
+++ b/exwm-workspace.el
@@ -27,6 +27,7 @@
 
 (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--current nil "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
   (let ((map (make-sparse-keymap)))
     (define-key map [t] (lambda () (interactive)))
+    (define-key map "+" #'exwm-workspace-add)
+    (define-key map "-" #'exwm-workspace-delete)
     (dotimes (i 10)
       (define-key map (int-to-string i)
         #'exwm-workspace--switch-map-nth-prefix))
@@ -88,13 +91,14 @@ NIL if FRAME is not a workspace"
 (defvar exwm-workspace--switch-history-outdated nil
   "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."
   (exwm-workspace--update-switch-history)
   (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)
+                       (or prompt "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
@@ -359,14 +363,25 @@ PREFIX-DIGITS is a list of the digits introduced so far."
   "Normal hook run after switching workspace.")
 
 ;;;###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.
 
 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--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))
          (index (exwm-workspace--position frame))
          (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."
   (interactive
    (unless (and (eq major-mode 'exwm-mode) exwm--fullscreen) ;it's invisible
-     (list
-      (exwm-workspace--prompt-for-workspace)
-      (exwm-workspace--prompt-for-workspace))))
+     (let* ((w1 (exwm-workspace--prompt-for-workspace "Pick a workspace: "))
+            (w2 (exwm-workspace--prompt-for-workspace
+                 (format "Swap workspace %d with: "
+                         (exwm-workspace--position w1)))))
+       (list w1 w2))))
   (let ((pos1 (exwm-workspace--position workspace1))
         (pos2 (exwm-workspace--position workspace2)))
     (if (or (not pos1) (not pos2) (= pos1 pos2))
@@ -469,8 +486,8 @@ before it."
   (interactive
    (unless (and (eq major-mode 'exwm-mode) exwm--fullscreen) ;it's invisible
      (list exwm-workspace--current
-           (exwm-workspace--position (exwm-workspace--prompt-for-workspace)))))
-  (let ((pos (exwm-workspace--position workspace)))
+           (exwm-workspace--position
+            (exwm-workspace--prompt-for-workspace "Move workspace to: ")))))
   (let ((pos (exwm-workspace--position workspace))
         flag start end index)
     (if (= nth pos)
@@ -496,6 +513,38 @@ before it."
                              (selected-window))
         (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 ()
   "Handle unexpected frame switch."
   ;; `focus-in-hook' is run by `handle-switch-frame'.
@@ -526,7 +575,8 @@ before it."
 ;;;###autoload
 (defun exwm-workspace-move-window (frame-or-index &optional id)
   "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)))
     (unless id (setq id (exwm--buffer->id (window-buffer))))
     (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.
     (modify-all-frames-parameters
      '((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
     (dolist (i initial-workspaces)
       (exwm-workspace--add-frame-as-workspace i)))
diff --git a/exwm.el b/exwm.el
index 9151fdc5c38c..f7d027ebcfc2 100644
--- a/exwm.el
+++ b/exwm.el
@@ -325,6 +325,17 @@
           id (slot-value obj 'window)
           data (slot-value (slot-value obj 'data) 'data32))
     (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.
      ((= type xcb:Atom:_NET_CURRENT_DESKTOP)
       (exwm-workspace-switch (elt data 0)))