Fix restarting issues

* exwm-workspace.el (exwm-workspace--confirm-kill-emacs): Prompt for
unsaved files before restarting; avoid running `server-force-stop'
early; restore the 'client' frame parameter before calling `exwm--exit';
correctly handle emacsclient.

* exwm.el (exwm-restart): Always kill subordinate Emacs instances.
This commit is contained in:
Chris Feng 2016-08-01 19:49:43 +08:00
parent 173bbde885
commit e7ff9a9f90
2 changed files with 59 additions and 23 deletions

View file

@ -25,6 +25,8 @@
;;; Code: ;;; Code:
(require 'server)
(require 'exwm-core) (require 'exwm-core)
(defvar exwm-workspace-number 1 "Initial number of workspaces.") (defvar exwm-workspace-number 1 "Initial number of workspaces.")
@ -1046,15 +1048,32 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first."
(defun exwm-workspace--confirm-kill-emacs (prompt &optional force) (defun exwm-workspace--confirm-kill-emacs (prompt &optional force)
"Confirm before exiting Emacs." "Confirm before exiting Emacs."
(when (or (and force (not (eq force 'no-check))) (when (cond
(and (or (eq force 'no-check) (not exwm--id-buffer-alist)) ((and force (not (eq force 'no-check)))
(y-or-n-p prompt)) ;; Force killing Emacs.
(yes-or-no-p (format "[EXWM] %d window(s) will be destroyed. %s" t)
(length exwm--id-buffer-alist) prompt))) ((or (eq force 'no-check) (not exwm--id-buffer-alist))
;; Run `kill-emacs-hook' before Emacs frames are unmapped so that ;; Check if there's any unsaved file.
;; errors can be visible. (pcase (catch 'break
(run-hooks 'kill-emacs-hook) (let ((kill-emacs-query-functions
(setq kill-emacs-hook nil) (append kill-emacs-query-functions
(list (lambda ()
(throw 'break 'break))))))
(save-buffers-kill-emacs)))
(`break (y-or-n-p prompt))
(x x)))
(t
(yes-or-no-p (format "[EXWM] %d window(s) will be destroyed. %s"
(length exwm--id-buffer-alist) prompt))))
;; Run `kill-emacs-hook' (`server-force-stop' excluded) before Emacs
;; frames are unmapped so that errors (if any) can be visible.
(if (memq #'server-force-stop kill-emacs-hook)
(progn
(setq kill-emacs-hook (delq #'server-force-stop kill-emacs-hook))
(run-hooks 'kill-emacs-hook)
(setq kill-emacs-hook (list #'server-force-stop)))
(run-hooks 'kill-emacs-hook)
(setq kill-emacs-hook nil))
;; Hide & reparent out all frames (save-set can't be used here since ;; Hide & reparent out all frames (save-set can't be used here since
;; X windows will be re-mapped). ;; X windows will be re-mapped).
(when (exwm-workspace--minibuffer-own-frame-p) (when (exwm-workspace--minibuffer-own-frame-p)
@ -1079,22 +1098,20 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first."
:parent exwm--root :parent exwm--root
:x 0 :x 0
:y 0)))) :y 0))))
;; Exit each module. ;; Restore the 'client' frame parameter (before `exwm--exit').
(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 (when exwm-workspace--client
(dolist (f exwm-workspace--list) (dolist (f exwm-workspace--list)
(set-frame-parameter f 'client exwm-workspace--client)) (set-frame-parameter f 'client exwm-workspace--client))
(when (exwm-workspace--minibuffer-own-frame-p) (when (exwm-workspace--minibuffer-own-frame-p)
(set-frame-parameter exwm-workspace--minibuffer 'client (set-frame-parameter exwm-workspace--minibuffer 'client
exwm-workspace--client)) exwm-workspace--client)))
;; Kill the client. ;; Exit each module.
(server-save-buffers-kill-terminal nil)) (exwm--exit)
;; Destroy all resources created by this connection.
(xcb:disconnect exwm--connection)
(setq exwm--connection nil)
;; Set the return value. ;; Set the return value.
(not exwm-workspace--client))) t))
(defun exwm-workspace--set-desktop-geometry () (defun exwm-workspace--set-desktop-geometry ()
"Set _NET_DESKTOP_GEOMETRY." "Set _NET_DESKTOP_GEOMETRY."

27
exwm.el
View file

@ -88,10 +88,29 @@
"Restart EXWM." "Restart EXWM."
(interactive) (interactive)
(when (exwm-workspace--confirm-kill-emacs "[EXWM] Restart? " 'no-check) (when (exwm-workspace--confirm-kill-emacs "[EXWM] Restart? " 'no-check)
(apply #'call-process (car command-line-args) nil nil nil (let* ((attr (process-attributes (emacs-pid)))
(cdr command-line-args)) (args (cdr (assq 'args attr)))
;; Kill this instance at last. (ppid (cdr (assq 'ppid attr)))
(kill-emacs))) (pargs (cdr (assq 'args (process-attributes ppid)))))
(cond
((= ppid 1)
;; The parent is the init process. This probably means this
;; instance is an emacsclient. Anyway, start a control instance
;; to manage the subsequent ones.
(call-process (car command-line-args))
(kill-emacs))
((string= args pargs)
;; This is a subordinate instance. Return a magic number to
;; inform the parent (control instance) to start another one.
(kill-emacs ?R))
(t
;; This is the control instance. Keep starting subordinate
;; instances until told to exit.
;; Run `server-force-stop' if it exists.
(run-hooks 'kill-emacs-hook)
(with-temp-buffer
(while (= ?R (shell-command-on-region (point) (point) args))))
(kill-emacs))))))
(defun exwm--update-window-type (id &optional force) (defun exwm--update-window-type (id &optional force)
"Update _NET_WM_WINDOW_TYPE." "Update _NET_WM_WINDOW_TYPE."