[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/exwm 33a1a28 06/14: Dissociate frame creation and delet
From: |
Chris Feng |
Subject: |
[elpa] externals/exwm 33a1a28 06/14: Dissociate frame creation and deletion handlers from the actual configuration of frames as workspaces |
Date: |
Thu, 8 Mar 2018 12:08:06 -0500 (EST) |
branch: externals/exwm
commit 33a1a284762c80dd3751ed152c872e3612b21a47
Author: Adrián Medraño Calvo <address@hidden>
Commit: Adrián Medraño Calvo <address@hidden>
Dissociate frame creation and deletion handlers from the actual
configuration of frames as workspaces
* exwm-workspace.el (exwm-workspace--add-frame-as-workspace)
(exwm-workspace--remove-frame-as-workspace): Limit functionality
to the configuration of frames as workspaces.
(exwm-workspace--on-after-make-frame)
(exwm-workspace--on-delete-frame): Callbacks run on frame creation
and deletion that may use or stop them from being used as
workspaces.
---
exwm-workspace.el | 252 ++++++++++++++++++++++++++++++------------------------
1 file changed, 139 insertions(+), 113 deletions(-)
diff --git a/exwm-workspace.el b/exwm-workspace.el
index f1ca8d5..323f5fc 100644
--- a/exwm-workspace.el
+++ b/exwm-workspace.el
@@ -1257,6 +1257,141 @@ Please check `exwm-workspace--minibuffer-own-frame-p'
first."
(defun exwm-workspace--add-frame-as-workspace (frame)
"Configure frame FRAME to be treated as a workspace."
+ (setq exwm-workspace--list (nconc exwm-workspace--list (list frame)))
+ (let ((outer-id (string-to-number (frame-parameter frame
+ 'outer-window-id)))
+ (window-id (string-to-number (frame-parameter frame 'window-id)))
+ (container (xcb:generate-id exwm--connection)))
+ ;; Save window IDs
+ (set-frame-parameter frame 'exwm-outer-id outer-id)
+ (set-frame-parameter frame 'exwm-id window-id)
+ (set-frame-parameter frame 'exwm-container container)
+ ;; In case it's created by emacsclient.
+ (set-frame-parameter frame 'client nil)
+ ;; Copy RandR frame parameters from the first workspace to
+ ;; prevent potential problems. The values do not matter here as
+ ;; they'll be updated by the RandR module later.
+ (let ((w (car exwm-workspace--list)))
+ (dolist (param '(exwm-randr-output
+ exwm-geometry))
+ (set-frame-parameter frame param (frame-parameter w param))))
+ (xcb:+request exwm--connection
+ (make-instance 'xcb:CreateWindow
+ :depth 0
+ :wid container
+ :parent exwm--root
+ :x -1
+ :y -1
+ :width 1
+ :height 1
+ :border-width 0
+ :class xcb:WindowClass:InputOutput
+ :visual 0
+ :value-mask (logior xcb:CW:BackPixmap
+ xcb:CW:OverrideRedirect)
+ :background-pixmap xcb:BackPixmap:ParentRelative
+ :override-redirect 1))
+ (xcb:+request exwm--connection
+ (make-instance 'xcb:ConfigureWindow
+ :window container
+ :value-mask xcb:ConfigWindow:StackMode
+ :stack-mode xcb:StackMode:Below))
+ (exwm--debug
+ (xcb:+request exwm--connection
+ (make-instance 'xcb:ewmh:set-_NET_WM_NAME
+ :window container
+ :data
+ (format "EXWM workspace %d frame container"
+ (exwm-workspace--position frame)))))
+ (xcb:+request exwm--connection
+ (make-instance 'xcb:ReparentWindow
+ :window outer-id :parent container :x 0 :y 0))
+ (xcb:+request exwm--connection
+ (make-instance 'xcb:MapWindow :window container)))
+ (xcb:flush exwm--connection)
+ ;; Delay making the workspace fullscreen until Emacs becomes idle
+ (exwm--defer 0 #'set-frame-parameter frame 'fullscreen 'fullboth)
+ ;; Update EWMH properties.
+ (exwm-workspace--update-ewmh-props)
+ (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)
+ "Stop treating frame FRAME as a workspace."
+ ;; TODO: restore all frame parameters (e.g. exwm-workspace, buffer-predicate,
+ ;; etc)
+ (exwm--log "Removing frame `%s' as workspace" frame)
+ (let* ((index (exwm-workspace--position frame))
+ (lastp (= index (1- (exwm-workspace--count))))
+ (nextw (elt exwm-workspace--list (+ index (if lastp -1 +1)))))
+ ;; Need to remove the workspace from the list in order for
+ ;; the correct calculation of indexes.
+ (setq exwm-workspace--list (delete frame exwm-workspace--list))
+ ;; Clients need to be moved to some other workspace before this is being
+ ;; removed.
+ (dolist (pair exwm--id-buffer-alist)
+ (with-current-buffer (cdr pair)
+ (when (eq exwm--frame frame)
+ (exwm-workspace-move-window nextw exwm--id))))
+ ;; Update the _NET_WM_DESKTOP property of each X window affected.
+ (dolist (pair exwm--id-buffer-alist)
+ (when (<= (1- index)
+ (exwm-workspace--position (buffer-local-value 'exwm--frame
+ (cdr pair))))
+ (exwm-workspace--set-desktop (car pair))))
+ ;; If the current workspace is deleted, switch to next one.
+ (when (eq frame exwm-workspace--current)
+ (exwm-workspace-switch nextw)))
+ ;; Reparent out the frame.
+ (let ((outer-id (frame-parameter frame 'exwm-outer-id)))
+ (xcb:+request exwm--connection
+ (make-instance 'xcb:UnmapWindow
+ :window outer-id))
+ (xcb:+request exwm--connection
+ (make-instance 'xcb:ReparentWindow
+ :window outer-id
+ :parent exwm--root
+ :x 0
+ :y 0))
+ ;; Reset the override-redirect.
+ (xcb:+request exwm--connection
+ (make-instance 'xcb:ChangeWindowAttributes
+ :window outer-id
+ :value-mask xcb:CW:OverrideRedirect
+ :override-redirect 0))
+ (xcb:+request exwm--connection
+ (make-instance 'xcb:MapWindow
+ :window outer-id)))
+ ;; Destroy the container.
+ (xcb:+request exwm--connection
+ (make-instance 'xcb:DestroyWindow
+ :window (frame-parameter frame 'exwm-container)))
+ (xcb:flush exwm--connection)
+ ;; Update EWMH properties.
+ (exwm-workspace--update-ewmh-props)
+ ;; Update switch history.
+ (setq exwm-workspace--switch-history-outdated t)
+ (run-hooks 'exwm-workspace-list-change-hook))
+
+(defun exwm-workspace--on-delete-frame (frame)
+ "Hook run upon `delete-frame' that tears down FRAME's configuration as a
workspace."
+ (cond
+ ((not (exwm-workspace--workspace-p frame))
+ (exwm--log "Frame `%s' is not a workspace" frame))
+ (t
+ (when (= 1 (exwm-workspace--count))
+ ;; The user managed to delete the last workspace, so create a new one.
+ (exwm--log "Last workspace deleted; create a new one")
+ ;; TODO: this makes sense in the hook. But we need a function that takes
+ ;; care of converting a workspace into a regular unmanaged frame.
+ (let ((exwm-workspace--create-silently t))
+ (make-frame)))
+ (exwm-workspace--remove-frame-as-workspace frame))))
+
+(defun exwm-workspace--on-after-make-frame (frame)
+ "Hook run upon `delete-frame' that configures FRAME as a workspace."
(cond
((exwm-workspace--workspace-p frame)
(exwm--log "Frame `%s' is already a workspace" frame))
@@ -1278,116 +1413,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)))
- (let ((outer-id (string-to-number (frame-parameter frame
- 'outer-window-id)))
- (window-id (string-to-number (frame-parameter frame 'window-id)))
- (container (xcb:generate-id exwm--connection)))
- ;; Save window IDs
- (set-frame-parameter frame 'exwm-outer-id outer-id)
- (set-frame-parameter frame 'exwm-id window-id)
- (set-frame-parameter frame 'exwm-container container)
- ;; In case it's created by emacsclient.
- (set-frame-parameter frame 'client nil)
- ;; Copy RandR frame parameters from the first workspace to
- ;; prevent potential problems. The values do not matter here as
- ;; they'll be updated by the RandR module later.
- (let ((w (car exwm-workspace--list)))
- (dolist (param '(exwm-randr-output
- exwm-geometry))
- (set-frame-parameter frame param (frame-parameter w param))))
- (xcb:+request exwm--connection
- (make-instance 'xcb:CreateWindow
- :depth 0
- :wid container
- :parent exwm--root
- :x -1
- :y -1
- :width 1
- :height 1
- :border-width 0
- :class xcb:WindowClass:InputOutput
- :visual 0
- :value-mask (logior xcb:CW:BackPixmap
- xcb:CW:OverrideRedirect)
- :background-pixmap xcb:BackPixmap:ParentRelative
- :override-redirect 1))
- (xcb:+request exwm--connection
- (make-instance 'xcb:ConfigureWindow
- :window container
- :value-mask xcb:ConfigWindow:StackMode
- :stack-mode xcb:StackMode:Below))
- (exwm--debug
- (xcb:+request exwm--connection
- (make-instance 'xcb:ewmh:set-_NET_WM_NAME
- :window container
- :data
- (format "EXWM workspace %d frame container"
- (exwm-workspace--position frame)))))
- (xcb:+request exwm--connection
- (make-instance 'xcb:ReparentWindow
- :window outer-id :parent container :x 0 :y 0))
- (xcb:+request exwm--connection
- (make-instance 'xcb:MapWindow :window container)))
- (xcb:flush exwm--connection)
- ;; Delay making the workspace fullscreen until Emacs becomes idle
- (exwm--defer 0 #'set-frame-parameter frame 'fullscreen 'fullboth)
- ;; Update EWMH properties.
- (exwm-workspace--update-ewmh-props)
- (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)
- "Stop treating frame FRAME as a workspace."
- (cond
- ((not (exwm-workspace--workspace-p frame))
- (exwm--log "Frame `%s' is not a workspace" frame))
- (t
- (exwm--log "Removing frame `%s' as workspace" frame)
- (when (= 1 (exwm-workspace--count))
- ;; The user managed to delete the last workspace, so create a new one.
- (exwm--log "Last workspace deleted; create a new one")
- (let ((exwm-workspace--create-silently t))
- (make-frame)))
- (let* ((index (exwm-workspace--position frame))
- (lastp (= index (1- (exwm-workspace--count))))
- (nextw (elt exwm-workspace--list (+ index (if lastp -1 +1)))))
- ;; Need to remove the workspace from the list in order for
- ;; the correct calculation of indexes.
- (setq exwm-workspace--list (delete frame exwm-workspace--list))
- ;; Clients need to be moved to some other workspace before this is being
- ;; removed.
- (dolist (pair exwm--id-buffer-alist)
- (with-current-buffer (cdr pair)
- (when (eq exwm--frame frame)
- (exwm-workspace-move-window nextw exwm--id))))
- ;; Update the _NET_WM_DESKTOP property of each X window affected.
- (dolist (pair exwm--id-buffer-alist)
- (when (<= (1- index)
- (exwm-workspace--position (buffer-local-value 'exwm--frame
- (cdr pair))))
- (exwm-workspace--set-desktop (car pair))))
- ;; If the current workspace is deleted, switch to next one.
- (when (eq frame exwm-workspace--current)
- (exwm-workspace-switch nextw)))
- ;; Reparent out the frame.
- (xcb:+request exwm--connection
- (make-instance 'xcb:ReparentWindow
- :window (frame-parameter frame 'exwm-outer-id)
- :parent exwm--root
- :x 0
- :y 0))
- ;; Destroy the container.
- (xcb:+request exwm--connection
- (make-instance 'xcb:DestroyWindow
- :window (frame-parameter frame 'exwm-container)))
- ;; Update EWMH properties.
- (exwm-workspace--update-ewmh-props)
- ;; Update switch history.
- (setq exwm-workspace--switch-history-outdated t)
- (run-hooks 'exwm-workspace-list-change-hook))))
+ (exwm-workspace--add-frame-as-workspace frame))))
(defun exwm-workspace--update-ewmh-props ()
"Update EWMH properties to match the workspace list."
@@ -1546,7 +1572,7 @@ applied to all subsequently created X frames."
(advice-add 'handle-focus-out :around #'exwm-workspace--handle-focus-out)
;; Make new frames create new workspaces.
(add-hook 'after-make-frame-functions
- #'exwm-workspace--add-frame-as-workspace)
+ #'exwm-workspace--on-after-make-frame)
(add-hook 'delete-frame-functions
#'exwm-workspace--remove-frame-as-workspace)
;; Switch to the first workspace
@@ -1579,9 +1605,9 @@ applied to all subsequently created X frames."
(advice-remove 'handle-focus-in #'exwm-workspace--handle-focus-in)
(advice-remove 'handle-focus-out #'exwm-workspace--handle-focus-out)
(remove-hook 'after-make-frame-functions
- #'exwm-workspace--add-frame-as-workspace)
+ #'exwm-workspace--on-after-make-frame)
(remove-hook 'delete-frame-functions
- #'exwm-workspace--remove-frame-as-workspace))
+ #'exwm-workspace--on-delete-frame))
(defun exwm-workspace--post-init ()
"The second stage in the initialization of the workspace module."
- [elpa] externals/exwm 4f7abf4 04/14: Cleanup exwm-manage on exit, (continued)
- [elpa] externals/exwm 4f7abf4 04/14: Cleanup exwm-manage on exit, Chris Feng, 2018/03/08
- [elpa] externals/exwm a2b6cfb 08/14: * exwm.el (exwm--exit): Drop SubstructureRedirect on root window., Chris Feng, 2018/03/08
- [elpa] externals/exwm 81529c2 02/14: Cleanup exwm-input on exit, Chris Feng, 2018/03/08
- [elpa] externals/exwm ce8af83 09/14: Disconnect on `exwm--exit', Chris Feng, 2018/03/08
- [elpa] externals/exwm 350950a 12/14: Clean up when failing to start, Chris Feng, 2018/03/08
- [elpa] externals/exwm a51be88 07/14: Cleanup exwm-workspace on exit, Chris Feng, 2018/03/08
- [elpa] externals/exwm cf98e3d 11/14: Name all helper windows created by EXWM, Chris Feng, 2018/03/08
- [elpa] externals/exwm 587a8ca 10/14: Add interactive commands for starting and stopping EXWM, Chris Feng, 2018/03/08
- [elpa] externals/exwm 7aae6ef 13/14: Support replacing and being replaced by other window managers, Chris Feng, 2018/03/08
- [elpa] externals/exwm 2f430db 14/14: Minor fixes, Chris Feng, 2018/03/08
- [elpa] externals/exwm 33a1a28 06/14: Dissociate frame creation and deletion handlers from the actual configuration of frames as workspaces,
Chris Feng <=