about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--exwm-core.el25
-rw-r--r--exwm-debug.el113
-rw-r--r--exwm-input.el32
-rw-r--r--exwm-layout.el14
-rw-r--r--exwm-manage.el16
-rw-r--r--exwm-systemtray.el37
-rw-r--r--exwm-workspace.el7
-rw-r--r--exwm.el14
8 files changed, 229 insertions, 29 deletions
diff --git a/exwm-core.el b/exwm-core.el
index ab5159c6a7a4..8d5e6dd6911f 100644
--- a/exwm-core.el
+++ b/exwm-core.el
@@ -31,9 +31,7 @@
 (require 'xcb)
 (require 'xcb-icccm)
 (require 'xcb-ewmh)
-
-(eval-and-compile
-  (defvar exwm-debug-on nil "Non-nil to turn on debug for EXWM."))
+(require 'exwm-debug)
 
 (defvar exwm--connection nil "X connection.")
 
@@ -70,10 +68,18 @@
 (declare-function exwm-workspace-move-window "exwm-workspace.el"
                   (frame-or-index &optional id))
 
-(defmacro exwm--log (format-string &rest args)
-  "Print debug message."
+(defmacro exwm--log (&optional format-string &rest objects)
+  "Emit a message prepending the name of the function being executed.
+
+FORMAT-STRING is a string specifying the message to output, as in
+`format'.  The OBJECTS arguments specify the substitutions."
   (when exwm-debug-on
-    `(message (concat "[EXWM] " ,format-string) ,@args)))
+    (unless format-string (setq format-string ""))
+    `(progn
+       (exwm-debug--message (concat "%s:\t" ,format-string "\n")
+                            (exwm-debug--compile-time-function-name)
+                            ,@objects)
+       nil)))
 
 (defmacro exwm--debug (&rest forms)
   (when exwm-debug-on `(progn ,@forms)))
@@ -88,6 +94,7 @@
 
 (defun exwm--lock (&rest _args)
   "Lock (disable all events)."
+  (exwm--log)
   (xcb:+request exwm--connection
       (make-instance 'xcb:ChangeWindowAttributes
                      :window exwm--root
@@ -97,6 +104,7 @@
 
 (defun exwm--unlock (&rest _args)
   "Unlock (enable all events)."
+  (exwm--log)
   (xcb:+request exwm--connection
       (make-instance 'xcb:ChangeWindowAttributes
                      :window exwm--root
@@ -281,6 +289,11 @@ least SECS seconds later."
                    (/= ,i exwm-workspace-current-index)])
                (number-sequence 0 (1- (exwm-workspace--count))))))))
 
+(exwm--debug
+  (let ((map exwm-mode-map))
+    (define-key map "\C-c\C-l" #'exwm-debug-clear)
+    (define-key map "\C-c\C-m" #'exwm-debug-mark)))
+
 (define-derived-mode exwm-mode nil "EXWM"
   "Major mode for managing X windows.
 
diff --git a/exwm-debug.el b/exwm-debug.el
new file mode 100644
index 000000000000..4d1ca7b403eb
--- /dev/null
+++ b/exwm-debug.el
@@ -0,0 +1,113 @@
+;;; exwm-debug.el --- Debugging helpers for EXWM  -*- lexical-binding: t -*-
+
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+
+;; Author: Adrián Medraño Calvo <adrian@medranocalvo.com>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This module collects functions that help in debugging EXWM.
+
+;;; Code:
+
+(eval-and-compile
+  (defvar exwm-debug-on nil "Non-nil to turn on debug for EXWM."))
+
+(defvar exwm-debug-buffer "*EXWM-DEBUG*" "Buffer to write debug messages to.")
+
+(defvar exwm-debug-backtrace-start-frame 5
+  "From which frame to start collecting backtraces.")
+
+(defun exwm-debug--call-stack ()
+  "Return the current call stack frames."
+  (let (frames frame
+        ;; No need to acount for our setq, while, let, ...
+        (index exwm-debug-backtrace-start-frame))
+    (while (setq frame (backtrace-frame index))
+      (push frame frames)
+      (cl-incf index))
+    (cl-remove-if-not 'car frames)))
+
+(defmacro exwm-debug--compile-time-function-name ()
+  "Get the name of outermost definition at expansion time."
+  (let* ((frame (cl-find-if
+		 (lambda (frame)
+		   (ignore-errors
+		     (let ((clause (car (cl-third frame))))
+		       (or (equal clause 'defalias)
+			   (equal clause 'cl-defmethod)))))
+		 (reverse (exwm-debug--call-stack))))
+	 (defn (cl-third frame))
+	 (deftype (car defn)))
+    (cl-case deftype
+      ((defalias) (symbol-name (cl-cadadr defn)))
+      ((cl-defmethod) (symbol-name (cadr defn)))
+      (t "<unknown function>"))))
+
+(defmacro exwm-debug--with-debug-buffer (&rest forms)
+  "Evaluate FORMS making sure `exwm-debug-buffer' is correctly updated."
+  `(with-current-buffer (get-buffer-create exwm-debug-buffer)
+     (let (windows-eob)
+       ;; Note windows whose point is at EOB.
+       (dolist (w (get-buffer-window-list exwm-debug-buffer t t))
+         (when (= (window-point w) (point-max))
+           (push w windows-eob)))
+       (save-excursion
+         (goto-char (point-max))
+         ,@forms)
+       ;; Restore point.
+       (dolist (w windows-eob)
+         (set-window-point w (point-max))))))
+
+(defun exwm-debug--message (format-string &rest objects)
+  "Print a message to `exwm-debug-buffer'.
+
+The FORMAT-STRING argument follows the speficies how to print each of
+the passed OBJECTS.  See `format' for details."
+  (exwm-debug--with-debug-buffer
+   (insert (apply #'format format-string objects))))
+
+(defmacro exwm-debug--backtrace ()
+  "Print a backtrace to the `exwm-debug-buffer'."
+  '(exwm-debug--with-debug-buffer
+    (let ((standard-output exwm-debug-buffer))
+      (backtrace))))
+
+(defmacro exwm-debug--backtrace-on-error (&rest forms)
+  "Evaluate FORMS.  Printing a backtrace if an error is signaled."
+  `(let ((debug-on-error t)
+         (debugger (lambda (&rest _) (exwm-debug--backtrace))))
+     ,@forms))
+
+(defun exwm-debug-clear ()
+  "Clear the debug buffer."
+  (interactive)
+  (exwm-debug--with-debug-buffer
+   (erase-buffer)))
+
+(defun exwm-debug-mark ()
+  "Insert a mark in the debug buffer."
+  (interactive)
+  (exwm-debug--with-debug-buffer
+   (insert "\n")))
+
+
+
+(provide 'exwm-debug)
+
+;;; exwm-debug.el ends here
diff --git a/exwm-input.el b/exwm-input.el
index 57a28735031c..57fed2d4b88e 100644
--- a/exwm-input.el
+++ b/exwm-input.el
@@ -157,6 +157,7 @@ This value should always be overwritten.")
 (defun exwm-input--set-focus (id)
   "Set input focus to window ID in a proper way."
   (when (exwm--id->buffer id)
+    (exwm--log "id=#x%x" id)
     (with-current-buffer (exwm--id->buffer id)
       (exwm-input--update-timestamp
        (lambda (timestamp id send-input-focus wm-take-focus)
@@ -187,6 +188,7 @@ This value should always be overwritten.")
 
 ARGS are additional arguments to CALLBACK."
   (setq exwm-input--timestamp-callback (cons callback args))
+  (exwm--log)
   (xcb:+request exwm--connection
       (make-instance 'xcb:ChangeProperty
                      :mode xcb:PropMode:Replace
@@ -200,6 +202,7 @@ ARGS are additional arguments to CALLBACK."
 
 (defun exwm-input--on-PropertyNotify (data _synthetic)
   "Handle PropertyNotify events."
+  (exwm--log)
   (when exwm-input--timestamp-callback
     (let ((obj (make-instance 'xcb:PropertyNotify)))
       (xcb:unmarshal obj data)
@@ -218,6 +221,7 @@ ARGS are additional arguments to CALLBACK."
     (with-slots (time root event root-x root-y event-x event-y state) evt
       (setq buffer (exwm--id->buffer event)
             window (get-buffer-window buffer t))
+      (exwm--log "EnterNotify: buffer=%s; window=%s" buffer window)
       (when (and buffer window (not (eq window (selected-window))))
         (setq frame (window-frame window)
               frame-xid (frame-parameter frame 'exwm-id))
@@ -265,6 +269,8 @@ ARGS are additional arguments to CALLBACK."
              (eq (current-buffer) (window-buffer))
              (not (string-prefix-p " *temp*"
                                    (buffer-name (car (last (buffer-list)))))))
+    (exwm--log "current-buffer=%S selected-window=%S"
+               (current-buffer) (selected-window))
     (redirect-frame-focus (selected-frame) nil)
     (setq exwm-input--update-focus-window (selected-window))
     (exwm-input--update-focus-defer)))
@@ -296,6 +302,7 @@ ARGS are additional arguments to CALLBACK."
 (defun exwm-input--update-focus (window)
   "Update input focus."
   (when (window-live-p window)
+    (exwm--log "focus-window=%s focus-buffer=%s" window (window-buffer window))
     (with-current-buffer (window-buffer window)
       (if (derived-mode-p 'exwm-mode)
           (if (not (eq exwm--frame exwm-workspace--current))
@@ -331,6 +338,10 @@ ARGS are additional arguments to CALLBACK."
               ;; The focus is on another workspace (e.g. it got clicked)
               ;; so switch to it.
               (progn
+                (exwm--log "Switching to %s's workspace %s (%s)"
+                           window
+                           (window-frame window)
+                           (selected-frame))
                 (set-frame-parameter (selected-frame) 'exwm-selected-window
                                      window)
                 (exwm--defer 0 #'exwm-workspace-switch (selected-frame)))
@@ -346,12 +357,14 @@ ARGS are additional arguments to CALLBACK."
 
 (defun exwm-input--on-minibuffer-setup ()
   "Run in `minibuffer-setup-hook' to set input focus."
+  (exwm--log)
   (unless (exwm-workspace--client-p)
     ;; Set input focus on the Emacs frame
     (x-focus-frame (window-frame (minibuffer-selected-window)))))
 
 (defun exwm-input--set-active-window (&optional id)
   "Set _NET_ACTIVE_WINDOW."
+  (exwm--log)
   (xcb:+request exwm--connection
       (make-instance 'xcb:ewmh:set-_NET_ACTIVE_WINDOW
                      :window exwm--root
@@ -363,6 +376,8 @@ ARGS are additional arguments to CALLBACK."
         (mode xcb:Allow:SyncPointer)
         button-event window buffer frame)
     (xcb:unmarshal obj data)
+    (exwm--log "major-mode=%s buffer=%s"
+               major-mode (buffer-name (current-buffer)))
     (with-slots (detail time event state) obj
       (setq button-event (xcb:keysyms:keysym->event exwm--connection
                                                     detail state)
@@ -412,12 +427,15 @@ ARGS are additional arguments to CALLBACK."
   "Handle KeyPress event."
   (let ((obj (make-instance 'xcb:KeyPress)))
     (xcb:unmarshal obj data)
+    (exwm--log "major-mode=%s buffer=%s"
+	       major-mode (buffer-name (current-buffer)))
     (if (derived-mode-p 'exwm-mode)
         (funcall exwm--on-KeyPress obj data)
       (exwm-input--on-KeyPress-char-mode obj))))
 
 (defun exwm-input--on-CreateNotify (data _synthetic)
   "Handle CreateNotify events."
+  (exwm--log)
   (let ((evt (make-instance 'xcb:CreateNotify)))
     (xcb:unmarshal evt data)
     (with-slots (window) evt
@@ -425,6 +443,7 @@ ARGS are additional arguments to CALLBACK."
 
 (defun exwm-input--update-global-prefix-keys ()
   "Update `exwm-input--global-prefix-keys'."
+  (exwm--log)
   (when exwm--connection
     (let ((original exwm-input--global-prefix-keys))
       (setq exwm-input--global-prefix-keys nil)
@@ -438,6 +457,7 @@ ARGS are additional arguments to CALLBACK."
                            'children))))))
 
 (defun exwm-input--grab-global-prefix-keys (&rest xwins)
+  (exwm--log)
   (let ((req (make-instance 'xcb:GrabKey
                             :owner-events 0
                             :grab-window nil
@@ -450,6 +470,8 @@ ARGS are additional arguments to CALLBACK."
       (setq keysym (xcb:keysyms:event->keysym exwm--connection k)
             keycode (xcb:keysyms:keysym->keycode exwm--connection
                                                  (car keysym)))
+      (exwm--log "Grabbing key=%s (keysym=%s keycode=%s)"
+                 (single-key-description k) keysym keycode)
       (setf (slot-value req 'modifiers) (cdr keysym)
             (slot-value req 'key) keycode)
       (dolist (xwin xwins)
@@ -498,6 +520,7 @@ specifically saved in the Customize interface for `exwm-input-global-keys'.
 In configuration you should customize or set `exwm-input-global-keys'
 instead."
   (interactive "KSet key globally: \nCSet key %s to command: ")
+  (exwm--log)
   (setq exwm-input-global-keys (append exwm-input-global-keys
                                        (list (cons key command))))
   (exwm-input--set-key key command)
@@ -517,6 +540,7 @@ instead."
 
 (defun exwm-input--mimic-read-event (event)
   "Process EVENT as if it were returned by `read-event'."
+  (exwm--log)
   (unless (eq 0 extra-keyboard-modifiers)
     (setq event (event-convert-list (append (event-modifiers
                                              extra-keyboard-modifiers)
@@ -559,6 +583,7 @@ instead."
   (with-slots (detail state) key-press
     (let ((keysym (xcb:keysyms:keycode->keysym exwm--connection detail state))
           event raw-event mode)
+      (exwm--log "%s" keysym)
       (when (and (/= 0 (car keysym))
                  (setq raw-event (xcb:keysyms:keysym->event
                                   exwm--connection (car keysym)
@@ -610,6 +635,7 @@ instead."
   (with-slots (detail state) key-press
     (let ((keysym (xcb:keysyms:keycode->keysym exwm--connection detail state))
           event raw-event)
+      (exwm--log "%s" keysym)
       (when (and (/= 0 (car keysym))
                  (setq raw-event (xcb:keysyms:keysym->event
                                   exwm--connection (car keysym)
@@ -660,6 +686,7 @@ instead."
   "Grab all key events on window ID."
   (unless id (setq id (exwm--buffer->id (window-buffer))))
   (when id
+    (exwm--log "id=#x%x" id)
     (when (xcb:+request-checked+request-check exwm--connection
               (make-instance 'xcb:GrabKey
                              :owner-events 0
@@ -676,6 +703,7 @@ instead."
   "Ungrab all key events on window ID."
   (unless id (setq id (exwm--buffer->id (window-buffer))))
   (when id
+    (exwm--log "id=#x%x" id)
     (when (xcb:+request-checked+request-check exwm--connection
               (make-instance 'xcb:UngrabKey
                              :key xcb:Grab:Any
@@ -692,6 +720,7 @@ instead."
   (interactive (list (when (derived-mode-p 'exwm-mode)
                        (exwm--buffer->id (window-buffer)))))
   (when id
+    (exwm--log "id=#x%x" id)
     (with-current-buffer (exwm--id->buffer id)
       (exwm-input--grab-keyboard id)
       (setq exwm--keyboard-grabbed t)
@@ -704,6 +733,7 @@ instead."
   (interactive (list (when (derived-mode-p 'exwm-mode)
                        (exwm--buffer->id (window-buffer)))))
   (when id
+    (exwm--log "id=#x%x" id)
     (with-current-buffer (exwm--id->buffer id)
       (exwm-input--release-keyboard id)
       (setq exwm--keyboard-grabbed nil)
@@ -716,6 +746,7 @@ instead."
   (interactive (list (when (derived-mode-p 'exwm-mode)
                        (exwm--buffer->id (window-buffer)))))
   (when id
+    (exwm--log "id=#x%x" id)
     (with-current-buffer (exwm--id->buffer id)
       (if exwm--keyboard-grabbed
           (exwm-input-release-keyboard id)
@@ -731,6 +762,7 @@ instead."
                                                (car keysym)))
     (when (/= 0 keycode)
       (setq id (exwm--buffer->id (window-buffer (selected-window))))
+      (exwm--log "id=#x%x event=%s keycode" id event keycode)
       (dolist (class '(xcb:KeyPress xcb:KeyRelease))
         (xcb:+request exwm--connection
             (make-instance 'xcb:SendEvent
diff --git a/exwm-layout.el b/exwm-layout.el
index 98a27d0ca03f..09a34985a7c6 100644
--- a/exwm-layout.el
+++ b/exwm-layout.el
@@ -59,6 +59,7 @@
 
 (defun exwm-layout--set-state (id state)
   "Set WM_STATE."
+  (exwm--log "id=#x%x" id)
   (xcb:+request exwm--connection
       (make-instance 'xcb:icccm:set-WM_STATE
                      :window id :state state :icon xcb:Window:None))
@@ -146,6 +147,7 @@
 (cl-defun exwm-layout-set-fullscreen (&optional id)
   "Make window ID fullscreen."
   (interactive)
+  (exwm--log "id=#x%x" (or id 0))
   (unless (and (or id (derived-mode-p 'exwm-mode))
                (not (exwm-layout--fullscreen-p)))
     (cl-return-from exwm-layout-set-fullscreen))
@@ -174,6 +176,7 @@
 (cl-defun exwm-layout-unset-fullscreen (&optional id)
   "Restore window from fullscreen state."
   (interactive)
+  (exwm--log "id=#x%x" (or id 0))
   (unless (and (or id (derived-mode-p 'exwm-mode))
                (exwm-layout--fullscreen-p))
     (cl-return-from exwm-layout-unset-fullscreen))
@@ -203,6 +206,7 @@
 (cl-defun exwm-layout-toggle-fullscreen (&optional id)
   "Toggle fullscreen mode."
   (interactive (list (exwm--buffer->id (window-buffer))))
+  (exwm--log "id=#x%x" (or id 0))
   (unless (or id (derived-mode-p 'exwm-mode))
     (cl-return-from exwm-layout-toggle-fullscreen))
   (when id
@@ -234,6 +238,7 @@ selected by `other-buffer'."
 
 (defun exwm-layout--set-client-list-stacking ()
   "Set _NET_CLIENT_LIST_STACKING."
+  (exwm--log)
   (let (id clients-floating clients clients-iconic clients-other)
     (dolist (pair exwm--id-buffer-alist)
       (setq id (car pair))
@@ -261,6 +266,7 @@ selected by `other-buffer'."
   ;; `window-configuration-change-hook' makes the frame selected.
   (unless frame
     (setq frame (selected-frame)))
+  (exwm--log "frame=%s" frame)
   (if (not (exwm-workspace--workspace-p frame))
       (if (frame-parameter frame 'exwm-outer-id)
           (exwm-layout--refresh-floating frame)
@@ -352,6 +358,7 @@ selected by `other-buffer'."
 
 (defun exwm-layout--on-minibuffer-setup ()
   "Refresh layout when minibuffer grows."
+  (exwm--log)
   (unless (exwm-workspace--client-p)
     (exwm--defer 0 (lambda ()
                      (when (< 1 (window-height (minibuffer-window)))
@@ -364,6 +371,7 @@ selected by `other-buffer'."
              (or (cl-position ?\n (current-message))
                  (> (length (current-message))
                     (frame-width exwm-workspace--current))))
+    (exwm--log)
     (if dirty
         (exwm-layout--refresh)
       (exwm--defer 0 #'exwm-layout--refresh))))
@@ -380,6 +388,7 @@ Normal hints are checked and regarded if the selected window is displaying an
 `exwm-mode' buffer.  However, this may violate the normal hints set on other X
 windows."
   (interactive "p")
+  (exwm--log)
   (cond
    ((zerop delta))                     ;no operation
    ((window-minibuffer-p))             ;avoid resize minibuffer-window
@@ -485,6 +494,7 @@ See also `exwm-layout-enlarge-window'."
 (defun exwm-layout-hide-mode-line ()
   "Hide mode-line."
   (interactive)
+  (exwm--log)
   (when (and (derived-mode-p 'exwm-mode) mode-line-format)
     (let (mode-line-height)
       (when exwm--floating-frame
@@ -503,6 +513,7 @@ See also `exwm-layout-enlarge-window'."
 (defun exwm-layout-show-mode-line ()
   "Show mode-line."
   (interactive)
+  (exwm--log)
   (when (and (derived-mode-p 'exwm-mode) (not mode-line-format))
     (setq mode-line-format exwm--mode-line-format
           exwm--mode-line-format nil)
@@ -520,6 +531,7 @@ See also `exwm-layout-enlarge-window'."
 (defun exwm-layout-toggle-mode-line ()
   "Toggle the display of mode-line."
   (interactive)
+  (exwm--log)
   (when (derived-mode-p 'exwm-mode)
     (if mode-line-format
         (exwm-layout-hide-mode-line)
@@ -528,6 +540,7 @@ See also `exwm-layout-enlarge-window'."
 (defun exwm-layout--init ()
   "Initialize layout module."
   ;; Auto refresh layout
+  (exwm--log)
   (add-hook 'window-configuration-change-hook #'exwm-layout--refresh)
   ;; The behavior of `window-configuration-change-hook' will be changed.
   (when (fboundp 'window-pixel-width-before-size-change)
@@ -541,6 +554,7 @@ See also `exwm-layout-enlarge-window'."
 
 (defun exwm-layout--exit ()
   "Exit the layout module."
+  (exwm--log)
   (remove-hook 'window-configuration-change-hook #'exwm-layout--refresh)
   (when (fboundp 'window-pixel-width-before-size-change)
     (remove-hook 'window-size-change-functions #'exwm-layout--refresh))
diff --git a/exwm-manage.el b/exwm-manage.el
index 349157f1ff20..81a486c09795 100644
--- a/exwm-manage.el
+++ b/exwm-manage.el
@@ -119,6 +119,7 @@ You can still make the X windows floating afterwards."
 
 (defun exwm-manage--update-geometry (id &optional force)
   "Update window geometry."
+  (exwm--log "id=#x%x" id)
   (with-current-buffer (exwm--id->buffer id)
     (unless (and exwm--geometry (not force))
       (let ((reply (xcb:+request-unchecked+reply exwm--connection
@@ -134,6 +135,7 @@ You can still make the X windows floating afterwards."
 
 (defun exwm-manage--update-ewmh-state (id)
   "Update _NET_WM_STATE."
+  (exwm--log "id=#x%x" id)
   (with-current-buffer (exwm--id->buffer id)
     (unless exwm--ewmh-state
       (let ((reply (xcb:+request-unchecked+reply exwm--connection
@@ -144,6 +146,7 @@ You can still make the X windows floating afterwards."
 
 (defun exwm-manage--update-mwm-hints (id &optional force)
   "Update _MOTIF_WM_HINTS."
+  (exwm--log "id=#x%x" id)
   (with-current-buffer (exwm--id->buffer id)
     (unless (and (not exwm--mwm-hints-decorations) (not force))
       (let ((reply (xcb:+request-unchecked+reply exwm--connection
@@ -167,6 +170,7 @@ You can still make the X windows floating afterwards."
 
 (defun exwm-manage--set-client-list ()
   "Set _NET_CLIENT_LIST."
+  (exwm--log)
   (xcb:+request exwm--connection
       (make-instance 'xcb:ewmh:set-_NET_CLIENT_LIST
                      :window exwm--root
@@ -174,6 +178,7 @@ You can still make the X windows floating afterwards."
 
 (cl-defun exwm-manage--get-configurations ()
   "Retrieve configurations for this buffer."
+  (exwm--log)
   (when (derived-mode-p 'exwm-mode)
     (dolist (i exwm-manage-configurations)
       (save-current-buffer
@@ -412,6 +417,7 @@ manager is shutting down."
 
 (defun exwm-manage--scan ()
   "Search for existing windows and try to manage them."
+  (exwm--log)
   (let* ((tree (xcb:+request-unchecked+reply exwm--connection
                    (make-instance 'xcb:QueryTree
                                   :window exwm--root)))
@@ -433,6 +439,7 @@ manager is shutting down."
 
 (defun exwm-manage--kill-buffer-query-function ()
   "Run in `kill-buffer-query-functions'."
+  (exwm--log "id=#x%x; buffer=%s" exwm--id (current-buffer))
   (catch 'return
     (when (or (not exwm--id)
               (xcb:+request-checked+request-check exwm--connection
@@ -510,6 +517,7 @@ Would you like to kill it? "
 (defun exwm-manage--kill-client (&optional id)
   "Kill an X client."
   (unless id (setq id (exwm--buffer->id (current-buffer))))
+  (exwm--log "id=#x%x" id)
   (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)))
@@ -526,12 +534,14 @@ Would you like to kill it? "
 
 (defun exwm-manage--add-frame (frame)
   "Run in `after-make-frame-functions'."
+  (exwm--log "frame=%s" frame)
   (when (display-graphic-p frame)
     (push (string-to-number (frame-parameter frame 'outer-window-id))
           exwm-manage--frame-outer-id-list)))
 
 (defun exwm-manage--remove-frame (frame)
   "Run in `delete-frame-functions'."
+  (exwm--log "frame=%s" frame)
   (when (display-graphic-p frame)
     (setq exwm-manage--frame-outer-id-list
           (delq (string-to-number (frame-parameter frame 'outer-window-id))
@@ -539,6 +549,7 @@ Would you like to kill it? "
 
 (defun exwm-manage--on-ConfigureRequest (data _synthetic)
   "Handle ConfigureRequest event."
+  (exwm--log)
   (let ((obj (make-instance 'xcb:ConfigureRequest))
         buffer edges width-delta height-delta)
     (xcb:unmarshal obj data)
@@ -631,6 +642,7 @@ border-width: %d; sibling: #x%x; stack-mode: %d"
   (let ((obj (make-instance 'xcb:MapRequest)))
     (xcb:unmarshal obj data)
     (with-slots (parent window) obj
+      (exwm--log "id=#x%x parent=#x%x" window parent)
       (if (assoc window exwm--id-buffer-alist)
           (with-current-buffer (exwm--id->buffer window)
             (if (exwm-layout--iconic-state-p)
@@ -650,12 +662,13 @@ border-width: %d; sibling: #x%x; stack-mode: %d"
   (let ((obj (make-instance 'xcb:UnmapNotify)))
     (xcb:unmarshal obj data)
     (with-slots (window) obj
-      (exwm--log "UnmapNotify from #x%x" window)
+      (exwm--log "id=#x%x" window)
       (exwm-manage--unmanage-window window t))))
 
 (defun exwm-manage--on-DestroyNotify (data synthetic)
   "Handle DestroyNotify event."
   (unless synthetic
+    (exwm--log)
     (let ((obj (make-instance 'xcb:DestroyNotify)))
       (xcb:unmarshal obj data)
       (exwm--log "DestroyNotify from #x%x" (slot-value obj 'window))
@@ -664,6 +677,7 @@ border-width: %d; sibling: #x%x; stack-mode: %d"
 (defun exwm-manage--init ()
   "Initialize manage module."
   ;; Intern _MOTIF_WM_HINTS
+  (exwm--log)
   (let ((atom-name "_MOTIF_WM_HINTS"))
     (setq exwm-manage--_MOTIF_WM_HINTS
           (slot-value (xcb:+request-unchecked+reply exwm--connection
diff --git a/exwm-systemtray.el b/exwm-systemtray.el
index ba1e3889347a..d3244ab8d088 100644
--- a/exwm-systemtray.el
+++ b/exwm-systemtray.el
@@ -70,7 +70,7 @@ You shall use the default value if using auto-hide minibuffer."
 
 (defvar exwm-systemtray--connection nil "The X connection.")
 
-(defvar exwm-systemtray--embedder nil "The embedder window.")
+(defvar exwm-systemtray--embedder-window nil "The embedder window.")
 
 (defvar exwm-systemtray--list nil "The icon list.")
 
@@ -112,7 +112,7 @@ You shall use the default value if using auto-hide minibuffer."
       (xcb:+request exwm-systemtray--connection
           (make-instance 'xcb:ReparentWindow
                          :window icon
-                         :parent exwm-systemtray--embedder
+                         :parent exwm-systemtray--embedder-window
                          :x 0
                          ;; Vertically centered.
                          :y (/ (- exwm-systemtray-height height*) 2)))
@@ -162,7 +162,8 @@ You shall use the default value if using auto-hide minibuffer."
                           (make-instance 'xcb:xembed:EMBEDDED-NOTIFY
                                          :window icon
                                          :time xcb:Time:CurrentTime
-                                         :embedder exwm-systemtray--embedder
+                                         :embedder
+                                         exwm-systemtray--embedder-window
                                          :version 0)
                           exwm-systemtray--connection)))
       (push `(,icon . ,(make-instance 'exwm-systemtray--icon
@@ -190,7 +191,8 @@ You shall use the default value if using auto-hide minibuffer."
   "Refresh the system tray."
   ;; Make sure to redraw the embedder.
   (xcb:+request exwm-systemtray--connection
-      (make-instance 'xcb:UnmapWindow :window exwm-systemtray--embedder))
+      (make-instance 'xcb:UnmapWindow
+                     :window exwm-systemtray--embedder-window))
   (let ((x exwm-systemtray-icon-gap)
         map)
     (dolist (pair exwm-systemtray--list)
@@ -207,14 +209,15 @@ You shall use the default value if using auto-hide minibuffer."
                          exwm-workspace-current-index)))
       (xcb:+request exwm-systemtray--connection
           (make-instance 'xcb:ConfigureWindow
-                         :window exwm-systemtray--embedder
+                         :window exwm-systemtray--embedder-window
                          :value-mask (logior xcb:ConfigWindow:X
                                              xcb:ConfigWindow:Width)
                          :x (- (aref workarea 2) x)
                          :width x)))
     (when map
       (xcb:+request exwm-systemtray--connection
-          (make-instance 'xcb:MapWindow :window exwm-systemtray--embedder))))
+          (make-instance 'xcb:MapWindow
+                         :window exwm-systemtray--embedder-window))))
   (xcb:flush exwm-systemtray--connection))
 
 (defun exwm-systemtray--on-DestroyNotify (data _synthetic)
@@ -230,7 +233,7 @@ You shall use the default value if using auto-hide minibuffer."
   (let ((obj (make-instance 'xcb:ReparentNotify)))
     (xcb:unmarshal obj data)
     (with-slots (window parent) obj
-      (when (and (/= parent exwm-systemtray--embedder)
+      (when (and (/= parent exwm-systemtray--embedder-window)
                  (assoc window exwm-systemtray--list))
         (exwm-systemtray--unembed window)))))
 
@@ -325,7 +328,7 @@ You shall use the default value if using auto-hide minibuffer."
   (unless (exwm-workspace--minibuffer-own-frame-p)
     (xcb:+request exwm-systemtray--connection
         (make-instance 'xcb:ReparentWindow
-                       :window exwm-systemtray--embedder
+                       :window exwm-systemtray--embedder-window
                        :parent (string-to-number
                                 (frame-parameter exwm-workspace--current
                                                  'window-id))
@@ -339,7 +342,7 @@ You shall use the default value if using auto-hide minibuffer."
   (unless (exwm-workspace--minibuffer-own-frame-p)
     (xcb:+request exwm-systemtray--connection
         (make-instance 'xcb:ConfigureWindow
-                       :window exwm-systemtray--embedder
+                       :window exwm-systemtray--embedder-window
                        :value-mask xcb:ConfigWindow:Y
                        :y (- (frame-pixel-height exwm-workspace--current)
                              exwm-systemtray-height))))
@@ -353,7 +356,7 @@ You shall use the default value if using auto-hide minibuffer."
   (cl-assert (not exwm-systemtray--connection))
   (cl-assert (not exwm-systemtray--list))
   (cl-assert (not exwm-systemtray--selection-owner-window))
-  (cl-assert (not exwm-systemtray--embedder))
+  (cl-assert (not exwm-systemtray--embedder-window))
   (unless exwm-systemtray-height
     (setq exwm-systemtray-height (max exwm-systemtray--icon-min-size
                                       (line-pixel-height))))
@@ -414,7 +417,8 @@ You shall use the default value if using auto-hide minibuffer."
     ;; Set _NET_WM_NAME.
     (xcb:+request exwm-systemtray--connection
         (make-instance 'xcb:ewmh:set-_NET_WM_NAME
-                       :window id :data "EXWM system tray selection owner"))
+                       :window id
+                       :data "EXWM: exwm-systemtray--selection-owner-window"))
     ;; Set the _NET_SYSTEM_TRAY_ORIENTATION property.
     (xcb:+request exwm-systemtray--connection
         (make-instance 'xcb:xembed:set-_NET_SYSTEM_TRAY_ORIENTATION
@@ -423,7 +427,7 @@ You shall use the default value if using auto-hide minibuffer."
   ;; Create the embedder.
   (let ((id (xcb:generate-id exwm-systemtray--connection))
         frame parent depth y)
-    (setq exwm-systemtray--embedder id)
+    (setq exwm-systemtray--embedder-window id)
     (if (exwm-workspace--minibuffer-own-frame-p)
         (setq frame exwm-workspace--minibuffer
               y (if (>= (line-pixel-height) exwm-systemtray-height)
@@ -460,7 +464,8 @@ You shall use the default value if using auto-hide minibuffer."
     ;; Set _NET_WM_NAME.
     (xcb:+request exwm-systemtray--connection
         (make-instance 'xcb:ewmh:set-_NET_WM_NAME
-                       :window id :data "EXWM system tray embedder")))
+                       :window id
+                       :data "EXWM: exwm-systemtray--embedder-window")))
   (xcb:flush exwm-systemtray--connection)
   ;; Attach event listeners.
   (xcb:+event exwm-systemtray--connection 'xcb:DestroyNotify
@@ -494,10 +499,10 @@ You shall use the default value if using auto-hide minibuffer."
     ;; parent of the embedder).
     (xcb:+request exwm-systemtray--connection
         (make-instance 'xcb:UnmapWindow
-                       :window exwm-systemtray--embedder))
+                       :window exwm-systemtray--embedder-window))
     (xcb:+request exwm-systemtray--connection
         (make-instance 'xcb:ReparentWindow
-                       :window exwm-systemtray--embedder
+                       :window exwm-systemtray--embedder-window
                        :parent exwm--root
                        :x 0
                        :y 0))
@@ -505,7 +510,7 @@ You shall use the default value if using auto-hide minibuffer."
     (setq exwm-systemtray--connection nil
           exwm-systemtray--list nil
           exwm-systemtray--selection-owner-window nil
-          exwm-systemtray--embedder nil)
+          exwm-systemtray--embedder-window nil)
     (remove-hook 'exwm-workspace-switch-hook
                  #'exwm-systemtray--on-workspace-switch)
     (remove-hook 'exwm-workspace--update-workareas-hook
diff --git a/exwm-workspace.el b/exwm-workspace.el
index 1034966374bf..bcfffff1d354 100644
--- a/exwm-workspace.el
+++ b/exwm-workspace.el
@@ -375,6 +375,7 @@ NIL if FRAME is not a workspace"
 
 (defun exwm-workspace--set-active (frame active)
   "Make frame FRAME active on its output."
+  (exwm--log "active=%s; frame=%s" frame active)
   (set-frame-parameter frame 'exwm-active active)
   (if active
       (exwm-workspace--set-fullscreen frame)
@@ -387,6 +388,7 @@ NIL if FRAME is not a workspace"
 
 (defun exwm-workspace--set-fullscreen (frame)
   "Make frame FRAME fullscreen according to `exwm-workspace--workareas'."
+  (exwm--log "frame=%s" frame)
   (let ((workarea (elt exwm-workspace--workareas
                        (exwm-workspace--position frame)))
         (id (frame-parameter frame 'exwm-outer-id))
@@ -396,6 +398,7 @@ NIL if FRAME is not a workspace"
           y (aref workarea 1)
           width (aref workarea 2)
           height (aref workarea 3))
+    (exwm--log "x=%s; y=%s; w=%s; h=%s" x y width height)
     (when (and (eq frame exwm-workspace--current)
                (exwm-workspace--minibuffer-own-frame-p))
       (exwm-workspace--resize-minibuffer-frame))
@@ -516,6 +519,7 @@ for internal use only."
            (<= 0 current-prefix-arg (exwm-workspace--count)))
       current-prefix-arg)
      (t 0))))
+  (exwm--log)
   (let* ((frame (exwm-workspace--workspace-from-frame-or-index frame-or-index))
          (old-frame exwm-workspace--current)
          (index (exwm-workspace--position frame))
@@ -665,6 +669,7 @@ Passing a workspace frame as the first option is for internal use only."
                  (format "Swap workspace %d with: "
                          (exwm-workspace--position w1))))
        (list w1 w2))))
+  (exwm--log)
   (let ((pos1 (exwm-workspace--position workspace1))
         (pos2 (exwm-workspace--position workspace2)))
     (if (or (not pos1) (not pos2) (= pos1 pos2))
@@ -703,6 +708,7 @@ before it."
           (<= 0 current-prefix-arg (exwm-workspace--count)))
      (list exwm-workspace--current current-prefix-arg))
     (t (list exwm-workspace--current 0))))
+  (exwm--log)
   (let ((pos (exwm-workspace--position workspace))
         flag start end index)
     (if (= nth pos)
@@ -928,6 +934,7 @@ INDEX must not exceed the current number of workspaces."
                       (remq #'exwm-input--on-buffer-list-update
                             buffer-list-update-hook)))
                  (rename-buffer (concat " " (buffer-name)))))))))))
+  (exwm--log)
   (when buffer-or-name
     (with-current-buffer buffer-or-name
       (if (derived-mode-p 'exwm-mode)
diff --git a/exwm.el b/exwm.el
index 9f9b6f468105..b9c1d0ba3475 100644
--- a/exwm.el
+++ b/exwm.el
@@ -360,6 +360,7 @@
     (xcb:unmarshal obj data)
     (setq id (slot-value obj 'window)
           atom (slot-value obj 'atom))
+    (exwm--log "atom=%s(%s)" (x-get-atom-name atom exwm-workspace--current) atom)
     (setq buffer (exwm--id->buffer id))
     (if (not (buffer-live-p buffer))
         ;; Properties of unmanaged X windows.
@@ -397,6 +398,7 @@
     (setq type (slot-value obj 'type)
           id (slot-value obj 'window)
           data (slot-value (slot-value obj 'data) 'data32))
+    (exwm--log "atom=%s(%s)" (x-get-atom-name type exwm-workspace--current) type)
     (cond
      ;; _NET_NUMBER_OF_DESKTOPS.
      ((= type xcb:Atom:_NET_NUMBER_OF_DESKTOPS)
@@ -665,15 +667,15 @@
                        :visual 0
                        :value-mask xcb:CW:OverrideRedirect
                        :override-redirect 1))
+    ;; Set _NET_WM_NAME
+    (xcb:+request exwm--connection
+        (make-instance 'xcb:ewmh:set-_NET_WM_NAME
+                       :window new-id :data "EXWM: exwm--guide-window"))
     (dolist (i (list exwm--root new-id))
       ;; Set _NET_SUPPORTING_WM_CHECK
       (xcb:+request exwm--connection
           (make-instance 'xcb:ewmh:set-_NET_SUPPORTING_WM_CHECK
-                         :window i :data new-id))
-      ;; Set _NET_WM_NAME
-      (xcb:+request exwm--connection
-          (make-instance 'xcb:ewmh:set-_NET_WM_NAME
-                         :window i :data "EXWM"))))
+                         :window i :data new-id))))
   ;; Set _NET_DESKTOP_VIEWPORT (we don't support large desktop).
   (xcb:+request exwm--connection
       (make-instance 'xcb:ewmh:set-_NET_DESKTOP_VIEWPORT
@@ -712,7 +714,7 @@ manager.  If t, replace it, if nil, abort and ask the user if `ask'."
                          :override-redirect 0))
       (xcb:+request exwm--connection
           (make-instance 'xcb:ewmh:set-_NET_WM_NAME
-                         :window new-owner :data "EXWM selection owner"))
+                         :window new-owner :data "EXWM: exwm--wmsn-window"))
       (xcb:+request-checked+request-check exwm--connection
           (make-instance 'xcb:SetSelectionOwner
                          :selection xcb:Atom:WM_S0