about summary refs log tree commit diff
diff options
context:
space:
mode:
authorChris Feng <chris.w.feng@gmail.com>2016-07-21T04·48+0800
committerChris Feng <chris.w.feng@gmail.com>2016-07-21T04·48+0800
commit0c114d97b78f806ebe2904c8f55f573fd7c879e7 (patch)
treec940a76366dceec1c44f6561c323e548b2b77379
parentf48b8eafb0b8f8afab0d42459a29f605cf452daa (diff)
Fix workspace creation and deletion
* exwm-workspace.el (exwm-workspace-switch)
(exwm-workspace-switch-create): Move support for creating missing
workspaces from the former to the latter..
(exwm-workspace-switch-create-limit): New variable limiting the number
of new workspaces allowed to create each time.

* exwm-workspace.el (exwm-workspace--prompt-add)
(exwm-workspace--prompt-delete): New commands for adding and deleting
workspaces from the `read-from-minibuffer' prompt.
(exwm-workspace--prompt-add-allowed)
(exwm-workspace--prompt-delete-allowed): New variables telling whether
the above two commands are allowed to run.
(exwm-workspace--switch-map): Change "+" / "-" to use the new commands.
* exwm-workspace.el (exwm-workspace-switch, exwm-workspace-swap)
(exwm-workspace-move-window): Use this new feature.

* exwm-workspace.el (exwm-workspace-add, exwm-workspace-delete): Since
they are not used by the keymap any more, drop the use of idle timer.

* exwm-workspace.el (exwm-workspace--create-silently): New variable
indicating whether new workspaces should be created in the background.
(exwm-workspace--add-frame-as-workspace): Support creating new
workspaces in the background.

* exwm-workspace.el (exwm-workspace--on-ConfigureNotify):
Update workareas if it's not up to date.

* exwm-randr.el (exwm-randr--refresh): Raise the standalone minibuffer
when refreshed.

* exwm-config.el (exwm-config-default): Add `exwm-workspace-number' and
`exwm-workspace-switch-create'.
-rw-r--r--exwm-config.el6
-rw-r--r--exwm-randr.el5
-rw-r--r--exwm-workspace.el128
3 files changed, 96 insertions, 43 deletions
diff --git a/exwm-config.el b/exwm-config.el
index e1e5010d3d0d..8c54607006d7 100644
--- a/exwm-config.el
+++ b/exwm-config.el
@@ -30,6 +30,8 @@
 
 (defun exwm-config-default ()
   "Default configuration of EXWM."
+  ;; Set the initial workspace number.
+  (setq exwm-workspace-number 4)
   ;; Make class name the buffer name
   (add-hook 'exwm-update-class-hook
             (lambda ()
@@ -41,7 +43,9 @@
   ;; 's-N': Switch to certain workspace
   (dotimes (i 10)
     (exwm-input-set-key (kbd (format "s-%d" i))
-                        `(lambda () (interactive) (exwm-workspace-switch ,i))))
+                        `(lambda ()
+                           (interactive)
+                           (exwm-workspace-switch-create ,i))))
   ;; 's-&': Launch application
   (exwm-input-set-key (kbd "s-&")
                       (lambda (command)
diff --git a/exwm-randr.el b/exwm-randr.el
index 709469a44d0a..4ce1752d9ee8 100644
--- a/exwm-randr.el
+++ b/exwm-randr.el
@@ -60,6 +60,7 @@
 (declare-function exwm-workspace--count "exwm-workspace.el")
 (declare-function exwm-workspace--set-fullscreen "exwm-workspace.el" (frame))
 (declare-function exwm-workspace--update-workareas "exwm-workspace.el" ())
+(declare-function exwm-workspace--show-minibuffer "exwm-workspace.el" ())
 (declare-function exwm-workspace--set-desktop-geometry "exwm-workspace.el" ())
 
 (defun exwm-randr--refresh ()
@@ -111,6 +112,10 @@
       ;; Resize workspace.
       (dolist (f exwm-workspace--list)
         (exwm-workspace--set-fullscreen f))
+      ;; Raise the minibuffer if it's active.
+      (when (and (active-minibuffer-window)
+                 (exwm-workspace--minibuffer-own-frame-p))
+        (exwm-workspace--show-minibuffer))
       ;; Set _NET_DESKTOP_GEOMETRY.
       (exwm-workspace--set-desktop-geometry)
       (xcb:flush exwm--connection)
diff --git a/exwm-workspace.el b/exwm-workspace.el
index e33144ec6a7b..0d636398c4d4 100644
--- a/exwm-workspace.el
+++ b/exwm-workspace.el
@@ -63,8 +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)
+    (define-key map "+" #'exwm-workspace--prompt-add)
+    (define-key map "-" #'exwm-workspace--prompt-delete)
     (dotimes (i 10)
       (define-key map (int-to-string i)
         #'exwm-workspace--switch-map-nth-prefix))
@@ -105,6 +105,38 @@ NIL if FRAME is not a workspace"
                                      :test #'equal)))
     (elt exwm-workspace--list workspace-idx)))
 
+(defvar exwm-workspace--prompt-add-allowed nil
+  "Non-nil to allow adding workspace from the prompt.")
+(defvar exwm-workspace--prompt-delete-allowed nil
+  "Non-nil to allow deleting workspace from the prompt")
+(defvar exwm-workspace--create-silently nil
+  "When non-nil workspaces are created in the background (not switched to).")
+
+(defun exwm-workspace--prompt-add ()
+  "Add workspace from the prompt."
+  (interactive)
+  (when exwm-workspace--prompt-add-allowed
+    (let ((exwm-workspace--create-silently t))
+      (make-frame))
+    (exwm-workspace--update-switch-history)
+    (goto-history-element minibuffer-history-position)))
+
+(defun exwm-workspace--prompt-delete ()
+  "Delete workspace from the prompt."
+  (interactive)
+  (when (and exwm-workspace--prompt-delete-allowed
+             (< 1 (exwm-workspace--count)))
+    (let ((frame (elt exwm-workspace--list (1- minibuffer-history-position))))
+      (if (eq frame exwm-workspace--current)
+          ;; Abort the recursive minibuffer if deleting the current workspace.
+          (progn
+            (run-with-idle-timer 0 nil #'delete-frame frame)
+            (abort-recursive-edit))
+        (delete-frame frame)
+        (exwm-workspace--update-switch-history)
+        (goto-history-element (min minibuffer-history-position
+                                   (exwm-workspace--count)))))))
+
 (defun exwm-workspace--update-switch-history ()
   "Update the history for switching workspace to reflect the latest status."
   (when exwm-workspace--switch-history-outdated
@@ -390,25 +422,16 @@ PREFIX-DIGITS is a list of the digits introduced so far."
   "Normal hook run after switching workspace.")
 
 ;;;###autoload
-(cl-defun exwm-workspace-switch (frame-or-index &optional force)
+(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 "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 ((exwm-workspace--prompt-add-allowed t)
+            (exwm-workspace--prompt-delete-allowed t))
+        (exwm-workspace--prompt-for-workspace "Switch to [+/-]: ")))))
   (let* ((frame (exwm-workspace--workspace-from-frame-or-index frame-or-index))
          (index (exwm-workspace--position frame))
          (workspace (frame-parameter frame 'exwm-workspace))
@@ -469,6 +492,23 @@ The optional FORCE option is for internal use only."
       (xcb:flush exwm--connection))
     (run-hooks 'exwm-workspace-switch-hook)))
 
+(defvar exwm-workspace-switch-create-limit 10
+  "Number of workspaces `exwm-workspace-switch-create' allowed to create
+each time.")
+
+(defun exwm-workspace-switch-create (frame-or-index)
+  "Switch to workspace FRAME-OR-INDEX, creating it if it does not exist yet."
+  (interactive)
+  (if (or (framep frame-or-index)
+          (< frame-or-index (exwm-workspace--count)))
+      (exwm-workspace-switch frame-or-index)
+    (let ((exwm-workspace--create-silently t))
+      (dotimes (_ (min exwm-workspace-switch-create-limit
+                       (1+ (- frame-or-index
+                              (exwm-workspace--count)))))
+        (make-frame)))
+    (exwm-workspace-switch (car (last exwm-workspace--list)))))
+
 (defvar exwm-workspace-list-change-hook nil
   "Normal hook run when the workspace list is changed (workspace added,
 deleted, moved, etc).")
