From 1e78045f958edbb2f3ef7c21953f8b55b3bbae42 Mon Sep 17 00:00:00 2001 From: Chris Feng Date: Sat, 30 Jul 2016 19:01:33 +0800 Subject: [PATCH] Add restart support * exwm-input.el (exwm-input--exit): Cancel timers. * exwm-manage.el (exwm-manage--manage-window): Add reparented X windows to save-set. * exwm-systemtray.el (exwm-systemtray--embed): Add embeded icons to save-set. * exwm-workspace.el (exwm-workspace--confirm-kill-emacs): No need to unmanage; also hide Emacs frames; always call `exwm--exit'. * exwm.el (exwm-restart): New command for restarting EXWM. (exwm--exit-icccm-ewmh): New function for cleaning up ICCCM/EWMH properties. (exwm-exit-hook): Update doc string. (exwm--exit): Call `exwm--exit-icccm-ewmh' and do not reset variables. --- exwm-input.el | 6 ++++- exwm-manage.el | 5 ++++ exwm-systemtray.el | 5 ++++ exwm-workspace.el | 65 +++++++++++++++++++++++----------------------- exwm.el | 49 +++++++++++++++++++++++++++------- 5 files changed, 87 insertions(+), 43 deletions(-) diff --git a/exwm-input.el b/exwm-input.el index f7a6704..555cc87 100644 --- a/exwm-input.el +++ b/exwm-input.el @@ -659,7 +659,11 @@ Its usage is the same with `exwm-input-set-simulation-keys'." (remove-hook 'post-command-hook #'exwm-input--on-post-command) (remove-hook 'buffer-list-update-hook #'exwm-input--on-buffer-list-update) (remove-hook 'exwm-workspace-list-change-hook - #'exwm-input--update-global-prefix-keys)) + #'exwm-input--update-global-prefix-keys) + (when exwm-input--update-focus-defer-timer + (cancel-timer exwm-input--update-focus-defer-timer)) + (when exwm-input--update-focus-timer + (cancel-timer exwm-input--update-focus-timer))) diff --git a/exwm-manage.el b/exwm-manage.el index 16abe98..0b7b475 100644 --- a/exwm-manage.el +++ b/exwm-manage.el @@ -112,6 +112,11 @@ corresponding buffer.") :window id :value-mask xcb:CW:EventMask :event-mask exwm--client-event-mask)) (throw 'return 'dead)) + ;; Add this X window to save-set. + (xcb:+request exwm--connection + (make-instance 'xcb:ChangeSaveSet + :mode xcb:SetMode:Insert + :window id)) (with-current-buffer (generate-new-buffer "*EXWM*") ;; Keep the oldest X window first. (setq exwm--id-buffer-alist diff --git a/exwm-systemtray.el b/exwm-systemtray.el index 56e5fb8..25f5fa5 100644 --- a/exwm-systemtray.el +++ b/exwm-systemtray.el @@ -89,6 +89,11 @@ You shall use the default value if using auto-hide minibuffer.") height* (round (* height (/ (float width*) width))))) (exwm--log "(System Tray) Resize from %dx%d to %dx%d" width height width* height*)) + ;; Add this icon to save-set. + (xcb:+request exwm-systemtray--connection + (make-instance 'xcb:ChangeSaveSet + :mode xcb:SetMode:Insert + :window icon)) ;; Reparent to the embedder. (xcb:+request exwm-systemtray--connection (make-instance 'xcb:ReparentWindow diff --git a/exwm-workspace.el b/exwm-workspace.el index ce2ed6f..b73059a 100644 --- a/exwm-workspace.el +++ b/exwm-workspace.el @@ -1045,47 +1045,46 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first." (0 (y-or-n-p prompt)) (x (yes-or-no-p (format "[EXWM] %d window%s currently alive. %s" x (if (= x 1) "" "s") prompt)))) - ;; Unmanage all X windows. - (dolist (i exwm--id-buffer-alist) - (exwm-manage--unmanage-window (car i) 'quit) - (xcb:+request exwm--connection - (make-instance 'xcb:MapWindow :window (car i)))) - ;; Reparent out the minibuffer frame. + ;; Hide & reparent out all frames (save-set can't be used here since + ;; X windows will be re-mapped). (when (exwm-workspace--minibuffer-own-frame-p) - (xcb:+request exwm--connection - (make-instance 'xcb:ReparentWindow - :window (frame-parameter exwm-workspace--minibuffer - 'exwm-outer-id) - :parent exwm--root - :x 0 - :y 0))) - ;; Reparent out all workspace frames. + (let ((id (frame-parameter exwm-workspace--minibuffer 'exwm-outer-id))) + (xcb:+request exwm--connection + (make-instance 'xcb:UnmapWindow + :window id)) + (xcb:+request exwm--connection + (make-instance 'xcb:ReparentWindow + :window id + :parent exwm--root + :x 0 + :y 0)))) (dolist (f exwm-workspace--list) - (xcb:+request exwm--connection - (make-instance 'xcb:ReparentWindow - :window (frame-parameter f 'exwm-outer-id) - :parent exwm--root - :x 0 - :y 0))) - (xcb:flush exwm--connection) - (if (not exwm-workspace--client) - (progn - ;; Destroy all resources created by this connection. - (xcb:disconnect exwm--connection) - t) - ;; Extra cleanups for emacsclient. + (let ((id (frame-parameter f 'exwm-outer-id))) + (xcb:+request exwm--connection + (make-instance 'xcb:UnmapWindow + :window id)) + (xcb:+request exwm--connection + (make-instance 'xcb:ReparentWindow + :window id + :parent exwm--root + :x 0 + :y 0)))) + ;; Exit each module. + (exwm--exit) + ;; Destroy all resources created by this connection. + (xcb:disconnect exwm--connection) + (setq exwm--connection nil) + ;; Extra cleanups for emacsclient. + (when exwm-workspace--client (dolist (f exwm-workspace--list) (set-frame-parameter f 'client exwm-workspace--client)) (when (exwm-workspace--minibuffer-own-frame-p) (set-frame-parameter exwm-workspace--minibuffer 'client exwm-workspace--client)) - (let ((connection exwm--connection)) - (exwm--exit) - ;; Destroy all resources created by this connection. - (xcb:disconnect connection)) ;; Kill the client. - (server-save-buffers-kill-terminal nil) - nil))) + (server-save-buffers-kill-terminal nil)) + ;; Set the return value. + (not exwm-workspace--client))) (defun exwm-workspace--set-desktop-geometry () "Set _NET_DESKTOP_GEOMETRY." diff --git a/exwm.el b/exwm.el index 692c863..b04990b 100644 --- a/exwm.el +++ b/exwm.el @@ -83,6 +83,20 @@ (exwm-layout--refresh) (call-interactively #'exwm-input-grab-keyboard)))) +;;;###autoload +(defun exwm-restart () + "Restart EXWM." + (interactive) + (when (exwm-workspace--confirm-kill-emacs "[EXWM] Restart? ") + (server-force-delete) + (run-hooks 'kill-emacs-hook) + ;; FIXME: more? + (apply #'call-process (car command-line-args) nil nil nil + (cdr command-line-args)) + ;; Kill this instance at last. + (let ((kill-emacs-hook nil)) + (kill-emacs)))) + (defun exwm--update-window-type (id &optional force) "Update _NET_WM_WINDOW_TYPE." (with-current-buffer (exwm--id->buffer id) @@ -597,6 +611,30 @@ :window i :data "EXWM")))) (xcb:flush exwm--connection)) +(defun exwm--exit-icccm-ewmh () + "Remove ICCCM/EWMH properties." + (dolist (p (list + xcb:Atom:_NET_WM_NAME + xcb:Atom:_NET_SUPPORTED + xcb:Atom:_NET_CLIENT_LIST + xcb:Atom:_NET_CLIENT_LIST_STACKING + xcb:Atom:_NET_NUMBER_OF_DESKTOPS + xcb:Atom:_NET_DESKTOP_GEOMETRY + xcb:Atom:_NET_DESKTOP_VIEWPORT + xcb:Atom:_NET_CURRENT_DESKTOP + xcb:Atom:_NET_ACTIVE_WINDOW + xcb:Atom:_NET_WORKAREA + xcb:Atom:_NET_SUPPORTING_WM_CHECK + xcb:Atom:_NET_VIRTUAL_ROOTS + ;; TODO: Keep this list synchronized with that in + ;; `exwm--init-icccm-ewmh'. + )) + (xcb:+request exwm--connection + (make-instance 'xcb:DeleteProperty + :window exwm--root + :property p)) + (xcb:flush exwm--connection))) + (defvar exwm-init-hook nil "Normal hook run when EXWM has just finished initialization.") @@ -643,10 +681,7 @@ (exwm-manage--scan) (run-hooks 'exwm-init-hook))))) -(defvar exwm-exit-hook nil - "Normal hook run just before EXWM is about to exit. - -This hook is only run when EXWM is started with emacsclient.") +(defvar exwm-exit-hook nil "Normal hook run just before EXWM exits.") (defun exwm--exit () "Exit EXWM." @@ -657,11 +692,7 @@ This hook is only run when EXWM is started with emacsclient.") (exwm-manage--exit) (exwm-floating--exit) (exwm-layout--exit) - ;; Reset several import variables. - (setq exwm--connection nil - exwm--root nil - exwm--id-buffer-alist nil) - (exwm-enable)) + (exwm--exit-icccm-ewmh)) (defvar exwm-blocking-subrs '(x-file-dialog x-popup-dialog x-select-font) "Subrs (primitives) that would normally block EXWM.")