branch: externals/exwm
commit 1b2ae3749e98b83f94cc19cef8830ce823c63367
Author: Chris Feng <chris.w.f...@gmail.com>
Commit: Chris Feng <chris.w.f...@gmail.com>

    Add cleanup codes for Emacs daemon
    
    * exwm-floating.el (exwm-floating--exit):
    * exwm-input.el (exwm-input--exit):
    * exwm-layout.el (exwm-layout--exit):
    * exwm-manage.el (exwm-manage--exit):
    * exwm-randr.el (exwm-randr--exit):
    * exwm-systemtray.el (exwm-systemtray--exit):
    * exwm-workspace.el (exwm-workspace--exit):
    New functions for cleanup each module.
    
    * exwm-input.el (exwm-input--on-pre-command, exwm-input--on-post-command)
    (exwm-input--init): Name lambda functions.
    
    * exwm-layout.el (exwm-layout--timer, exwm-layout--init): Save timer.
    
    * exwm-randr.el (exwm-randr-enable): Register the cleanup function.
    
    * exwm-systemtray.el (exwm-systemtray--init): Force refresh atoms in XEMBED
    and system tray protocols.
    (exwm-systemtray-enable): Register the cleanup function.
    
    * exwm-workspace.el (exwm-workspace--client): Save the server process.
    (exwm-workspace--confirm-kill-emacs): Add emacsclient-specific
    cleanup codes.
    (exwm-workspace--timer): Save the timer.
    (exwm-workspace--init): Save the server process and timer;
    fix problems with emacsclient frames.
    
    * exwm.el (exwm-init): Always select the newly created frame;
    force refresh ICCCM & EWMH atoms.
    (exwm-exit-hook): New hook for holding cleanup codes.
    (exwm--exit): Run `exwm-exit-hook', execute cleanup codes for
    each module and reset the environment.
---
 exwm-floating.el   |    3 +++
 exwm-input.el      |   20 ++++++++++++---
 exwm-layout.el     |   14 ++++++++++-
 exwm-manage.el     |    4 +++
 exwm-randr.el      |    6 ++++-
 exwm-systemtray.el |   24 +++++++++++++++---
 exwm-workspace.el  |   70 ++++++++++++++++++++++++++++++++++++++++++++--------
 exwm.el            |   30 +++++++++++++++++++---
 8 files changed, 149 insertions(+), 22 deletions(-)

diff --git a/exwm-floating.el b/exwm-floating.el
index 770976d..b3a5b18 100644
--- a/exwm-floating.el
+++ b/exwm-floating.el
@@ -622,6 +622,9 @@ Both DELTA-X and DELTA-Y default to 1.  This command should 
be bound locally."
         exwm-floating--cursor-left
         (xcb:cursor:load-cursor exwm--connection "left_side")))
 
+(defun exwm-floating--exit ()
+  "Exit the floating module.")
+
 
 
 (provide 'exwm-floating)
diff --git a/exwm-input.el b/exwm-input.el
index dc7f2b5..4bf2cd1 100644
--- a/exwm-input.el
+++ b/exwm-input.el
@@ -476,6 +476,14 @@ SIMULATION-KEYS is an alist of the form (original-key . 
simulated-key)."
         (dolist (j pair)
           (exwm-input--fake-key j))))))
 
+(defun exwm-input--on-pre-command ()
+  "Run in `pre-command-hook'."
+  (setq exwm-input--during-command t))
+
+(defun exwm-input--on-post-command ()
+  "Run in `post-command-hook'."
+  (setq exwm-input--during-command nil))
+
 (declare-function exwm-floating--stop-moveresize "exwm-floating.el"
                   (&rest _args))
 (declare-function exwm-floating--do-moveresize "exwm-floating.el"
@@ -510,14 +518,20 @@ SIMULATION-KEYS is an alist of the form (original-key . 
simulated-key)."
   ;; `pre-command-hook' marks the end of a key sequence (existing or not)
   (add-hook 'pre-command-hook #'exwm-input--finish-key-sequence)
   ;; Control `exwm-input--during-command'
-  (add-hook 'pre-command-hook (lambda () (setq exwm-input--during-command t)))
-  (add-hook 'post-command-hook
-            (lambda () (setq exwm-input--during-command nil)))
+  (add-hook 'pre-command-hook #'exwm-input--on-pre-command)
+  (add-hook 'post-command-hook #'exwm-input--on-post-command)
   ;; Update focus when buffer list updates
   (add-hook 'buffer-list-update-hook #'exwm-input--on-buffer-list-update)
   ;; Update prefix keys for global keys
   (exwm-input--update-global-prefix-keys))
 
+(defun exwm-input--exit ()
+  "Exit the input module."
+  (remove-hook 'pre-command-hook #'exwm-input--finish-key-sequence)
+  (remove-hook 'pre-command-hook #'exwm-input--on-pre-command)
+  (remove-hook 'post-command-hook #'exwm-input--on-post-command)
+  (remove-hook 'buffer-list-update-hook #'exwm-input--on-buffer-list-update))
+
 
 
 (provide 'exwm-input)
diff --git a/exwm-layout.el b/exwm-layout.el
index 9cbdd2b..0069767 100644
--- a/exwm-layout.el
+++ b/exwm-layout.el
@@ -528,6 +528,8 @@ See also `exwm-layout-enlarge-window'."
         (exwm-layout-hide-mode-line)
       (exwm-layout-show-mode-line))))
 
+(defvar exwm-layout--timer nil "Timer used to track echo area changes.")
+
 (defun exwm-layout--init ()
   "Initialize layout module."
   ;; Auto refresh layout
@@ -535,9 +537,19 @@ See also `exwm-layout-enlarge-window'."
   (unless (exwm-workspace--minibuffer-own-frame-p)
     ;; Refresh when minibuffer grows
     (add-hook 'minibuffer-setup-hook #'exwm-layout--on-minibuffer-setup t)
-    (run-with-idle-timer 0 t #'exwm-layout--on-echo-area-change t)
+    (setq exwm-layout--timer
+          (run-with-idle-timer 0 t #'exwm-layout--on-echo-area-change t))
     (add-hook 'echo-area-clear-hook #'exwm-layout--on-echo-area-change)))
 
+(defun exwm-layout--exit ()
+  "Exit the layout module."
+  (remove-hook 'window-configuration-change-hook #'exwm-layout--refresh)
+  (remove-hook 'minibuffer-setup-hook #'exwm-layout--on-minibuffer-setup)
+  (when exwm-layout--timer
+    (cancel-timer exwm-layout--timer)
+    (setq exwm-layout--timer nil))
+  (remove-hook 'echo-area-clear-hook #'exwm-layout--on-echo-area-change))
+
 
 
 (provide 'exwm-layout)
diff --git a/exwm-manage.el b/exwm-manage.el
index 1877033..1c63134 100644
--- a/exwm-manage.el
+++ b/exwm-manage.el
@@ -555,6 +555,10 @@ border-width: %d; sibling: #x%x; stack-mode: %d"
   (xcb:+event exwm--connection 'xcb:DestroyNotify
               #'exwm-manage--on-DestroyNotify))
 
+(defun exwm-manage--exit ()
+  "Exit the manage module."
+  (setq exwm-manage--_MOTIF_WM_HINTS nil))
+
 
 
 (provide 'exwm-manage)
diff --git a/exwm-randr.el b/exwm-randr.el
index e761d8f..0e4469d 100644
--- a/exwm-randr.el
+++ b/exwm-randr.el
@@ -164,9 +164,13 @@
                            ))
         (xcb:flush exwm--connection)))))
 
+(defun exwm-randr--exit ()
+  "Exit the RandR module.")
+
 (defun exwm-randr-enable ()
   "Enable RandR support for EXWM."
-  (add-hook 'exwm-init-hook #'exwm-randr--init))
+  (add-hook 'exwm-init-hook #'exwm-randr--init)
+  (add-hook 'exwm-exit-hook #'exwm-randr--exit))
 
 
 