@@ -478,10 +518,14 @@ deleted, moved, etc).")
   "Interchange position of WORKSPACE1 with that of WORKSPACE2."
   (interactive
    (unless (and (eq major-mode 'exwm-mode) exwm--fullscreen) ;it's invisible
-     (let* ((w1 (exwm-workspace--prompt-for-workspace "Pick a workspace: "))
-            (w2 (exwm-workspace--prompt-for-workspace
+     (let (w1 w2)
+       (let ((exwm-workspace--prompt-add-allowed t)
+             (exwm-workspace--prompt-delete-allowed t))
+         (setq w1 (exwm-workspace--prompt-for-workspace
+                   "Pick a workspace [+/-]: ")))
+       (setq w2 (exwm-workspace--prompt-for-workspace
                  (format "Swap workspace %d with: "
-                         (exwm-workspace--position w1)))))
+                         (exwm-workspace--position w1))))
        (list w1 w2))))
   (let ((pos1 (exwm-workspace--position workspace1))
         (pos2 (exwm-workspace--position workspace2)))
@@ -544,31 +588,20 @@ before it."
 
 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)))
+  (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)))
 
 ;;;###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)))
+  (delete-frame
+   (if frame-or-index
+       (exwm-workspace--workspace-from-frame-or-index frame-or-index)
+     exwm-workspace--current)))
 
 (defun exwm-workspace--on-focus-in ()
   "Handle unexpected frame switch."
@@ -601,7 +634,9 @@ INDEX must not exceed the current number of workspaces."
 (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 "Move to: ")))
