mirror of
https://github.com/ch11ng/exwm.git
synced 2024-11-24 03:47:59 +01:00
Allow adding and removing workspaces
Making and deleting frames adds them as new workspaces.
This commit is contained in:
parent
5222dc17d6
commit
0ec34061b9
2 changed files with 77 additions and 37 deletions
|
@ -76,7 +76,7 @@
|
||||||
(unless default-geometry ;assume the first output as primary
|
(unless default-geometry ;assume the first output as primary
|
||||||
(setq default-geometry geometry)))))))
|
(setq default-geometry geometry)))))))
|
||||||
(cl-assert (<= 2 (length output-plist)))
|
(cl-assert (<= 2 (length output-plist)))
|
||||||
(dotimes (i exwm-workspace-number)
|
(dotimes (i (length exwm-workspace--list))
|
||||||
(let* ((output (plist-get exwm-randr-workspace-output-plist i))
|
(let* ((output (plist-get exwm-randr-workspace-output-plist i))
|
||||||
(geometry (lax-plist-get output-plist output))
|
(geometry (lax-plist-get output-plist output))
|
||||||
(frame (elt exwm-workspace--list i)))
|
(frame (elt exwm-workspace--list i)))
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
(define-key map "\C-a" (lambda () (interactive) (goto-history-element 1)))
|
(define-key map "\C-a" (lambda () (interactive) (goto-history-element 1)))
|
||||||
(define-key map "\C-e" (lambda ()
|
(define-key map "\C-e" (lambda ()
|
||||||
(interactive)
|
(interactive)
|
||||||
(goto-history-element exwm-workspace-number)))
|
(goto-history-element (length exwm-workspace--list))))
|
||||||
(define-key map "\C-g" 'abort-recursive-edit)
|
(define-key map "\C-g" 'abort-recursive-edit)
|
||||||
(define-key map "\C-]" 'abort-recursive-edit)
|
(define-key map "\C-]" 'abort-recursive-edit)
|
||||||
(define-key map "\C-j" 'exit-minibuffer)
|
(define-key map "\C-j" 'exit-minibuffer)
|
||||||
|
@ -61,8 +61,9 @@
|
||||||
|
|
||||||
(defun exwm-workspace--update-switch-history ()
|
(defun exwm-workspace--update-switch-history ()
|
||||||
"Update the history for switching workspace to reflect the latest status."
|
"Update the history for switching workspace to reflect the latest status."
|
||||||
(let ((sequence (number-sequence 0 (1- exwm-workspace-number)))
|
(let* ((num (length exwm-workspace--list))
|
||||||
(not-empty (make-vector exwm-workspace-number nil)))
|
(sequence (number-sequence 0 (1- num)))
|
||||||
|
(not-empty (make-vector num nil)))
|
||||||
(dolist (i exwm--id-buffer-alist)
|
(dolist (i exwm--id-buffer-alist)
|
||||||
(with-current-buffer (cdr i)
|
(with-current-buffer (cdr i)
|
||||||
(when exwm--frame
|
(when exwm--frame
|
||||||
|
@ -104,7 +105,7 @@ The optional FORCE option is for internal use only."
|
||||||
. ,(1+ exwm-workspace-current-index)))))
|
. ,(1+ exwm-workspace-current-index)))))
|
||||||
(cl-position idx exwm-workspace--switch-history :test 'equal)))))
|
(cl-position idx exwm-workspace--switch-history :test 'equal)))))
|
||||||
(when index
|
(when index
|
||||||
(unless (and (<= 0 index) (< index exwm-workspace-number))
|
(unless (and (<= 0 index) (< index (length exwm-workspace--list)))
|
||||||
(user-error "[EXWM] Workspace index out of range: %d" index))
|
(user-error "[EXWM] Workspace index out of range: %d" index))
|
||||||
(when (or force (/= exwm-workspace-current-index index))
|
(when (or force (/= exwm-workspace-current-index index))
|
||||||
(let ((frame (elt exwm-workspace--list index)))
|
(let ((frame (elt exwm-workspace--list index)))
|
||||||
|
@ -163,7 +164,7 @@ The optional FORCE option is for internal use only."
|
||||||
. ,(1+ exwm-workspace-current-index)))))
|
. ,(1+ exwm-workspace-current-index)))))
|
||||||
(cl-position idx exwm-workspace--switch-history :test 'equal))))
|
(cl-position idx exwm-workspace--switch-history :test 'equal))))
|
||||||
(unless id (setq id (exwm--buffer->id (window-buffer))))
|
(unless id (setq id (exwm--buffer->id (window-buffer))))
|
||||||
(unless (and (<= 0 index) (< index exwm-workspace-number))
|
(unless (and (<= 0 index) (< index (length exwm-workspace--list)))
|
||||||
(user-error "[EXWM] Workspace index out of range: %d" index))
|
(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)))
|
(let ((frame (elt exwm-workspace--list index)))
|
||||||
|
@ -211,6 +212,71 @@ The optional FORCE option is for internal use only."
|
||||||
(setq newname (format "%s<%d>" basename (cl-incf counter))))
|
(setq newname (format "%s<%d>" basename (cl-incf counter))))
|
||||||
(rename-buffer (concat (and hidden " ") newname))))
|
(rename-buffer (concat (and hidden " ") newname))))
|
||||||
|
|
||||||
|
(defun exwm-workspace--add-frame-as-workspace (frame)
|
||||||
|
"Configure frame FRAME to be treated as a workspace."
|
||||||
|
(cond
|
||||||
|
((>= (length exwm-workspace--list) exwm-workspace-number)
|
||||||
|
(delete-frame frame)
|
||||||
|
(user-error "[EXWM] Too many workspaces: maximum is %d" exwm-workspace-number))
|
||||||
|
((memq frame exwm-workspace--list)
|
||||||
|
(exwm--log "Frame is already a workspace: %s" frame))
|
||||||
|
(t
|
||||||
|
(exwm--log "Adding workspace: %s" frame)
|
||||||
|
(setq exwm-workspace--list (nconc exwm-workspace--list (list frame)))
|
||||||
|
(let ((window-id (string-to-number (frame-parameter frame 'window-id)))
|
||||||
|
(outer-id (string-to-number (frame-parameter frame 'outer-window-id))))
|
||||||
|
;; Save window IDs
|
||||||
|
(set-frame-parameter frame 'exwm-window-id window-id)
|
||||||
|
(set-frame-parameter frame 'exwm-outer-id outer-id)
|
||||||
|
;; Set OverrideRedirect on all frames
|
||||||
|
(xcb:+request exwm--connection
|
||||||
|
(make-instance 'xcb:ChangeWindowAttributes
|
||||||
|
:window outer-id :value-mask xcb:CW:OverrideRedirect
|
||||||
|
:override-redirect 1))
|
||||||
|
;; Select events on all virtual roots
|
||||||
|
(xcb:+request exwm--connection
|
||||||
|
(make-instance 'xcb:ChangeWindowAttributes
|
||||||
|
:window window-id :value-mask xcb:CW:EventMask
|
||||||
|
:event-mask xcb:EventMask:SubstructureRedirect)))
|
||||||
|
(xcb:flush exwm--connection)
|
||||||
|
;; We have to delay making the frame visible until the
|
||||||
|
;; override-redirect flag has been set.
|
||||||
|
(set-frame-parameter frame 'visibility t)
|
||||||
|
(lower-frame frame)
|
||||||
|
(set-frame-parameter frame 'fullscreen 'fullboth)
|
||||||
|
;; Update EWMH properties.
|
||||||
|
(exwm-workspace--update-ewmh-props)
|
||||||
|
;; Update switch history.
|
||||||
|
(exwm-workspace--update-switch-history))))
|
||||||
|
|
||||||
|
(defun exwm-workspace--remove-frame-as-workspace (frame)
|
||||||
|
"Stop treating frame FRAME as a workspace."
|
||||||
|
(cond
|
||||||
|
((= 1 (llength exwm-workspace--list))
|
||||||
|
(exwm--log "Cannot remove last workspace"))
|
||||||
|
((not (memq frame exwm-workspace--list))
|
||||||
|
(exwm--log "Frame is not a workspace: %s" frame))
|
||||||
|
(t
|
||||||
|
(exwm--log "Removing workspace: %s" frame)
|
||||||
|
(setq exwm-workspace--list (delete frame exwm-workspace--list))
|
||||||
|
;; Update EWMH properties.
|
||||||
|
(exwm-workspace--update-ewmh-props)
|
||||||
|
;; Update switch history.
|
||||||
|
(exwm-workspace--update-switch-history))))
|
||||||
|
|
||||||
|
(defun exwm-workspace--update-ewmh-props ()
|
||||||
|
"Update EWMH properties to match the workspace list."
|
||||||
|
;; Set _NET_VIRTUAL_ROOTS
|
||||||
|
(let ((num-workspaces (exwm-workspace--count)))
|
||||||
|
(xcb:+request exwm--connection
|
||||||
|
(make-instance 'xcb:ewmh:set-_NET_VIRTUAL_ROOTS
|
||||||
|
:window exwm--root
|
||||||
|
:data (vconcat (mapcar
|
||||||
|
(lambda (i)
|
||||||
|
(frame-parameter i 'exwm-window-id))
|
||||||
|
exwm-workspace--list))))
|
||||||
|
(xcb:flush exwm--connection)))
|
||||||
|
|
||||||
(defun exwm-workspace--init ()
|
(defun exwm-workspace--init ()
|
||||||
"Initialize workspace module."
|
"Initialize workspace module."
|
||||||
(cl-assert (and (< 0 exwm-workspace-number) (>= 10 exwm-workspace-number)))
|
(cl-assert (and (< 0 exwm-workspace-number) (>= 10 exwm-workspace-number)))
|
||||||
|
@ -238,40 +304,14 @@ The optional FORCE option is for internal use only."
|
||||||
(visibility . nil))))))
|
(visibility . nil))))))
|
||||||
;; Configure workspaces
|
;; Configure workspaces
|
||||||
(dolist (i exwm-workspace--list)
|
(dolist (i exwm-workspace--list)
|
||||||
(let ((window-id (string-to-int (frame-parameter i 'window-id)))
|
(exwm-workspace--add-frame-as-workspace i))
|
||||||
(outer-id (string-to-int (frame-parameter i 'outer-window-id))))
|
|
||||||
;; Save window IDs
|
|
||||||
(set-frame-parameter i 'exwm-window-id window-id)
|
|
||||||
(set-frame-parameter i 'exwm-outer-id outer-id)
|
|
||||||
;; Set OverrideRedirect on all frames
|
|
||||||
(xcb:+request exwm--connection
|
|
||||||
(make-instance 'xcb:ChangeWindowAttributes
|
|
||||||
:window outer-id :value-mask xcb:CW:OverrideRedirect
|
|
||||||
:override-redirect 1))
|
|
||||||
;; Select events on all virtual roots
|
|
||||||
(xcb:+request exwm--connection
|
|
||||||
(make-instance 'xcb:ChangeWindowAttributes
|
|
||||||
:window window-id :value-mask xcb:CW:EventMask
|
|
||||||
:event-mask xcb:EventMask:SubstructureRedirect))))
|
|
||||||
(xcb:flush exwm--connection)
|
|
||||||
;; We have to delay making the frame visible until the
|
|
||||||
;; override-redirect flag has been set.
|
|
||||||
(select-frame-set-input-focus (car exwm-workspace--list))
|
(select-frame-set-input-focus (car exwm-workspace--list))
|
||||||
(dolist (i exwm-workspace--list)
|
|
||||||
(set-frame-parameter i 'visibility t)
|
|
||||||
(lower-frame i)
|
|
||||||
(set-frame-parameter i 'fullscreen 'fullboth))
|
|
||||||
(raise-frame (car exwm-workspace--list))
|
|
||||||
;; Handle unexpected frame switch
|
;; Handle unexpected frame switch
|
||||||
(add-hook 'focus-in-hook 'exwm-workspace--on-focus-in)
|
(add-hook 'focus-in-hook 'exwm-workspace--on-focus-in)
|
||||||
;; Set _NET_VIRTUAL_ROOTS
|
;; Make new frames create new workspaces.
|
||||||
(xcb:+request exwm--connection
|
(setq window-system-default-frame-alist '((x . ((visibility . nil)))))
|
||||||
(make-instance 'xcb:ewmh:set-_NET_VIRTUAL_ROOTS
|
(add-hook 'after-make-frame-functions #'exwm-workspace--add-frame-as-workspace)
|
||||||
:window exwm--root
|
(add-hook 'delete-frame-functions #'exwm-workspace--remove-frame-as-workspace)
|
||||||
:data (vconcat (mapcar
|
|
||||||
(lambda (i)
|
|
||||||
(frame-parameter i 'exwm-window-id))
|
|
||||||
exwm-workspace--list))))
|
|
||||||
;; Switch to the first workspace
|
;; Switch to the first workspace
|
||||||
(exwm-workspace-switch 0 t))
|
(exwm-workspace-switch 0 t))
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue