From e7ff9a9f90f0356a9ab8a9ca3857df03deeb1696 Mon Sep 17 00:00:00 2001 From: Chris Feng Date: Mon, 1 Aug 2016 19:49:43 +0800 Subject: [PATCH] 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. --- exwm-workspace.el | 55 +++++++++++++++++++++++++++++++---------------- exwm.el | 27 +++++++++++++++++++---- 2 files changed, 59 insertions(+), 23 deletions(-) diff --git a/exwm-workspace.el b/exwm-workspace.el index 7c2601a..097a950 100644 --- a/exwm-workspace.el +++ b/exwm-workspace.el @@ -25,6 +25,8 @@ ;;; Code: +(require 'server) + (require 'exwm-core) (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) "Confirm before exiting Emacs." - (when (or (and force (not (eq force 'no-check))) - (and (or (eq force 'no-check) (not exwm--id-buffer-alist)) - (y-or-n-p prompt)) - (yes-or-no-p (format "[EXWM] %d window(s) will be destroyed. %s" - (length exwm--id-buffer-alist) prompt))) - ;; Run `kill-emacs-hook' before Emacs frames are unmapped so that - ;; errors can be visible. - (run-hooks 'kill-emacs-hook) - (setq kill-emacs-hook nil) + (when (cond + ((and force (not (eq force 'no-check))) + ;; Force killing Emacs. + t) + ((or (eq force 'no-check) (not exwm--id-buffer-alist)) + ;; Check if there's any unsaved file. + (pcase (catch 'break + (let ((kill-emacs-query-functions + (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 ;; X windows will be re-mapped). (when (exwm-workspace--minibuffer-own-frame-p) @@ -1079,22 +1098,20 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first." :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. + ;; Restore the 'client' frame parameter (before `exwm--exit'). (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)) - ;; Kill the client. - (server-save-buffers-kill-terminal nil)) + exwm-workspace--client))) + ;; Exit each module. + (exwm--exit) + ;; Destroy all resources created by this connection. + (xcb:disconnect exwm--connection) + (setq exwm--connection nil) ;; Set the return value. - (not exwm-workspace--client))) + t)) (defun exwm-workspace--set-desktop-geometry () "Set _NET_DESKTOP_GEOMETRY." diff --git a/exwm.el b/exwm.el index 861d51a..dd279bb 100644 --- a/exwm.el +++ b/exwm.el @@ -88,10 +88,29 @@ "Restart EXWM." (interactive) (when (exwm-workspace--confirm-kill-emacs "[EXWM] Restart? " 'no-check) - (apply #'call-process (car command-line-args) nil nil nil - (cdr command-line-args)) - ;; Kill this instance at last. - (kill-emacs))) + (let* ((attr (process-attributes (emacs-pid))) + (args (cdr (assq 'args attr))) + (ppid (cdr (assq 'ppid attr))) + (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) "Update _NET_WM_WINDOW_TYPE."