+                (let ((exwm-workspace--prompt-add-allowed t)
+                      (exwm-workspace--prompt-delete-allowed t))
+                  (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)
@@ -874,6 +909,9 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first."
                              :window window
                              :value-mask xcb:ConfigWindow:Height
                              :height height)))
+        (when (/= (exwm-workspace--count) (length exwm-workspace--workareas))
+          ;; There is a chance the workareas are not updated timely.
+          (exwm-workspace--update-workareas))
         (setq workarea (elt exwm-workspace--workareas
                             exwm-workspace-current-index)
               y (if (eq exwm-workspace-minibuffer-position 'top)
@@ -1064,8 +1102,7 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first."
     (exwm--log "Frame `%s' is floating" frame))
    (t
     (exwm--log "Adding frame `%s' as workspace" frame)
-    (setq exwm-workspace--list (nconc exwm-workspace--list (list frame))
-          exwm-workspace--current frame)
+    (setq exwm-workspace--list (nconc exwm-workspace--list (list frame)))
     (let ((outer-id (string-to-number (frame-parameter frame
                                                        'outer-window-id)))
           (container (xcb:generate-id exwm--connection))
@@ -1094,6 +1131,11 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first."
                          :override-redirect 1
                          :event-mask xcb:EventMask:SubstructureRedirect))
       (xcb:+request exwm--connection
+          (make-instance 'xcb:ConfigureWindow
+                         :window workspace
+                         :value-mask xcb:ConfigWindow:StackMode
+                         :stack-mode xcb:StackMode:Below))
+      (xcb:+request exwm--connection
           (make-instance 'xcb:CreateWindow
                          :depth 0 :wid container :parent workspace
                          :x 0 :y 0
@@ -1129,7 +1171,9 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first."
                          frame 'fullscreen 'fullboth)
     ;; Update EWMH properties.
     (exwm-workspace--update-ewmh-props)
-    (exwm-workspace-switch frame t)
+    (if exwm-workspace--create-silently
+        (setq exwm-workspace--switch-history-outdated t)
+      (exwm-workspace-switch frame t))
     (run-hooks 'exwm-workspace-list-change-hook))))
 
 (defun exwm-workspace--remove-frame-as-workspace (frame)