about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--exwm-config.el2
-rw-r--r--exwm-workspace.el99
2 files changed, 64 insertions, 37 deletions
diff --git a/exwm-config.el b/exwm-config.el
index d6e10f23c9f7..e1e5010d3d0d 100644
--- a/exwm-config.el
+++ b/exwm-config.el
@@ -39,7 +39,7 @@
   ;; 's-w': Switch workspace
   (exwm-input-set-key (kbd "s-w") #'exwm-workspace-switch)
   ;; 's-N': Switch to certain workspace
-  (dotimes (i exwm-workspace-number)
+  (dotimes (i 10)
     (exwm-input-set-key (kbd (format "s-%d" i))
                         `(lambda () (interactive) (exwm-workspace-switch ,i))))
   ;; 's-&': Launch application
diff --git a/exwm-workspace.el b/exwm-workspace.el
index 2a11756fbb3e..75fcc96e0407 100644
--- a/exwm-workspace.el
+++ b/exwm-workspace.el
@@ -27,7 +27,6 @@
 
 (require 'exwm-core)
 
-(defvar exwm-workspace-number 4 "Number of workspaces (1 ~ 10).")
 (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.")
@@ -63,12 +62,7 @@ NIL if FRAME is not a workspace"
   (let ((map (make-sparse-keymap)))
     (define-key map [t] (lambda () (interactive)))
     (dotimes (i 10)
-      (define-key map (int-to-string i)
-        `(lambda ()
-           (interactive)
-           (when (< ,i (exwm-workspace--count))
-             (goto-history-element ,(1+ i))
-             (exit-minibuffer)))))
+      (define-key map (int-to-string i) #'exwm-workspace--switch-map-nth-prefix))
     (define-key map "\C-a" (lambda () (interactive) (goto-history-element 1)))
     (define-key map "\C-e" (lambda ()
                              (interactive)
@@ -318,6 +312,48 @@ Value nil means to use the default position which is fixed at bottom, while
                        :stack-mode xcb:StackMode:Above))
     (set-frame-width exwm-workspace--minibuffer width nil t)))
 
+(defun exwm-workspace--switch-map-nth-prefix (&optional prefix-digits)
+  "Allow selecting a workspace by number.
+
+PREFIX-DIGITS is a list of the digits introduced so far."
+  (interactive)
+  (let* ((ev (this-command-keys-vector))
+         (off (1- (length ev)))
+         (k (elt ev off))
+         ;; 0 is ASCII 48.
+         (d (- k 48))
+         ;; Convert prefix-digits to number.  For example, '(2 1) to 120.
+         (o 1)
+         (pn (apply #'+ (mapcar (lambda (x)
+                                  (setq o (* 10 o))
+                                  (* o x))
+                                prefix-digits)))
+         (n (+ pn d))
+         (num-workspaces (exwm-workspace--count)))
+    (if (= (length prefix-digits)           ; Go ahead if there are enough
+           (floor (log num-workspaces 10))) ; digits to select any workspace.
+        (exwm-workspace--switch-map-select-nth n)
+      (set-transient-map
+       (let ((map (make-sparse-keymap))
+             (cmd `(lambda ()
+                     (interactive)
+                     (exwm-workspace--switch-map-nth-prefix ',(cons d prefix-digits))
+                     )))
+         (dotimes (i 10)
+           (define-key map (int-to-string i) cmd))
+         ;; Accept
+         (define-key map [return]
+           `(lambda ()
+              (interactive)
+              (exwm-workspace--switch-map-select-nth ,n)))
+         map)))))
+
+(defun exwm-workspace--switch-map-select-nth (n)
+  "Select Nth workspace."
+  (interactive)
+  (goto-history-element (1+ n))
+  (exit-minibuffer))
+
 (defvar exwm-workspace-switch-hook nil
   "Normal hook run after switching workspace.")
 
@@ -854,9 +890,6 @@ before it."
 (defun exwm-workspace--add-frame-as-workspace (frame)
   "Configure frame FRAME to be treated as a workspace."
   (cond
-   ((>= (exwm-workspace--count) exwm-workspace-number)
-    (delete-frame frame)
-    (user-error "[EXWM] Too many workspaces: maximum is %d" exwm-workspace-number))
    ((exwm-workspace--workspace-p frame)
     (exwm--log "Frame `%s' is already a workspace" frame))
    ((not (display-graphic-p frame))
@@ -1010,31 +1043,23 @@ applied to all subsequently created X frames."
 
 (defun exwm-workspace--init ()
   "Initialize workspace module."
-  (cl-assert (and (< 0 exwm-workspace-number) (>= 10 exwm-workspace-number)))
   ;; Prevent unexpected exit
   (setq confirm-kill-emacs #'exwm-workspace--confirm-kill-emacs)
   (let ((initial-workspaces (frame-list)))
     (if (not (exwm-workspace--minibuffer-own-frame-p))
         ;; Initialize workspaces with minibuffers.
-        (progn
-          (when (< 1 (exwm-workspace--count))
-            ;; Exclude the initial frame.
-            (dolist (i initial-workspaces)
-              (unless (frame-parameter i 'window-id)
-                (setq initial-workspaces (delq i initial-workspaces))))
-            (cl-assert (= 1 (length initial-workspaces)))
-            (setq exwm-workspace--client
-                  (frame-parameter (car exwm-workspace--list) 'client))
-            (let ((f (car initial-workspaces)))
-              ;; Remove the possible internal border.
-              (set-frame-parameter f 'internal-border-width 0)
-              ;; Prevent user from deleting this frame by accident.
-              (set-frame-parameter f 'client nil)))
-          ;; Create remaining frames.
-          (dotimes (_ (1- exwm-workspace-number))
-            (nconc initial-workspaces
-                   (list (make-frame '((window-system . x)
-                                       (internal-border-width . 0)))))))
+        (when (< 1 (length initial-workspaces))
+          ;; Exclude the initial frame.
+          (dolist (i initial-workspaces)
+            (unless (frame-parameter i 'window-id)
+              (setq initial-workspaces (delq i initial-workspaces))))
+          (setq exwm-workspace--client
+                (frame-parameter (car exwm-workspace--list) 'client))
+          (let ((f (car initial-workspaces)))
+            ;; Remove the possible internal border.
+            (set-frame-parameter f 'internal-border-width 0)
+            ;; Prevent user from deleting the first frame by accident.
+            (set-frame-parameter f 'client nil)))
       ;; Initialize workspaces without minibuffers.
       (setq exwm-workspace--minibuffer
             (make-frame '((window-system . x) (minibuffer . only)
@@ -1092,12 +1117,14 @@ applied to all subsequently created X frames."
       (setq exwm-workspace--timer
           (run-with-idle-timer 0 t #'exwm-workspace--on-echo-area-dirty))
       (add-hook 'echo-area-clear-hook #'exwm-workspace--on-echo-area-clear)
-      ;; Create workspace frames.
-      (dotimes (_ exwm-workspace-number)
-        (push (make-frame `((window-system . x)
-                            (internal-border-width . 0)
-                            (client . nil)))
-              exwm-workspace--list))
+      ;; Recreate frames with the external minibuffer set.
+      (setq initial-workspaces
+            (mapcar
+             (lambda (_)
+               (make-frame `((window-system . x)
+                             (internal-border-width . 0)
+                             (client . nil))))
+             initial-workspaces))
       ;; The default behavior of `display-buffer' (indirectly called by
       ;; `minibuffer-completion-help') is not correct here.
       (cl-pushnew '(exwm-workspace--display-buffer) display-buffer-alist