diff --git a/exwm-systemtray.el b/exwm-systemtray.el
index cb08ba9..d1783de 100644
--- a/exwm-systemtray.el
+++ b/exwm-systemtray.el
@@ -311,8 +311,8 @@ You shall use the default value if using auto-hide 
minibuffer.")
                                               'process)
                                   nil)
   ;; Initialize XELB modules.
-  (xcb:xembed:init exwm-systemtray--connection)
-  (xcb:systemtray:init exwm-systemtray--connection)
+  (xcb:xembed:init exwm-systemtray--connection t)
+  (xcb:systemtray:init exwm-systemtray--connection t)
   ;; Acquire the manager selection _NET_SYSTEM_TRAY_S0.
   (with-slots (owner)
       (xcb:+request-unchecked+reply exwm-systemtray--connection
@@ -399,11 +399,27 @@ You shall use the default value if using auto-hide 
minibuffer.")
               #'exwm-systemtray--on-ClientMessage)
   ;; Add hook to move/reparent the embedder.
   (add-hook 'exwm-workspace-switch-hook #'exwm-systemtray--on-workspace-switch)
-  (add-hook 'exwm-randr-refresh-hook #'exwm-systemtray--on-randr-refresh))
+  (when (boundp 'exwm-randr-refresh-hook)
+    (add-hook 'exwm-randr-refresh-hook #'exwm-systemtray--on-randr-refresh)))
+
+(defun exwm-systemtray--exit ()
+  "Exit the systemtray module."
+  (when exwm-systemtray--connection
+    (xcb:disconnect exwm-systemtray--connection)
+    (setq exwm-systemtray--connection nil
+          exwm-systemtray--list nil
+          exwm-systemtray--selection-owner-window nil
+          exwm-systemtray--embedder nil)
+    (remove-hook 'exwm-workspace-switch-hook
+                 #'exwm-systemtray--on-workspace-switch)
+    (when (boundp 'exwm-randr-refresh-hook)
+      (remove-hook 'exwm-randr-refresh-hook
+                   #'exwm-systemtray--on-randr-refresh))))
 
 (defun exwm-systemtray-enable ()
   "Enable system tray support for EXWM."
-  (add-hook 'exwm-init-hook #'exwm-systemtray--init))
+  (add-hook 'exwm-init-hook #'exwm-systemtray--init)
+  (add-hook 'exwm-exit-hook #'exwm-systemtray--exit))
 
 
 
diff --git a/exwm-workspace.el b/exwm-workspace.el
index 124c681..b61b81c 100644
--- a/exwm-workspace.el
+++ b/exwm-workspace.el
@@ -584,7 +584,11 @@ The optional FORCE option is for internal use only."
       (cancel-timer exwm-workspace--display-echo-area-timer)
       (setq exwm-workspace--display-echo-area-timer nil))))
 
+(defvar exwm-workspace--client nil
+  "The 'client' frame parameter of emacsclient frames.")
+
 (declare-function exwm-manage--unmanage-window "exwm-manage.el")
+(declare-function exwm--exit "exwm.el")
 
 (defun exwm-workspace--confirm-kill-emacs (prompt)
   "Confirm before exiting Emacs."
@@ -615,9 +619,26 @@ The optional FORCE option is for internal use only."
                          :x 0
                          :y 0)))
     (xcb:flush exwm--connection)
-    ;; Destroy all resources created by this connection.
-    (xcb:disconnect exwm--connection)
-    t))
+    (if (not exwm-workspace--client)
+        (progn
+          ;; Destroy all resources created by this connection.
+          (xcb:disconnect exwm--connection)
+          t)
+      ;; Extra cleanups for emacsclient.
+      (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)))
+
+(defvar exwm-workspace--timer nil "Timer used to track echo area changes.")
 
 (defun exwm-workspace--init ()
   "Initialize workspace module."
@@ -629,11 +650,13 @@ The optional FORCE option is for internal use only."
       (progn
         (setq exwm-workspace--list (frame-list))
         (when (< 1 (length exwm-workspace--list))
-          ;; Emacs client creates an extra (but unusable) frame.
+          ;; Exclude the initial frame.
           (dolist (i exwm-workspace--list)
             (unless (frame-parameter i 'window-id)
               (setq exwm-workspace--list (delq i exwm-workspace--list))))
           (cl-assert (= 1 (length exwm-workspace--list)))
+          (setq exwm-workspace--client
+                (frame-parameter (car exwm-workspace--list) 'client))
           ;; Prevent user from deleting this frame by accident.
           (set-frame-parameter (car exwm-workspace--list) 'client nil))
         ;; Create remaining frames.
@@ -645,12 +668,17 @@ The optional FORCE option is for internal use only."
       (setq exwm-workspace--minibuffer
             (make-frame '((window-system . x) (minibuffer . only)
                           (left . 10000) (right . 10000)
-                          (width . 0) (height . 0))))
+                          (width . 0) (height . 0)
+                          (client . nil))))
       ;; Remove/hide existing frames.
       (dolist (f old-frames)
         (if (frame-parameter f 'client)
-            (make-frame-invisible f)
-          (delete-frame f))))
+            (progn
+              (unless exwm-workspace--client
+                (setq exwm-workspace--client (frame-parameter f 'client)))
+              (make-frame-invisible f))
+          (when (eq 'x (framep f))   ;do not delete the initial frame.
+            (delete-frame f)))))
     ;; This is the only usable minibuffer frame.
     (setq default-minibuffer-frame exwm-workspace--minibuffer)
     (let ((outer-id (string-to-number
@@ -687,17 +715,20 @@ The optional FORCE option is for internal use only."
     ;; Show/hide minibuffer / echo area when they're active/inactive.
     (add-hook 'minibuffer-setup-hook #'exwm-workspace--on-minibuffer-setup)
     (add-hook 'minibuffer-exit-hook #'exwm-workspace--on-minibuffer-exit)
-    (run-with-idle-timer 0 t #'exwm-workspace--on-echo-area-dirty)
+    (setq exwm-workspace--timer
+          (run-with-idle-timer 0 t #'exwm-workspace--on-echo-area-dirty))
     (add-hook 'echo-area-clear-hook #'exwm-workspace--on-echo-area-clear)
     ;; Create workspace frames.
     (dotimes (_ exwm-workspace-number)
       (push (make-frame `((window-system . x)
                           (minibuffer . ,(minibuffer-window
-                                          exwm-workspace--minibuffer))))
+                                          exwm-workspace--minibuffer))
+                          (client . nil)))
             exwm-workspace--list))
     ;; The default behavior of `display-buffer' (indirectly called by
     ;; `minibuffer-completion-help') is not correct here.
-    (cl-pushnew '(exwm-workspace--display-buffer) display-buffer-alist))
+    (cl-pushnew '(exwm-workspace--display-buffer) display-buffer-alist
+                :test #'equal))
   ;; Handle unexpected frame switch.
   (add-hook 'focus-in-hook #'exwm-workspace--on-focus-in)
   ;; Prevent `other-buffer' from selecting already displayed EXWM buffers.
@@ -768,6 +799,25 @@ The optional FORCE option is for internal use only."
   ;; Switch to the first workspace
   (exwm-workspace-switch 0 t))
 
+(defun exwm-workspace--exit ()
+  "Exit the workspace module."
+  (setq confirm-kill-emacs nil
+        exwm-workspace--list nil
+        exwm-workspace--client nil
+        exwm-workspace--minibuffer nil
+        default-minibuffer-frame nil)
+  (remove-hook 'minibuffer-setup-hook #'exwm-workspace--on-minibuffer-setup)
+  (remove-hook 'minibuffer-exit-hook #'exwm-workspace--on-minibuffer-exit)
+  (when exwm-workspace--timer
+    (cancel-timer exwm-workspace--timer)
+    (setq exwm-workspace--timer nil))
+  (remove-hook 'echo-area-clear-hook #'exwm-workspace--on-echo-area-clear)
+  (setq display-buffer-alist
+        (cl-delete '(exwm-workspace--display-buffer) display-buffer-alist
+                   :test #'equal))
+  (remove-hook 'focus-in-hook #'exwm-workspace--on-focus-in)
+  (advice-remove 'x-create-frame #'exwm-workspace--x-create-frame))
+
 (defvar exwm-layout--fullscreen-frame-count)
 
 (defun exwm-workspace--post-init ()
diff --git a/exwm.el b/exwm.el
index c9dc6cd..0bc27d7 100644
--- a/exwm.el
+++ b/exwm.el
@@ -477,7 +477,11 @@
 
 (defun exwm-init (&optional frame)
   "Initialize EXWM."
-  (if (not (eq 'x (framep (or frame (selected-frame)))))
+  (if frame
+      ;; The frame might not be selected if it's created by emacslicnet.
+      (select-frame-set-input-focus frame)
+    (setq frame (selected-frame)))
+  (if (not (eq 'x (framep frame)))
       (exwm--log "Not running under X environment")
     (unless exwm--connection
       (exwm-enable 'undo)               ;never initialize again
@@ -499,8 +503,8 @@
         ;; Disable some features not working well with EXWM
         (setq use-dialog-box nil)
         ;; Initialize ICCCM/EWMH support
-        ;; (xcb:icccm:init exwm--connection)
-        (xcb:ewmh:init exwm--connection)
+        (xcb:icccm:init exwm--connection t)
+        (xcb:ewmh:init exwm--connection t)
         (exwm--lock)
         (exwm--init-icccm-ewmh)
         (exwm-layout--init)
@@ -514,6 +518,26 @@
         (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.")
+
+(defun exwm--exit ()
+  "Exit EXWM."
+  (run-hooks 'exwm-exit-hook)
+  ;; Exit modules.
+  (exwm-input--exit)
+  (exwm-workspace--exit)
+  (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))
+
 (defvar exwm-blocking-subrs '(x-file-dialog x-popup-dialog x-select-font)
   "Subrs (primitives) that would normally block EXWM.")
 

Reply via email to