about summary refs log tree commit diff
diff options
context:
space:
mode:
authorChris Feng <chris.w.feng@gmail.com>2015-10-29T10·31+0800
committerChris Feng <chris.w.feng@gmail.com>2015-10-29T10·32+0800
commitb2ee10205177361a5f14dd11c4206b5ffd1cb98c (patch)
tree0bc4e0dbef4074a039b882eeb0e2bebcbbaaf4a9
parentd9b4ba0265fc1674b1205a11e838f86bce434b13 (diff)
Improve robustness of killing buffers
* exwm-core.el (exwm-mode): Use the return value of
  exwm-manage--close-window.
* exwm-manage.el (exwm-manage--close-window): Kill empty buffers; Handle X
  windows that does not support _NET_WM_PING.
  (exwm-manage--kill-client): Kill X windows supporting _NET_WM_PID with
  both SIGKILL and KillClient.
-rw-r--r--exwm-core.el3
-rw-r--r--exwm-manage.el69
2 files changed, 40 insertions, 32 deletions
diff --git a/exwm-core.el b/exwm-core.el
index ec7034737a0f..aaa98e394fc8 100644
--- a/exwm-core.el
+++ b/exwm-core.el
@@ -139,8 +139,7 @@
   ;; Kill buffer -> close window
   (add-hook 'kill-buffer-query-functions
             (lambda ()
-              (exwm-manage--close-window exwm--id (current-buffer))
-              nil)
+              (exwm-manage--close-window exwm--id (current-buffer)))
             nil t)
   (setq buffer-read-only t
         left-margin-width nil
diff --git a/exwm-manage.el b/exwm-manage.el
index bf285ab94406..aa484d657b21 100644
--- a/exwm-manage.el
+++ b/exwm-manage.el
@@ -249,6 +249,8 @@ corresponding buffer.")
 (defun exwm-manage--close-window (id &optional buffer)
   "Close window ID in a proper way."
   (catch 'return
+    (unless (exwm--id->buffer id)
+      (throw 'return t))
     (unless buffer (setq buffer (exwm--id->buffer id)))
     ;; Destroy the client window if it does not support WM_DELETE_WINDOW
     (unless (and (buffer-live-p buffer)
@@ -268,31 +270,33 @@ corresponding buffer.")
                                exwm--connection)))
     (xcb:flush exwm--connection)
     ;; Try to determine if the client stop responding
-    ;; FIXME: check
     (with-current-buffer buffer
-      (when (memq xcb:Atom:_NET_WM_PING exwm--protocols)
-        (setq exwm-manage--ping-lock t)
-        (xcb:+request exwm--connection
-            (make-instance 'xcb:SendEvent
-                           :propagate 0 :destination id
-                           :event-mask xcb:EventMask:NoEvent
-                           :event (xcb:marshal
-                                   (make-instance 'xcb:ewmh:_NET_WM_PING
-                                                  :window id :timestamp 0
-                                                  :client-window id)
-                                   exwm--connection)))
-        (xcb:flush exwm--connection)
-        (with-timeout (exwm-manage-ping-timeout
-                       (if (yes-or-no-p (format "\
-`%s' is not responding. Would you like to kill it? " (buffer-name buffer)))
-                           (progn (exwm-manage--kill-client id)
-                                  (throw 'return nil))
-                         (throw 'return nil)))
-          (while (and exwm-manage--ping-lock
-                      (exwm--id->buffer id)) ;may have be destroyed
-            (accept-process-output nil 0.1)))
-        (throw 'return nil)))
-    (throw 'return nil)))
+      (unless (memq xcb:Atom:_NET_WM_PING exwm--protocols)
+        ;; Ensure it's dead
+        (run-with-timer exwm-manage-ping-timeout nil
+                        `(lambda () (exwm-manage--kill-client ,id)))
+        (throw 'return nil))
+      (setq exwm-manage--ping-lock t)
+      (xcb:+request exwm--connection
+          (make-instance 'xcb:SendEvent
+                         :propagate 0 :destination id
+                         :event-mask xcb:EventMask:NoEvent
+                         :event (xcb:marshal
+                                 (make-instance 'xcb:ewmh:_NET_WM_PING
+                                                :window id :timestamp 0
+                                                :client-window id)
+                                 exwm--connection)))
+      (xcb:flush exwm--connection)
+      (with-timeout (exwm-manage-ping-timeout
+                     (if (yes-or-no-p (format "`%s' is not responding. \
+Would you like to kill it? "
+                                              (buffer-name buffer)))
+                         (progn (exwm-manage--kill-client id)
+                                (throw 'return nil))
+                       (throw 'return nil)))
+        (while (and exwm-manage--ping-lock
+                    (exwm--id->buffer id)) ;may have been destroyed
+          (accept-process-output nil 0.1))))))
 
 (defun exwm-manage--kill-client (&optional id)
   "Kill an X client."
@@ -300,12 +304,17 @@ corresponding buffer.")
   (unless id (setq id (exwm--buffer->id (current-buffer))))
   (let* ((response (xcb:+request-unchecked+reply exwm--connection
                        (make-instance 'xcb:ewmh:get-_NET_WM_PID :window id)))
-         (pid (and response (slot-value response 'value))))
-    (if pid
-        (signal-process pid 'SIGKILL)
-      (xcb:+request exwm--connection
-          (make-instance 'xcb:KillClient :resource id))
-      (xcb:flush exwm--connection))))
+         (pid (and response (slot-value response 'value)))
+         (request (make-instance 'xcb:KillClient :resource id)))
+    (if (not pid)
+        (xcb:+request exwm--connection request)
+      ;; What if the PID is fake/wrong?
+      (signal-process pid 'SIGKILL)
+      ;; Ensure it's dead
+      (run-with-timer exwm-manage-ping-timeout nil
+                      `(lambda ()
+                         (xcb:+request exwm--connection ,request))))
+    (xcb:flush exwm--connection)))
 
 (defun exwm-manage--on-ConfigureRequest (data _synthetic)
   "Handle ConfigureRequest event."