From 62ffde76aa3fa79c202d3c3f41cc995c716449d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Medra=C3=B1o=20Calvo?= Date: Thu, 9 Dec 2021 00:00:00 +0000 Subject: [PATCH 01/20] Refactor `exwm-workspace--get-remove-frame-next-workspace' * exwm-workspace.el (exwm-workspace--prompt-delete) (exwm-workspace--set-desktop): Stop explicitly moving X windows to other workspace; dealt with by `exwm-workspace--remove-frame-as-workspace'. (exwm-workspace--get-remove-frame-next-workspace): Remove function. Refactored into `exwm-workspace--get-next-workspace' and `exwm-workspace--remove-frame-as-workspace'. (exwm-workspace--get-next-workspace): Add function. (exwm-workspace--remove-frame-as-workspace): Move X windows to next workspace. --- exwm-workspace.el | 38 +++++++++++++++----------------------- exwm.el | 1 - 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/exwm-workspace.el b/exwm-workspace.el index c51334711..dbb6e6c9f 100644 --- a/exwm-workspace.el +++ b/exwm-workspace.el @@ -264,7 +264,6 @@ NIL if FRAME is not a workspace" (when (and exwm-workspace--prompt-delete-allowed (< 1 (exwm-workspace--count))) (let ((frame (elt exwm-workspace--list (1- minibuffer-history-position)))) - (exwm-workspace--get-remove-frame-next-workspace frame) (if (eq frame exwm-workspace--current) ;; Abort the recursive minibuffer if deleting the current workspace. (progn @@ -830,7 +829,6 @@ INDEX must not exceed the current number of workspaces." (exwm-workspace--workspace-from-frame-or-index frame-or-index) exwm-workspace--current))) - (exwm-workspace--get-remove-frame-next-workspace frame) (delete-frame frame)))) (defun exwm-workspace--set-desktop (id) @@ -1385,20 +1383,12 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first." frame exwm-workspace-current-index original-index)) (run-hooks 'exwm-workspace-list-change-hook))) -(defun exwm-workspace--get-remove-frame-next-workspace (frame) - "Return the next workspace if workspace FRAME is removed. - -All X windows currently on workspace FRAME will be automatically moved to -the next workspace." +(defun exwm-workspace--get-next-workspace (frame) + "Return the next workspace if workspace FRAME were removed. +Return nil if FRAME is the only workspace." (let* ((index (exwm-workspace--position frame)) (lastp (= index (1- (exwm-workspace--count)))) (nextw (elt exwm-workspace--list (+ index (if lastp -1 +1))))) - ;; Clients need to be moved to some other workspace before this being - ;; removed. - (dolist (pair exwm--id-buffer-alist) - (with-current-buffer (cdr pair) - (when (eq exwm--frame frame) - (exwm-workspace-move-window nextw exwm--id)))) nextw)) (defun exwm-workspace--remove-frame-as-workspace (frame) @@ -1406,20 +1396,22 @@ the next workspace." ;; TODO: restore all frame parameters (e.g. exwm-workspace, buffer-predicate, ;; etc) (exwm--log "Removing frame `%s' as workspace" frame) - (let* ((index (exwm-workspace--position frame)) - (nextw (exwm-workspace--get-remove-frame-next-workspace frame))) - ;; Need to remove the workspace from the list in order for - ;; the correct calculation of indexes. + (let* ((next-frame (exwm-workspace--get-next-workspace frame)) + (following-frames (cdr (memq frame exwm-workspace--list)))) + ;; Need to remove the workspace from the list for the correct calculation of + ;; indexes below. (setq exwm-workspace--list (delete frame exwm-workspace--list)) - ;; Update the _NET_WM_DESKTOP property of each X window affected. (dolist (pair exwm--id-buffer-alist) - (when (<= (1- index) - (exwm-workspace--position (buffer-local-value 'exwm--frame - (cdr pair)))) - (exwm-workspace--set-desktop (car pair)))) + (let ((other-frame (buffer-local-value 'exwm--frame (cdr pair)))) + ;; Move X windows to next-frame. + (when (eq other-frame frame) + (exwm-workspace-move-window next-frame (car pair))) + ;; Update the _NET_WM_DESKTOP property of each following X window. + (when (memq other-frame following-frames) + (exwm-workspace--set-desktop (car pair))))) ;; If the current workspace is deleted, switch to next one. (when (eq frame exwm-workspace--current) - (exwm-workspace-switch nextw))) + (exwm-workspace-switch next-frame))) ;; Reparent out the frame. (let ((outer-id (frame-parameter frame 'exwm-outer-id))) (xcb:+request exwm--connection diff --git a/exwm.el b/exwm.el index b025f6b49..4c1689a55 100644 --- a/exwm.el +++ b/exwm.el @@ -434,7 +434,6 @@ ((and (> current requested) (> current 1)) (let ((frame (car (last exwm-workspace--list)))) - (exwm-workspace--get-remove-frame-next-workspace frame) (delete-frame frame)))))) ;; _NET_CURRENT_DESKTOP. ((= type xcb:Atom:_NET_CURRENT_DESKTOP) From a11bb099fbd0b755d9a6d80a63a0dcd275280e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Medra=C3=B1o=20Calvo?= Date: Thu, 9 Dec 2021 00:00:00 +0000 Subject: [PATCH 02/20] Refactor re-creation of last frame * exwm-workspace.el (exwm-workspace--get-next-workspace): Return nil when there's only one frame. (exwm-workspace--on-delete-frame) (exwm-workspace--remove-frame-as-workspace): Create a workspace when removing the last one, for X windows to be moved to. --- exwm-workspace.el | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/exwm-workspace.el b/exwm-workspace.el index dbb6e6c9f..3bdbd472f 100644 --- a/exwm-workspace.el +++ b/exwm-workspace.el @@ -1389,7 +1389,8 @@ Return nil if FRAME is the only workspace." (let* ((index (exwm-workspace--position frame)) (lastp (= index (1- (exwm-workspace--count)))) (nextw (elt exwm-workspace--list (+ index (if lastp -1 +1))))) - nextw)) + (unless (eq frame nextw) + nextw))) (defun exwm-workspace--remove-frame-as-workspace (frame) "Stop treating frame FRAME as a workspace." @@ -1401,6 +1402,11 @@ Return nil if FRAME is the only workspace." ;; Need to remove the workspace from the list for the correct calculation of ;; indexes below. (setq exwm-workspace--list (delete frame exwm-workspace--list)) + (unless next-frame + ;; The user managed to delete the last workspace, so create a new one. + (exwm--log "Last workspace deleted; create a new one") + (let ((exwm-workspace--create-silently t)) + (setq next-frame (make-frame)))) (dolist (pair exwm--id-buffer-alist) (let ((other-frame (buffer-local-value 'exwm--frame (cdr pair)))) ;; Move X windows to next-frame. @@ -1454,13 +1460,6 @@ Return nil if FRAME is the only workspace." ((not (exwm-workspace--workspace-p frame)) (exwm--log "Frame `%s' is not a workspace" frame)) (t - (when (= 1 (exwm-workspace--count)) - ;; The user managed to delete the last workspace, so create a new one. - (exwm--log "Last workspace deleted; create a new one") - ;; TODO: this makes sense in the hook. But we need a function that takes - ;; care of converting a workspace into a regular unmanaged frame. - (let ((exwm-workspace--create-silently t)) - (make-frame))) (exwm-workspace--remove-frame-as-workspace frame) (remhash frame exwm-workspace--client-p-hash-table)))) From 1aa4ca781dff7853bf6ed01e5e397793fb3ee661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Medra=C3=B1o=20Calvo?= Date: Thu, 9 Dec 2021 00:00:00 +0000 Subject: [PATCH 03/20] Support for killing the X terminal Check whether frames are alive upon teardown, as it might not be the case when the terminal is killed as `delete-terminal-functions' might be invoked after the terminal is deleted. * exwm-core.el (exwm--terminal): New variable holding the terminal EXWM runs under. (exwm-init, exwm-exit): Set and unset it. * exwm.el (exwm--on-delete-terminal): New function for exiting EXWM when the terminal is deleted. (exwm-init): Use it. * exwm.el (exwm--confirm-kill-terminal, exwm-init): Ask for confirmation before deleting terminal. * exwm-workspace.el (exwm-workspace--fullscreen-workspace): New function. Ensure the frame is alive. (exwm-workspace--add-frame-as-workspace): Use it. (exwm-workspace--exit-minibuffer-frame): Cancel `exwm-workspace--display-echo-area-timer'. (exwm-workspace--exit-minibuffer-frame): Ensure the minibuffer frame is alive. (exwm-workspace--exit): Ignore dead workspace frames. --- exwm-core.el | 3 +++ exwm-workspace.el | 61 ++++++++++++++++++++++++++++------------------- exwm.el | 24 ++++++++++++++++++- 3 files changed, 63 insertions(+), 25 deletions(-) diff --git a/exwm-core.el b/exwm-core.el index 5356ef9b9..5bcf94385 100644 --- a/exwm-core.el +++ b/exwm-core.el @@ -59,6 +59,9 @@ Here are some predefined candidates: (defvar exwm--connection nil "X connection.") +(defvar exwm--terminal nil + "Terminal corresponding to `exwm--connection'.") + (defvar exwm--wmsn-window nil "An X window owning the WM_S0 selection.") diff --git a/exwm-workspace.el b/exwm-workspace.el index 3bdbd472f..ff9920d16 100644 --- a/exwm-workspace.el +++ b/exwm-workspace.el @@ -1372,7 +1372,7 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first." (make-instance 'xcb:MapWindow :window container))) (xcb:flush exwm--connection) ;; Delay making the workspace fullscreen until Emacs becomes idle - (exwm--defer 0 #'set-frame-parameter frame 'fullscreen 'fullboth) + (exwm--defer 0 #'exwm-workspace--fullscreen-workspace frame) ;; Update EWMH properties. (exwm-workspace--update-ewmh-props) (if exwm-workspace--create-silently @@ -1463,6 +1463,12 @@ Return nil if FRAME is the only workspace." (exwm-workspace--remove-frame-as-workspace frame) (remhash frame exwm-workspace--client-p-hash-table)))) +(defun exwm-workspace--fullscreen-workspace (frame) + "Make workspace FRAME fullscreen. +Called from a timer." + (when (frame-live-p frame) + (set-frame-parameter frame 'fullscreen 'fullboth))) + (defun exwm-workspace--on-after-make-frame (frame) "Hook run upon `make-frame' that configures FRAME as a workspace." (cond @@ -1606,6 +1612,8 @@ applied to all subsequently created X frames." (remove-hook 'minibuffer-setup-hook #'exwm-workspace--on-minibuffer-setup) (remove-hook 'minibuffer-exit-hook #'exwm-workspace--on-minibuffer-exit) (remove-hook 'echo-area-clear-hook #'exwm-workspace--on-echo-area-clear) + (when exwm-workspace--display-echo-area-timer + (cancel-timer exwm-workspace--display-echo-area-timer)) (when exwm-workspace--timer (cancel-timer exwm-workspace--timer) (setq exwm-workspace--timer nil)) @@ -1613,15 +1621,16 @@ applied to all subsequently created X frames." (cl-delete '(exwm-workspace--display-buffer) display-buffer-alist :test #'equal)) (setq default-minibuffer-frame nil) - (let ((id (frame-parameter exwm-workspace--minibuffer 'exwm-outer-id))) - (when (and exwm-workspace--minibuffer id) - (xcb:+request exwm--connection - (make-instance 'xcb:ReparentWindow - :window id - :parent exwm--root - :x 0 - :y 0))) - (setq exwm-workspace--minibuffer nil))) + (when (frame-live-p exwm-workspace--minibuffer) ; might be already dead + (let ((id (frame-parameter exwm-workspace--minibuffer 'exwm-outer-id))) + (when (and exwm-workspace--minibuffer id) + (xcb:+request exwm--connection + (make-instance 'xcb:ReparentWindow + :window id + :parent exwm--root + :x 0 + :y 0))) + (setq exwm-workspace--minibuffer nil)))) (defun exwm-workspace--init () "Initialize workspace module." @@ -1712,24 +1721,28 @@ applied to all subsequently created X frames." ;; X windows will be re-mapped). (setq exwm-workspace--current nil) (dolist (i exwm-workspace--list) - (exwm-workspace--remove-frame-as-workspace i) - (modify-frame-parameters i '((exwm-selected-window . nil) - (exwm-urgency . nil) - (exwm-outer-id . nil) - (exwm-id . nil) - (exwm-container . nil) - ;; (internal-border-width . nil) ; integerp - ;; (client . nil) - (fullscreen . nil) - (buffer-predicate . nil)))) + (when (frame-live-p i) ; might be already dead + (exwm-workspace--remove-frame-as-workspace i) + (modify-frame-parameters i '((exwm-selected-window . nil) + (exwm-urgency . nil) + (exwm-outer-id . nil) + (exwm-id . nil) + (exwm-container . nil) + ;; (internal-border-width . nil) ; integerp + (fullscreen . nil) + (buffer-predicate . nil))) + ;; Restore the 'client' frame parameter (before `exwm-exit'). + (when exwm-workspace--client + (set-frame-parameter f 'client exwm-workspace--client)))) ;; 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) + (when (and exwm-workspace--minibuffer-own-frame-p + (frame-live-p exwm-workspace--minibuffer)) (set-frame-parameter exwm-workspace--minibuffer 'client exwm-workspace--client)) - (setq exwm-workspace--client nil))) + (setq exwm-workspace--client nil)) + ;; Don't let dead frames linger. + (setq exwm-workspace--list nil)) (defun exwm-workspace--post-init () "The second stage in the initialization of the workspace module." diff --git a/exwm.el b/exwm.el index 4c1689a55..9e2df1ad6 100644 --- a/exwm.el +++ b/exwm.el @@ -604,6 +604,13 @@ (eq selection xcb:Atom:WM_S0)) (exwm-exit)))) +(defun exwm--on-delete-terminal (terminal) + "Handle terminal being deleted without Emacs being killed. +This may happen when invoking `save-buffers-kill-terminal' within an emacsclient +session." + (when (eq terminal exwm--terminal) + (exwm-exit))) + (defun exwm--init-icccm-ewmh () "Initialize ICCCM/EWMH support." (exwm--log) @@ -840,6 +847,7 @@ manager. If t, replace it, if nil, abort and ask the user if `ask'." (condition-case err (progn (exwm-enable 'undo) ;never initialize again + (setq exwm--terminal (frame-terminal frame)) (setq exwm--connection (xcb:connect)) (set-process-query-on-exit-flag (slot-value exwm--connection 'process) nil) ;prevent query message on exit @@ -862,6 +870,10 @@ manager. If t, replace it, if nil, abort and ask the user if `ask'." ;; Disable some features not working well with EXWM (setq use-dialog-box nil confirm-kill-emacs #'exwm--confirm-kill-emacs) + (advice-add 'save-buffers-kill-terminal + :before-while #'exwm--confirm-kill-terminal) + ;; Clean up if the terminal is deleted. + (add-hook 'delete-terminal-functions 'exwm--on-delete-terminal) (exwm--lock) (exwm--init-icccm-ewmh) (exwm-layout--init) @@ -898,7 +910,9 @@ manager. If t, replace it, if nil, abort and ask the user if `ask'." (when exwm--connection (xcb:flush exwm--connection) (xcb:disconnect exwm--connection)) - (setq exwm--connection nil)) + (setq exwm--connection nil) + (setq exwm--terminal nil) + (exwm--log "Exited")) ;;;###autoload (defun exwm-enable (&optional undo) @@ -977,6 +991,14 @@ manager. If t, replace it, if nil, abort and ask the user if `ask'." ;; For other types, return the value as-is. (t result)))))) +(defun exwm--confirm-kill-terminal (&optional _) + "Confirm before killing terminal." + ;; This is invoked instead of `save-buffers-kill-emacs' (C-x C-c) on client + ;; frames. + (if (eq (frame-terminal) exwm--terminal) + (exwm--confirm-kill-emacs "[EXWM] Kill terminal?") + t)) + (defun exwm--confirm-kill-emacs (prompt &optional force) "Confirm before exiting Emacs." (exwm--log) From ca7623349eb8b1c3a68d8b8fb632277989d5da81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Medra=C3=B1o=20Calvo?= Date: Thu, 9 Dec 2021 00:00:00 +0000 Subject: [PATCH 04/20] Leave `client' frame parameter in place EXWM removed the `client' frame parameter from workspace frames, perhaps in order to lead Emacs to ask for confirmation before quitting. This change leaves the `client' frame parameter in place. Emacs no longer asks for confirmation when killing the emacsclient session. A followup commit will correct this. * exwm-workspace.el (exwm-workspace--add-frame-as-workspace) (exwm-workspace--init-minibuffer-frame, exwm-workspace--init) (exwm-workspace--exit, exwm-workspace--post-init): Remove special handling for `client' frames. They become workspaces just like any other frame. --- exwm-workspace.el | 47 +++++++---------------------------------------- 1 file changed, 7 insertions(+), 40 deletions(-) diff --git a/exwm-workspace.el b/exwm-workspace.el index ff9920d16..3e53a7a82 100644 --- a/exwm-workspace.el +++ b/exwm-workspace.el @@ -85,9 +85,6 @@ each time." If the minibuffer is detached, this value is 0.") -(defvar exwm-workspace--client nil - "The 'client' frame parameter of emacsclient frames.") - (defvar exwm-workspace--create-silently nil "When non-nil workspaces are created in the background (not switched to). @@ -1329,8 +1326,6 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first." (set-frame-parameter frame 'exwm-outer-id outer-id) (set-frame-parameter frame 'exwm-id window-id) (set-frame-parameter frame 'exwm-container container) - ;; In case it's created by emacsclient. - (set-frame-parameter frame 'client nil) ;; Copy RandR frame parameters from the first workspace to ;; prevent potential problems. The values do not matter here as ;; they'll be updated by the RandR module later. @@ -1541,8 +1536,7 @@ applied to all subsequently created X frames." (setq exwm-workspace--minibuffer (make-frame '((window-system . x) (minibuffer . only) (left . 10000) (right . 10000) - (width . 1) (height . 1) - (client . nil)))) + (width . 1) (height . 1)))) ;; This is the only usable minibuffer frame. (setq default-minibuffer-frame exwm-workspace--minibuffer) (exwm-workspace--modify-all-x-frames-parameters @@ -1648,33 +1642,22 @@ applied to all subsequently created X frames." (dolist (i initial-workspaces) (unless (frame-parameter i 'window-id) (setq initial-workspaces (delq i initial-workspaces)))) - (setq exwm-workspace--client - (frame-parameter (car initial-workspaces) 'client)) (let ((f (car initial-workspaces))) ;; Remove the possible internal border. - (set-frame-parameter f 'internal-border-width 0) - ;; Prevent user from deleting the first frame by accident. - (set-frame-parameter f 'client nil))) + (set-frame-parameter f 'internal-border-width 0))) (exwm-workspace--init-minibuffer-frame) ;; Remove/hide existing frames. (dolist (f initial-workspaces) - (if (frame-parameter f 'client) - (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)))) + (when (eq 'x (framep f)) ;do not delete the initial frame. + (delete-frame f))) ;; Recreate one frame with the external minibuffer set. - (setq initial-workspaces (list (make-frame '((window-system . x) - (client . nil)))))) + (setq initial-workspaces (list (make-frame '((window-system . x)))))) ;; Prevent `other-buffer' from selecting already displayed EXWM buffers. (modify-all-frames-parameters '((buffer-predicate . exwm-layout--other-buffer-predicate))) ;; Create remaining workspaces. (dotimes (_ (- exwm-workspace-number (length initial-workspaces))) - (nconc initial-workspaces (list (make-frame '((window-system . x) - (client . nil)))))) + (nconc initial-workspaces (list (make-frame '((window-system . x)))))) ;; Configure workspaces (let ((exwm-workspace--create-silently t)) (dolist (i initial-workspaces) @@ -1730,29 +1713,13 @@ applied to all subsequently created X frames." (exwm-container . nil) ;; (internal-border-width . nil) ; integerp (fullscreen . nil) - (buffer-predicate . nil))) - ;; Restore the 'client' frame parameter (before `exwm-exit'). - (when exwm-workspace--client - (set-frame-parameter f 'client exwm-workspace--client)))) - ;; Restore the 'client' frame parameter (before `exwm-exit'). - (when exwm-workspace--client - (when (and exwm-workspace--minibuffer-own-frame-p - (frame-live-p exwm-workspace--minibuffer)) - (set-frame-parameter exwm-workspace--minibuffer 'client - exwm-workspace--client)) - (setq exwm-workspace--client nil)) + (buffer-predicate . nil))))) ;; Don't let dead frames linger. (setq exwm-workspace--list nil)) (defun exwm-workspace--post-init () "The second stage in the initialization of the workspace module." (exwm--log) - (when exwm-workspace--client - ;; Reset the 'fullscreen' frame parameter to make emacsclinet frames - ;; fullscreen (even without the RandR module enabled). - (dolist (i exwm-workspace--list) - (set-frame-parameter i 'fullscreen nil) - (set-frame-parameter i 'fullscreen 'fullboth))) ;; Wait until all workspace frames are resized. (with-timeout (1) (while (< exwm-workspace--fullscreen-frame-count (exwm-workspace--count)) From d4a7d166763077b5d5e81584d765cd48d920ebf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Medra=C3=B1o=20Calvo?= Date: Thu, 9 Dec 2021 00:00:00 +0000 Subject: [PATCH 05/20] Improve confirmation prompts * exwm.el (exwm-restart, exwm--confirm-kill-emacs): Improve confirmation prompts. --- exwm.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exwm.el b/exwm.el index 9e2df1ad6..8a85002c4 100644 --- a/exwm.el +++ b/exwm.el @@ -127,7 +127,7 @@ "Restart EXWM." (interactive) (exwm--log) - (when (exwm--confirm-kill-emacs "[EXWM] Restart? " 'no-check) + (when (exwm--confirm-kill-emacs "Restart?" 'no-check) (let* ((attr (process-attributes (emacs-pid))) (args (cdr (assq 'args attr))) (ppid (cdr (assq 'ppid attr))) @@ -1017,7 +1017,7 @@ manager. If t, replace it, if nil, abort and ask the user if `ask'." (`break (y-or-n-p prompt)) (x x))) (t - (yes-or-no-p (format "[EXWM] %d window(s) will be destroyed. %s" + (yes-or-no-p (format "[EXWM] %d X 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. From d6f62ff55aa722456e5fcf2bd8cb431a626347f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Medra=C3=B1o=20Calvo?= Date: Thu, 9 Dec 2021 00:00:00 +0000 Subject: [PATCH 06/20] Check EXWM terminal instead of client or graphical frames * exwm-core.el (exwm--terminal-p): Add function. * exwm.el (exwm--confirm-kill-terminal): Use it. * exwm-input.el (exwm-input--on-buffer-list-update): Use it. (exwm-input--on-minibuffer-setup) (exwm-input--on-minibuffer-exit): Use it. (exwm-input--on-minibuffer-exit): Use the minibuffer's selected window's frame or selected frame instead of current workspace. (exwm-input--on-echo-area-dirty): Removed test, as it's checked in `exwm-input--on-minibuffer-setup'. * exwm-layout.el (exwm-layout--on-minibuffer-setup) (exwm-layout--on-echo-area-change): Use it. (exwm-layout--on-echo-area-change): Refresh layout the frame of selected window's minibuffer if it's an EXWM frame. * exwm-workspace.el (exwm-workspace--update-minibuffer-height) (exwm-workspace--on-minibuffer-setup) (exwm-workspace--on-minibuffer-exit) (exwm-workspace--on-echo-area-dirty) (exwm-workspace--on-echo-area-clear) (exwm-workspace--on-delete-frame): Use it. * exwm-workspace.el (exwm-workspace--client-p-hash-table): Remove variable. (exwm-workspace--client-p): Remove function. --- exwm-core.el | 5 +++++ exwm-input.el | 50 ++++++++++++++++++++++++----------------------- exwm-layout.el | 27 +++++++++++++------------ exwm-workspace.el | 36 ++++++++++++---------------------- exwm.el | 2 +- 5 files changed, 59 insertions(+), 61 deletions(-) diff --git a/exwm-core.el b/exwm-core.el index 5bcf94385..85bbe5884 100644 --- a/exwm-core.el +++ b/exwm-core.el @@ -180,6 +180,11 @@ least SECS seconds later." ,function ,@args)) +(defsubst exwm--terminal-p (&optional frame) + "Return t when FRAME's terminal is EXWM's terminal. +If FRAME is null, use selected frame." + (eq exwm--terminal (frame-terminal frame))) + (defun exwm--get-client-event-mask () "Return event mask set on all managed windows." (logior xcb:EventMask:StructureNotify diff --git a/exwm-input.el b/exwm-input.el index c27ee1b04..79bc78ef0 100644 --- a/exwm-input.el +++ b/exwm-input.el @@ -159,8 +159,6 @@ Current buffer will be the `exwm-mode' buffer when this hook runs.") (declare-function exwm-layout--iconic-state-p "exwm-layout.el" (&optional id)) (declare-function exwm-layout--show "exwm-layout.el" (id &optional window)) (declare-function exwm-reset "exwm.el" ()) -(declare-function exwm-workspace--client-p "exwm-workspace.el" - (&optional frame)) (declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el") (declare-function exwm-workspace--workspace-p "exwm-workspace.el" (workspace)) (declare-function exwm-workspace-switch "exwm-workspace.el" @@ -296,8 +294,9 @@ ARGS are additional arguments to CALLBACK." (defun exwm-input--on-buffer-list-update () "Run in `buffer-list-update-hook' to track input focus." - (when (and (not (exwm-workspace--client-p)) - (not exwm-input--skip-buffer-list-update)) + (when (and ; this hook is called incesantly; place cheap tests on top + (not exwm-input--skip-buffer-list-update) + (exwm--terminal-p)) ; skip other terminals, e.g. TTY client frames (exwm--log "current-buffer=%S selected-window=%S" (current-buffer) (selected-window)) (redirect-frame-focus (selected-frame) nil) @@ -1100,37 +1099,40 @@ One use is to access the keymap bound to KEYS (as prefix keys) in char-mode." (defun exwm-input--on-minibuffer-setup () "Run in `minibuffer-setup-hook' to grab keyboard if necessary." - (exwm--log) - (with-current-buffer - (window-buffer (frame-selected-window exwm-workspace--current)) - (when (and (derived-mode-p 'exwm-mode) - (not (exwm-workspace--client-p)) - (eq exwm--selected-input-mode 'char-mode)) - (exwm-input--grab-keyboard exwm--id)))) + (let* ((window (or (minibuffer-selected-window) ; minibuffer-setup-hook + (selected-window))) ; echo-area-clear-hook + (frame (window-frame window))) + (when (exwm--terminal-p frame) + (with-current-buffer (window-buffer window) + (when (and (derived-mode-p 'exwm-mode) + (eq exwm--selected-input-mode 'char-mode)) + (exwm--log "Grab #x%x window=%s frame=%s" exwm--id window frame) + (exwm-input--grab-keyboard exwm--id)))))) (defun exwm-input--on-minibuffer-exit () "Run in `minibuffer-exit-hook' to release keyboard if necessary." - (exwm--log) - (with-current-buffer - (window-buffer (frame-selected-window exwm-workspace--current)) - (when (and (derived-mode-p 'exwm-mode) - (not (exwm-workspace--client-p)) - (eq exwm--selected-input-mode 'char-mode) - (eq exwm--input-mode 'line-mode)) - (exwm-input--release-keyboard exwm--id)))) + (let* ((window (or (minibuffer-selected-window) ; minibuffer-setup-hook + (selected-window))) ; echo-area-clear-hook + (frame (window-frame window))) + (when (exwm--terminal-p frame) + (with-current-buffer (window-buffer window) + (when (and (derived-mode-p 'exwm-mode) + (eq exwm--selected-input-mode 'char-mode) + (eq exwm--input-mode 'line-mode)) + (exwm--log "Release #x%x window=%s frame=%s" exwm--id window frame) + (exwm-input--release-keyboard exwm--id)))))) (defun exwm-input--on-echo-area-dirty () "Run when new message arrives to grab keyboard if necessary." - (exwm--log) - (when (and (not (active-minibuffer-window)) - (not (exwm-workspace--client-p)) - cursor-in-echo-area) + (when (and cursor-in-echo-area + (not (active-minibuffer-window))) + (exwm--log) (exwm-input--on-minibuffer-setup))) (defun exwm-input--on-echo-area-clear () "Run in `echo-area-clear-hook' to release keyboard if necessary." - (exwm--log) (unless (current-message) + (exwm--log) (exwm-input--on-minibuffer-exit))) (defun exwm-input--init () diff --git a/exwm-layout.el b/exwm-layout.el index 9173a1c04..3d78b4265 100644 --- a/exwm-layout.el +++ b/exwm-layout.el @@ -57,8 +57,6 @@ (declare-function exwm-input--grab-keyboard "exwm-input.el") (declare-function exwm-input-grab-keyboard "exwm-input.el") (declare-function exwm-workspace--active-p "exwm-workspace.el" (frame)) -(declare-function exwm-workspace--client-p "exwm-workspace.el" - (&optional frame)) (declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el") (declare-function exwm-workspace--workspace-p "exwm-workspace.el" (workspace)) @@ -405,22 +403,27 @@ selected by `other-buffer'." (defun exwm-layout--on-minibuffer-setup () "Refresh layout when minibuffer grows." (exwm--log) - (unless (exwm-workspace--client-p) + ;; Only when the minibuffer's frame is an EXWM frame. + ;; FIXME: would it be enough checking for workspace frames? + (when (exwm--terminal-p) (exwm--defer 0 (lambda () (when (< 1 (window-height (minibuffer-window))) (exwm-layout--refresh)))))) (defun exwm-layout--on-echo-area-change (&optional dirty) "Run when message arrives or in `echo-area-clear-hook' to refresh layout." - (when (and (current-message) - (not (exwm-workspace--client-p)) - (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)))) + (let ((frame (window-frame (minibuffer-window))) + (msg (current-message))) + ;; Check whether the frame where current window's minibuffer resides (not + ;; current window's frame for floating windows!) must be adjusted. + (when (and msg + (exwm--terminal-p frame) + (or (cl-position ?\n msg) + (> (length msg) (frame-width frame)))) + (exwm--log) + (if dirty + (exwm-layout--refresh exwm-workspace--current) + (exwm--defer 0 #'exwm-layout--refresh exwm-workspace--current))))) ;;;###autoload (defun exwm-layout-enlarge-window (delta &optional horizontal) diff --git a/exwm-workspace.el b/exwm-workspace.el index 3e53a7a82..450a38135 100644 --- a/exwm-workspace.el +++ b/exwm-workspace.el @@ -162,22 +162,6 @@ NIL if FRAME is not a workspace" "Return t if FRAME is a workspace." (memq frame exwm-workspace--list)) -(defvar exwm-workspace--client-p-hash-table - (make-hash-table :test 'eq :weakness 'key) - "Used to cache the results of calling ‘exwm-workspace--client-p’.") - -(defsubst exwm-workspace--client-p (&optional frame) - "Return non-nil if FRAME is an emacsclient frame." - (let* ((frame (or frame (selected-frame))) - (cached-value - (gethash frame exwm-workspace--client-p-hash-table 'absent))) - (if (eq cached-value 'absent) - (puthash frame - (or (frame-parameter frame 'client) - (not (display-graphic-p frame))) - exwm-workspace--client-p-hash-table) - cached-value))) - (defvar exwm-workspace--switch-map nil "Keymap used for interactively selecting workspace.") @@ -1126,7 +1110,7 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first." (defun exwm-workspace--update-minibuffer-height (&optional echo-area) "Update the minibuffer frame height." - (unless (exwm-workspace--client-p) + (when (exwm--terminal-p) (let ((height (with-current-buffer (window-buffer (minibuffer-window exwm-workspace--minibuffer)) @@ -1243,7 +1227,7 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first." "Run in minibuffer-setup-hook to show the minibuffer and its container." (exwm--log) (when (and (= 1 (minibuffer-depth)) - (not (exwm-workspace--client-p))) + (exwm--terminal-p)) (add-hook 'post-command-hook #'exwm-workspace--update-minibuffer-height) (exwm-workspace--show-minibuffer)) ;; FIXME: This is a temporary fix for the *Completions* buffer not @@ -1265,16 +1249,16 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first." "Run in minibuffer-exit-hook to hide the minibuffer container." (exwm--log) (when (and (= 1 (minibuffer-depth)) - (not (exwm-workspace--client-p))) + (exwm--terminal-p)) (remove-hook 'post-command-hook #'exwm-workspace--update-minibuffer-height) (exwm-workspace--hide-minibuffer))) (defun exwm-workspace--on-echo-area-dirty () "Run when new message arrives to show the echo area and its container." (when (and (not (active-minibuffer-window)) - (not (exwm-workspace--client-p)) (or (current-message) - cursor-in-echo-area)) + cursor-in-echo-area) + (exwm--terminal-p)) (exwm-workspace--update-minibuffer-height t) (exwm-workspace--show-minibuffer) (unless (or (not exwm-workspace-display-echo-area-timeout) @@ -1297,7 +1281,7 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first." (defun exwm-workspace--on-echo-area-clear () "Run in echo-area-clear-hook to hide echo area container." - (unless (exwm-workspace--client-p) + (when (exwm--terminal-p) (unless (active-minibuffer-window) (exwm-workspace--hide-minibuffer)) (when exwm-workspace--display-echo-area-timer @@ -1455,8 +1439,7 @@ Return nil if FRAME is the only workspace." ((not (exwm-workspace--workspace-p frame)) (exwm--log "Frame `%s' is not a workspace" frame)) (t - (exwm-workspace--remove-frame-as-workspace frame) - (remhash frame exwm-workspace--client-p-hash-table)))) + (exwm-workspace--remove-frame-as-workspace frame)))) (defun exwm-workspace--fullscreen-workspace (frame) "Make workspace FRAME fullscreen. @@ -1471,6 +1454,11 @@ Called from a timer." (exwm--log "Frame `%s' is already a workspace" frame)) ((not (display-graphic-p frame)) (exwm--log "Frame `%s' is not graphical" frame)) + ((not (eq (frame-terminal) exwm--terminal)) + (exwm--log "Frame `%s' is on a different terminal (%S instead of %S)" + frame + (frame-terminal frame) + exwm--terminal)) ((not (string-equal (replace-regexp-in-string "\\.0$" "" (slot-value exwm--connection 'display)) diff --git a/exwm.el b/exwm.el index 8a85002c4..ecce55c59 100644 --- a/exwm.el +++ b/exwm.el @@ -995,7 +995,7 @@ manager. If t, replace it, if nil, abort and ask the user if `ask'." "Confirm before killing terminal." ;; This is invoked instead of `save-buffers-kill-emacs' (C-x C-c) on client ;; frames. - (if (eq (frame-terminal) exwm--terminal) + (if (exwm--terminal-p) (exwm--confirm-kill-emacs "[EXWM] Kill terminal?") t)) From e042832b2b598336bdec0acb12fc34aefcd18564 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Sun, 24 Jul 2022 12:42:17 -0700 Subject: [PATCH 07/20] Hide tab-bar on floating windows Floating windows are dedicated to a specific buffer anyways. * exwm-floating.el (exwm-floating--set-floating): Hide the tab bar. --- exwm-floating.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exwm-floating.el b/exwm-floating.el index a9f9315b7..69e86a24e 100644 --- a/exwm-floating.el +++ b/exwm-floating.el @@ -161,6 +161,8 @@ context of the corresponding buffer." (get-buffer "*scratch*"))) (make-frame `((minibuffer . ,(minibuffer-window exwm--frame)) + (tab-bar-lines . 0) + (tab-bar-lines-keep-state . t) (left . ,(* window-min-width -10000)) (top . ,(* window-min-height -10000)) (width . ,window-min-width) From ce2191c444ae29edf669790a1002238b8fc90ac4 Mon Sep 17 00:00:00 2001 From: Manuel Giraud Date: Wed, 12 Oct 2022 10:47:11 +0200 Subject: [PATCH 08/20] Focus workspace frames upon _NET_ACTIVE_WINDOW * exwm.el (exwm--on-ClientMessage): Take care of focusing workspace frames when a _NET_ACTIVE_WINDOW message is received for a workspace frame. This is responsibility of the window manager when it advertises _NET_ACTIVE_WINDOW support, which we do. Emacs versions before 29 took care of setting the input focus to the frame. Thanks-to: Po Lu for the work on Emacs and assistance with this issue. --- exwm.el | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/exwm.el b/exwm.el index b025f6b49..1bfeb3638 100644 --- a/exwm.el +++ b/exwm.el @@ -420,8 +420,8 @@ (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) + (exwm--log "atom=%s(%s) id=#x%x data=%s" (x-get-atom-name type exwm-workspace--current) + type (or id 0) data) (cond ;; _NET_NUMBER_OF_DESKTOPS. ((= type xcb:Atom:_NET_NUMBER_OF_DESKTOPS) @@ -443,7 +443,8 @@ ((= type xcb:Atom:_NET_ACTIVE_WINDOW) (let ((buffer (exwm--id->buffer id)) iconic window) - (when (buffer-live-p buffer) + (if (buffer-live-p buffer) + ;; Either an `exwm-mode' buffer (an X window) or a floating frame. (with-current-buffer buffer (when (eq exwm--frame exwm-workspace--current) (if exwm--floating-frame @@ -457,7 +458,11 @@ (setq window (get-buffer-window nil t)) (when (or iconic (not (eq window (selected-window)))) - (select-window window)))))))) + (select-window window))))) + ;; A workspace. + (dolist (f exwm-workspace--list) + (when (eq id (frame-parameter f 'exwm-outer-id)) + (x-focus-frame f t)))))) ;; _NET_CLOSE_WINDOW. ((= type xcb:Atom:_NET_CLOSE_WINDOW) (let ((buffer (exwm--id->buffer id))) From 0a2c03ed597a27ff1ab06751b39618018f6d9deb Mon Sep 17 00:00:00 2001 From: James Date: Sun, 23 Oct 2022 19:34:40 +0200 Subject: [PATCH 09/20] Fix logging order in exwm-workspace--set-active * exwm-workspace.el (exwm-workspace--set-active): Swap logging arguments to match message. Copyright-paperwork-exempt: yes --- exwm-workspace.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exwm-workspace.el b/exwm-workspace.el index fc68e1b07..12319958c 100644 --- a/exwm-workspace.el +++ b/exwm-workspace.el @@ -444,7 +444,7 @@ NIL if FRAME is not a workspace" (defun exwm-workspace--set-active (frame active) "Make frame FRAME active on its monitor." - (exwm--log "active=%s; frame=%s" frame active) + (exwm--log "active=%s; frame=%s" active frame) (set-frame-parameter frame 'exwm-active active) (if active (exwm-workspace--set-fullscreen frame) From b8d621041ade27480124c920d38673a21491e8a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Medra=C3=B1o=20Calvo?= Date: Fri, 4 Nov 2022 00:00:00 +0000 Subject: [PATCH 10/20] Use default visual, depth and colormap in systray embedder window We were using the Emacs' frame's depth, but not the visual nor colormap. This failed with Emacs 29 and its support for 32-bit depths. We now use the default screen's visual: using a non-default visual in the system tray requires support for embedding icons with different visuals, which is not implemented. We restrict our limited transparency support to Emacs frames with depth equal to the default visual's detph. * exwm-core.el (exwm--get-visual-depth-colormap): New function. * exwm-systemtray.el (exwm-systemtray--init): Use root window's visual, depth and colormap. Reset all attributes that refer (perhaps due to defaults) to the parent window, as it might have a different visual, depth or colormap. (exwm-systemtray--init): Set _NET_SYSTEM_TRAY_VISUAL. (exwm-systemtray-background-color): Emit a warning when transparency is selected but not supported. (exwm-systemtray--set-background-color): New function to set embedder window background. (exwm-systemtray--embedder-window-depth): Add variable. (exwm-systemtray--transparency-supported-p): New function to check whether transparency is supported. --- exwm-systemtray.el | 157 +++++++++++++++++++++++++++++++++------------ 1 file changed, 115 insertions(+), 42 deletions(-) diff --git a/exwm-systemtray.el b/exwm-systemtray.el index 43b3e1eae..776aced4c 100644 --- a/exwm-systemtray.el +++ b/exwm-systemtray.el @@ -67,44 +67,51 @@ You shall use the default value if using auto-hide minibuffer." "Gap between icons." :type 'integer) +(defvar exwm-systemtray--connection nil "The X connection.") + (defvar exwm-systemtray--embedder-window nil "The embedder window.") +(defvar exwm-systemtray--embedder-window-depth nil + "The embedder window's depth.") -(defcustom exwm-systemtray-background-color nil +(defcustom exwm-systemtray-background-color + (if (exwm-systemtray--transparency-supported-p) + "black" + 'transparent) "Background color of systemtray. +This should be a color, the symbol `workspace-background' for the background +color of current workspace frame, or the symbol `transparent' for transparent +background. -This should be a color, or nil for transparent background." - :type '(choice (const :tag "Transparent" nil) +Transparent background is not yet supported when Emacs uses 32-bit depth +visual, as reported by `x-display-planes'. The X resource \"Emacs.visualClass: +TrueColor-24\" can be used to force Emacs to use 24-bit depth." + :type '(choice (const :tag "Transparent" 'transparent) (color)) :initialize #'custom-initialize-default :set (lambda (symbol value) + (when (and (eq value 'transparent) + (not (exwm-systemtray--transparency-supported-p))) + (display-warning 'exwm-systemtray + "Transparent background is not supported yet when \ +using 32-bit depth. Using black instead.") + (setq value "black")) (set-default symbol value) - ;; Change the background color for embedder. - (when (and exwm--connection + (when (and exwm-systemtray--connection exwm-systemtray--embedder-window) - (let ((background-pixel (exwm--color->pixel value))) - (xcb:+request exwm--connection - (make-instance 'xcb:ChangeWindowAttributes - :window exwm-systemtray--embedder-window - :value-mask (logior xcb:CW:BackPixmap - (if background-pixel - xcb:CW:BackPixel 0)) - :background-pixmap - xcb:BackPixmap:ParentRelative - :background-pixel background-pixel)) - ;; Unmap & map to take effect immediately. - (xcb:+request exwm--connection - (make-instance 'xcb:UnmapWindow - :window exwm-systemtray--embedder-window)) - (xcb:+request exwm--connection - (make-instance 'xcb:MapWindow - :window exwm-systemtray--embedder-window)) - (xcb:flush exwm--connection))))) + ;; Change the background color for embedder. + (exwm-systemtray--set-background-color) + ;; Unmap & map to take effect immediately. + (xcb:+request exwm-systemtray--connection + (make-instance 'xcb:UnmapWindow + :window exwm-systemtray--embedder-window)) + (xcb:+request exwm-systemtray--connection + (make-instance 'xcb:MapWindow + :window exwm-systemtray--embedder-window)) + (xcb:flush exwm-systemtray--connection)))) ;; GTK icons require at least 16 pixels to show normally. (defconst exwm-systemtray--icon-min-size 16 "Minimum icon size.") -(defvar exwm-systemtray--connection nil "The X connection.") - (defvar exwm-systemtray--list nil "The icon list.") (defvar exwm-systemtray--selection-owner-window nil @@ -249,6 +256,61 @@ This should be a color, or nil for transparent background." :window exwm-systemtray--embedder-window)))) (xcb:flush exwm-systemtray--connection)) +(defun exwm-systemtray--set-background-color () + "Change the background color of the embedder. +The color is set according to `exwm-systemtray-background-color'. + +Note that this function does not change the current contents of the embedder +window; unmap & map are necessary for the background color to take effect." + (when (and exwm-systemtray--connection + exwm-systemtray--embedder-window) + (let* ((color (cl-case exwm-systemtray-background-color + ((transparent nil) ; nil means transparent as well + (if (exwm-systemtray--transparency-supported-p) + nil + (message "%s" "[EXWM] system tray does not support transparent background; using black instead") + "black")) + (t exwm-systemtray-background-color))) + (background-pixel (exwm--color->pixel color))) + (xcb:+request exwm-systemtray--connection + (make-instance 'xcb:ChangeWindowAttributes + :window exwm-systemtray--embedder-window + ;; Either-or. A `background-pixel' of nil + ;; means simulate transparency. We use + ;; `xcb:CW:BackPixmap' together with + ;; `xcb:BackPixmap:ParentRelative' do that, + ;; but this only works when the parent + ;; window's visual (Emacs') has the same + ;; visual depth. + :value-mask (if background-pixel + xcb:CW:BackPixel + xcb:CW:BackPixmap) + ;; Due to the :value-mask above, + ;; :background-pixmap only takes effect when + ;; `transparent' is requested and supported + ;; (visual depth of Emacs and of system tray + ;; are equal). Setting + ;; `xcb:BackPixmap:ParentRelative' when + ;; that's not the case would produce an + ;; `xcb:Match' error. + :background-pixmap xcb:BackPixmap:ParentRelative + :background-pixel background-pixel))))) + +(defun exwm-systemtray--transparency-supported-p () + "Check whether transparent background is supported. +EXWM system tray supports transparency when the visual depth of the system tray +window matches that of Emacs. The visual depth of the system tray window is the +default visual depth of the display. + +Sections \"Visual and background pixmap handling\" and +\"_NET_SYSTEM_TRAY_VISUAL\" of the System Tray Protocol Specification +\(https://specifications.freedesktop.org/systemtray-spec/systemtray-spec-latest.html#visuals) +indicate how to support actual transparency." + (let ((planes (x-display-planes))) + (if exwm-systemtray--embedder-window-depth + (= planes exwm-systemtray--embedder-window-depth) + (<= planes 24)))) + (defun exwm-systemtray--on-DestroyNotify (data _synthetic) "Unembed icons on DestroyNotify." (exwm--log) @@ -469,8 +531,7 @@ This should be a color, or nil for transparent background." :data xcb:systemtray:ORIENTATION:HORZ))) ;; Create the embedder. (let ((id (xcb:generate-id exwm-systemtray--connection)) - (background-pixel (exwm--color->pixel exwm-systemtray-background-color)) - frame parent depth y) + frame parent embedder-depth embedder-visual embedder-colormap y) (setq exwm-systemtray--embedder-window id) (if (exwm-workspace--minibuffer-own-frame-p) (setq frame exwm-workspace--minibuffer @@ -487,15 +548,21 @@ This should be a color, or nil for transparent background." 3) exwm-workspace--frame-y-offset exwm-systemtray-height))) - (setq parent (string-to-number (frame-parameter frame 'window-id)) - depth (slot-value (xcb:+request-unchecked+reply - exwm-systemtray--connection - (make-instance 'xcb:GetGeometry - :drawable parent)) - 'depth)) + (setq parent (string-to-number (frame-parameter frame 'window-id))) + ;; Use default depth, visual and colormap (from root window), instead of + ;; Emacs frame's. See Section "Visual and background pixmap handling" in + ;; "System Tray Protocol Specification 0.3". + (let* ((vdc (exwm--get-visual-depth-colormap exwm-systemtray--connection + exwm--root))) + (setq embedder-visual (car vdc)) + (setq embedder-depth (cadr vdc)) + (setq embedder-colormap (caddr vdc))) + ;; Note down the embedder window's depth. It will be used to check whether + ;; we can use xcb:BackPixmap:ParentRelative to emulate transparency. + (setq exwm-systemtray--embedder-window-depth embedder-depth) (xcb:+request exwm-systemtray--connection (make-instance 'xcb:CreateWindow - :depth depth + :depth embedder-depth :wid id :parent parent :x 0 @@ -504,19 +571,24 @@ This should be a color, or nil for transparent background." :height exwm-systemtray-height :border-width 0 :class xcb:WindowClass:InputOutput - :visual 0 - :value-mask (logior xcb:CW:BackPixmap - (if background-pixel - xcb:CW:BackPixel 0) + :visual embedder-visual + :colormap embedder-colormap + :value-mask (logior xcb:CW:BorderPixel + xcb:CW:Colormap xcb:CW:EventMask) - :background-pixmap xcb:BackPixmap:ParentRelative - :background-pixel background-pixel + :border-pixel 0 :event-mask xcb:EventMask:SubstructureNotify)) + (exwm-systemtray--set-background-color) ;; Set _NET_WM_NAME. (xcb:+request exwm-systemtray--connection (make-instance 'xcb:ewmh:set-_NET_WM_NAME :window id - :data "EXWM: exwm-systemtray--embedder-window"))) + :data "EXWM: exwm-systemtray--embedder-window")) + ;; Set _NET_SYSTEM_TRAY_VISUAL. + (xcb:+request exwm-systemtray--connection + (make-instance 'xcb:xembed:set-_NET_SYSTEM_TRAY_VISUAL + :window exwm-systemtray--selection-owner-window + :data embedder-visual))) (xcb:flush exwm-systemtray--connection) ;; Attach event listeners. (xcb:+event exwm-systemtray--connection 'xcb:DestroyNotify @@ -564,7 +636,8 @@ This should be a color, or nil for transparent background." (setq exwm-systemtray--connection nil exwm-systemtray--list nil exwm-systemtray--selection-owner-window nil - exwm-systemtray--embedder-window nil) + exwm-systemtray--embedder-window nil + exwm-systemtray--embedder-window-depth nil) (remove-hook 'exwm-workspace-switch-hook #'exwm-systemtray--on-workspace-switch) (remove-hook 'exwm-workspace--update-workareas-hook From 07b9b2ccf83ec8c96098faa30810058ac3befa67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Medra=C3=B1o=20Calvo?= Date: Fri, 4 Nov 2022 00:00:00 +0000 Subject: [PATCH 11/20] Support setting system tray background color to current workspace's * exwm-systemtray.el (exwm-systemtray-background-color): Add support for using current workspace's background color as system tray background color. (exwm-systemtray--refresh-background-color): New function to set the background color upon theme changes or workspace switches. (exwm-systemtray--on-workspace-switch) (exwm-systemtray--on-theme-change): Use it. (exwm-systemtray--init): React to theme changes. --- exwm-systemtray.el | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/exwm-systemtray.el b/exwm-systemtray.el index 776aced4c..841b80f00 100644 --- a/exwm-systemtray.el +++ b/exwm-systemtray.el @@ -75,7 +75,7 @@ You shall use the default value if using auto-hide minibuffer." (defcustom exwm-systemtray-background-color (if (exwm-systemtray--transparency-supported-p) - "black" + 'workspace-background 'transparent) "Background color of systemtray. This should be a color, the symbol `workspace-background' for the background @@ -85,16 +85,17 @@ background. Transparent background is not yet supported when Emacs uses 32-bit depth visual, as reported by `x-display-planes'. The X resource \"Emacs.visualClass: TrueColor-24\" can be used to force Emacs to use 24-bit depth." - :type '(choice (const :tag "Transparent" 'transparent) - (color)) + :type '(choice (const :tag "Transparent" transparent) + (const :tag "Frame background" workspace-background) + (color :tag "Color")) :initialize #'custom-initialize-default :set (lambda (symbol value) (when (and (eq value 'transparent) (not (exwm-systemtray--transparency-supported-p))) (display-warning 'exwm-systemtray "Transparent background is not supported yet when \ -using 32-bit depth. Using black instead.") - (setq value "black")) +using 32-bit depth. Using `workspace-background' instead.") + (setq value 'workspace-background)) (set-default symbol value) (when (and exwm-systemtray--connection exwm-systemtray--embedder-window) @@ -256,6 +257,12 @@ using 32-bit depth. Using black instead.") :window exwm-systemtray--embedder-window)))) (xcb:flush exwm-systemtray--connection)) +(defun exwm-systemtray--refresh-background-color () + "Refresh background color after theme change or workspace switch." + ;; Only `workspace-background' is dependent on current theme and workspace. + (when (eq 'workspace-background exwm-systemtray-background-color) + (exwm-systemtray--set-background-color))) + (defun exwm-systemtray--set-background-color () "Change the background color of the embedder. The color is set according to `exwm-systemtray-background-color'. @@ -268,8 +275,11 @@ window; unmap & map are necessary for the background color to take effect." ((transparent nil) ; nil means transparent as well (if (exwm-systemtray--transparency-supported-p) nil - (message "%s" "[EXWM] system tray does not support transparent background; using black instead") - "black")) + (message "%s" "[EXWM] system tray does not support \ +`transparent' background; using `workspace-background' instead") + (face-background 'default exwm-workspace--current))) + (workspace-background + (face-background 'default exwm-workspace--current)) (t exwm-systemtray-background-color))) (background-pixel (exwm--color->pixel color))) (xcb:+request exwm-systemtray--connection @@ -437,8 +447,13 @@ indicate how to support actual transparency." 3) exwm-workspace--frame-y-offset exwm-systemtray-height)))) + (exwm-systemtray--refresh-background-color) (exwm-systemtray--refresh)) +(defun exwm-systemtray--on-theme-change () + "Refresh system tray upon theme change." + (exwm-systemtray--refresh-background-color)) + (defun exwm-systemtray--refresh-all () "Reposition/Refresh the system tray." (exwm--log) @@ -608,6 +623,9 @@ indicate how to support actual transparency." (add-hook 'exwm-workspace-switch-hook #'exwm-systemtray--on-workspace-switch) (add-hook 'exwm-workspace--update-workareas-hook #'exwm-systemtray--refresh-all) + ;; Add hook to update background colors. + (add-hook 'enable-theme-functions #'exwm-systemtray--on-theme-change) + (add-hook 'disable-theme-functions #'exwm-systemtray--on-theme-change) (add-hook 'menu-bar-mode-hook #'exwm-systemtray--refresh-all) (add-hook 'tool-bar-mode-hook #'exwm-systemtray--refresh-all) (when (boundp 'exwm-randr-refresh-hook) @@ -642,6 +660,8 @@ indicate how to support actual transparency." #'exwm-systemtray--on-workspace-switch) (remove-hook 'exwm-workspace--update-workareas-hook #'exwm-systemtray--refresh-all) + (remove-hook 'enable-theme-functions #'exwm-systemtray--on-theme-change) + (remove-hook 'disable-theme-functions #'exwm-systemtray--on-theme-change) (remove-hook 'menu-bar-mode-hook #'exwm-systemtray--refresh-all) (remove-hook 'tool-bar-mode-hook #'exwm-systemtray--refresh-all) (when (boundp 'exwm-randr-refresh-hook) From f93bfb21f76158e074eff388f7bda0be8511930c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Medra=C3=B1o=20Calvo?= Date: Fri, 4 Nov 2022 00:00:00 +0000 Subject: [PATCH 12/20] * exwm-systemtray.el (exwm-systemtray--init): Set EWMH window type to dock. --- exwm-systemtray.el | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/exwm-systemtray.el b/exwm-systemtray.el index 841b80f00..8b6360e99 100644 --- a/exwm-systemtray.el +++ b/exwm-systemtray.el @@ -1,7 +1,7 @@ ;;; exwm-systemtray.el --- System Tray Module for -*- lexical-binding: t -*- ;;; EXWM -;; Copyright (C) 2016-2021 Free Software Foundation, Inc. +;; Copyright (C) 2016-2022 Free Software Foundation, Inc. ;; Author: Chris Feng @@ -30,6 +30,7 @@ ;;; Code: +(require 'xcb-ewmh) (require 'xcb-icccm) (require 'xcb-xembed) (require 'xcb-systemtray) @@ -599,6 +600,11 @@ indicate how to support actual transparency." (make-instance 'xcb:ewmh:set-_NET_WM_NAME :window id :data "EXWM: exwm-systemtray--embedder-window")) + ;; Set _NET_WM_WINDOW_TYPE. + (xcb:+request exwm-systemtray--connection + (make-instance 'xcb:ewmh:set-_NET_WM_WINDOW_TYPE + :window id + :data (vector xcb:Atom:_NET_WM_WINDOW_TYPE_DOCK))) ;; Set _NET_SYSTEM_TRAY_VISUAL. (xcb:+request exwm-systemtray--connection (make-instance 'xcb:xembed:set-_NET_SYSTEM_TRAY_VISUAL From b3766e52d639a500e792f38572e79c2f6f044625 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Sat, 5 Nov 2022 08:21:05 -0700 Subject: [PATCH 13/20] * exwm-systemtray.el (exwm-systemtray--on-theme-change): Add missing parameter. --- exwm-systemtray.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exwm-systemtray.el b/exwm-systemtray.el index 8b6360e99..d2bd428c8 100644 --- a/exwm-systemtray.el +++ b/exwm-systemtray.el @@ -451,7 +451,7 @@ indicate how to support actual transparency." (exwm-systemtray--refresh-background-color) (exwm-systemtray--refresh)) -(defun exwm-systemtray--on-theme-change () +(defun exwm-systemtray--on-theme-change (_theme) "Refresh system tray upon theme change." (exwm-systemtray--refresh-background-color)) From e95b9ebf1d3dc8e78ae02875f388a2876d54dd94 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Sat, 5 Nov 2022 08:21:39 -0700 Subject: [PATCH 14/20] Refresh the tray icon background when updating the background color * exwm-systemtray.el (exwm-systemtray--refresh-background-color): Add optional parameter REMAP to force redrawing of the background. (exwm-systemtray--on-theme-change): Use it. --- exwm-systemtray.el | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/exwm-systemtray.el b/exwm-systemtray.el index d2bd428c8..62e034ef7 100644 --- a/exwm-systemtray.el +++ b/exwm-systemtray.el @@ -258,11 +258,21 @@ using 32-bit depth. Using `workspace-background' instead.") :window exwm-systemtray--embedder-window)))) (xcb:flush exwm-systemtray--connection)) -(defun exwm-systemtray--refresh-background-color () - "Refresh background color after theme change or workspace switch." +(defun exwm-systemtray--refresh-background-color (&optional remap) + "Refresh background color after theme change or workspace switch. +If REMAP is not nil, map and unmap the embedder window so that the background is +redrawn." ;; Only `workspace-background' is dependent on current theme and workspace. (when (eq 'workspace-background exwm-systemtray-background-color) - (exwm-systemtray--set-background-color))) + (exwm-systemtray--set-background-color) + (when remap + (xcb:+request exwm-systemtray--connection + (make-instance 'xcb:UnmapWindow + :window exwm-systemtray--embedder-window)) + (xcb:+request exwm-systemtray--connection + (make-instance 'xcb:MapWindow + :window exwm-systemtray--embedder-window)) + (xcb:flush exwm-systemtray--connection)))) (defun exwm-systemtray--set-background-color () "Change the background color of the embedder. @@ -453,7 +463,7 @@ indicate how to support actual transparency." (defun exwm-systemtray--on-theme-change (_theme) "Refresh system tray upon theme change." - (exwm-systemtray--refresh-background-color)) + (exwm-systemtray--refresh-background-color 'remap)) (defun exwm-systemtray--refresh-all () "Reposition/Refresh the system tray." From 3fb1ebe58c182a3cb7a6b8630f08b44f77fa6bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Medra=C3=B1o=20Calvo?= Date: Wed, 9 Nov 2022 00:00:00 +0000 Subject: [PATCH 15/20] Default exwm-systemtray color to `workspace-background' * exwm-systemtray.el (exwm-systemtray-background-color): Change default to `workspace-background', as it's supported in all configurations. --- exwm-systemtray.el | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/exwm-systemtray.el b/exwm-systemtray.el index 62e034ef7..8bb5bcc3c 100644 --- a/exwm-systemtray.el +++ b/exwm-systemtray.el @@ -74,10 +74,7 @@ You shall use the default value if using auto-hide minibuffer." (defvar exwm-systemtray--embedder-window-depth nil "The embedder window's depth.") -(defcustom exwm-systemtray-background-color - (if (exwm-systemtray--transparency-supported-p) - 'workspace-background - 'transparent) +(defcustom exwm-systemtray-background-color 'workspace-background "Background color of systemtray. This should be a color, the symbol `workspace-background' for the background color of current workspace frame, or the symbol `transparent' for transparent From e9cc0962cc478640afe3001e39ff32577d73d6a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Medra=C3=B1o=20Calvo?= Date: Fri, 11 Nov 2022 00:00:00 +0000 Subject: [PATCH 16/20] Bump version to 0.27 --- exwm.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exwm.el b/exwm.el index 1bfeb3638..61595634e 100644 --- a/exwm.el +++ b/exwm.el @@ -4,7 +4,7 @@ ;; Author: Chris Feng ;; Maintainer: Adrián Medraño Calvo -;; Version: 0.26 +;; Version: 0.27 ;; Package-Requires: ((xelb "0.18")) ;; Keywords: unix ;; URL: https://github.com/ch11ng/exwm From 4e1bb33f3782e82bacf2940eeb22f4b1e3daef76 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 25 Jul 2022 09:33:05 -0700 Subject: [PATCH 17/20] Add a module for setting the X background When enabled, EXWM will automatically set the background color either the user-specified color, or theme's default background color. This will even work with compositors such as picom. * background.el: add it. * exwm-core (exwm--intern-atom): optionally take a conn. --- exwm-background.el | 201 +++++++++++++++++++++++++++++++++++++++++++++ exwm-core.el | 4 +- 2 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 exwm-background.el diff --git a/exwm-background.el b/exwm-background.el new file mode 100644 index 000000000..e7a0360c9 --- /dev/null +++ b/exwm-background.el @@ -0,0 +1,201 @@ +;;; exwm-background.el --- X Background Module for EXWM -*- lexical-binding: t -*- + +;; Copyright (C) 2022 Free Software Foundation, Inc. + +;; Author: Steven Allen + +;; 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 . + +;;; Commentary: + +;; This module adds X background color setting support to EXWM. + +;; To use this module, load and enable it as follows: +;; (require 'exwm-background) +;; (exwm-background-enable) +;; +;; By default, this will apply the theme's background color. However, that +;; color can be customized via the `exwm-background-color' setting. + +;;; Code: + +(require 'exwm-core) + +(defcustom exwm-background-color nil + "Background color for Xorg." + :type '(choice + (color :tag "Background Color") + (const :tag "Default" nil)) + :group 'exwm + :initialize #'custom-initialize-default + :set (lambda (symbol value) + (set-default-toplevel-value symbol value) + (exwm-background--update))) + +(defconst exwm-background--properties '("_XROOTPMAP_ID" "_XSETROOT_ID" "ESETROOT_PMAP_ID") + "The background properties to set. +We can't need to set these so that compositing window managers can correctly display the background +color.") + +(defvar exwm-background--connection nil + "The X connection used for setting the background. +We use a separate connection as other background-setting tools may kill this connection when they +replace it.") + +(defvar exwm-background--pixmap nil + "Cached background pixmap.") + +(defvar exwm-background--atoms nil + "Cached background atoms.") + +(defun exwm-background--update (&rest _) + "Update the EXWM background." + + ;; Always reconnect as any tool that sets the background may have disconnected us (to force X to + ;; free resources). + (exwm-background--connect) + + (let ((gc (xcb:generate-id exwm-background--connection)) + (color (exwm--color->pixel (or exwm-background-color + (face-background 'default))))) + ;; Fill the pixmap. + (xcb:+request exwm-background--connection + (make-instance 'xcb:CreateGC + :cid gc :drawable exwm-background--pixmap + :value-mask (logior xcb:GC:Foreground + xcb:GC:GraphicsExposures) + :foreground color + :graphics-exposures 0)) + + (xcb:+request exwm-background--connection + (make-instance 'xcb:PolyFillRectangle + :gc gc :drawable exwm-background--pixmap + :rectangles + (list + (make-instance + 'xcb:RECTANGLE + :x 0 :y 0 :width 1 :height 1)))) + (xcb:+request exwm-background--connection (make-instance 'xcb:FreeGC :gc gc))) + + ;; Reapply it to force an update (also clobber anyone else who may have set it). + (xcb:+request exwm-background--connection + (make-instance 'xcb:ChangeWindowAttributes + :window exwm--root + :value-mask xcb:CW:BackPixmap + :background-pixmap exwm-background--pixmap)) + + (let (old) + ;; Collect old pixmaps so we can kill other background clients (all the background setting tools + ;; seem to do this). + (dolist (atom exwm-background--atoms) + (when-let* ((reply (xcb:+request-unchecked+reply exwm-background--connection + (make-instance 'xcb:GetProperty + :delete 0 + :window exwm--root + :property atom + :type xcb:Atom:PIXMAP + :long-offset 0 + :long-length 1))) + (value (vconcat (slot-value reply 'value))) + ((length= value 4)) + (pixmap (funcall (if xcb:lsb #'xcb:-unpack-u4-lsb #'xcb:-unpack-u4) + value 0)) + ((not (or (= pixmap exwm-background--pixmap) + (member pixmap old))))) + (push pixmap old))) + + ;; Change the background. + (dolist (atom exwm-background--atoms) + (xcb:+request exwm-background--connection + (make-instance 'xcb:ChangeProperty + :window exwm--root + :property atom + :type xcb:Atom:PIXMAP + :format 32 + :mode xcb:PropMode:Replace + :data-len 1 + :data + (funcall (if xcb:lsb + #'xcb:-pack-u4-lsb + #'xcb:-pack-u4) + exwm-background--pixmap)))) + + ;; Kill the old background clients. + (dolist (pixmap old) + (xcb:+request exwm-background--connection + (make-instance 'xcb:KillClient :resource pixmap)))) + + (xcb:flush exwm-background--connection)) + +(defun exwm-background--connected-p () + (and exwm-background--connection + (process-live-p (slot-value exwm-background--connection 'process)))) + +(defun exwm-background--connect () + (unless (exwm-background--connected-p) + (setq exwm-background--connection (xcb:connect)) + ;;prevent query message on exit + (set-process-query-on-exit-flag (slot-value exwm-background--connection 'process) nil) + + ;; Intern the background property atoms. + (setq exwm-background--atoms + (mapcar + (lambda (prop) (exwm--intern-atom prop exwm-background--connection)) + exwm-background--properties)) + + ;; Create the pixmap. + (setq exwm-background--pixmap (xcb:generate-id exwm-background--connection)) + (xcb:+request exwm-background--connection + (make-instance 'xcb:CreatePixmap + :depth + (slot-value + (xcb:+request-unchecked+reply exwm-background--connection + (make-instance 'xcb:GetGeometry :drawable exwm--root)) + 'depth) + :pid exwm-background--pixmap + :drawable exwm--root + :width 1 :height 1)))) + +(defun exwm-background--init () + "Initialize background module." + (exwm--log) + + (add-hook 'enable-theme-functions 'exwm-background--update) + (add-hook 'disable-theme-functions 'exwm-background--update) + + (exwm-background--update)) + +(defun exwm-background--exit () + "Uninitialize the background module." + (exwm--log) + + (remove-hook 'enable-theme-functions 'exwm-background--update) + (remove-hook 'disable-theme-functions 'exwm-background--update) + (when exwm-background--connection + (xcb:disconnect exwm-background--connection)) + (setq exwm-background--pixmap nil + exwm-background--connection nil + exwm-background--atoms nil)) + +(defun exwm-background-enable () + "Enable background support for EXWM." + (exwm--log) + (add-hook 'exwm-init-hook #'exwm-background--init) + (add-hook 'exwm-exit-hook #'exwm-background--exit)) + +(provide 'exwm-background) + +;;; exwm-background.el ends here diff --git a/exwm-core.el b/exwm-core.el index 995b590dc..3215dcdd2 100644 --- a/exwm-core.el +++ b/exwm-core.el @@ -155,9 +155,9 @@ Nil can be passed as placeholder." (if height xcb:ConfigWindow:Height 0)) :x x :y y :width width :height height))) -(defun exwm--intern-atom (atom) +(defun exwm--intern-atom (atom &optional conn) "Intern X11 ATOM." - (slot-value (xcb:+request-unchecked+reply exwm--connection + (slot-value (xcb:+request-unchecked+reply (or conn exwm--connection) (make-instance 'xcb:InternAtom :only-if-exists 0 :name-len (length atom) From cb0093411b89d4da668957cb489885885a585448 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Sat, 6 Aug 2022 15:01:40 -0700 Subject: [PATCH 18/20] Pick the correct line height for the systemtray * exwm-systemtray.el (exwm-systemtray--init): Use the line-height of the minibuffer-window, not that of the selected one. --- exwm-systemtray.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exwm-systemtray.el b/exwm-systemtray.el index 8bb5bcc3c..0f1998662 100644 --- a/exwm-systemtray.el +++ b/exwm-systemtray.el @@ -487,7 +487,8 @@ indicate how to support actual transparency." (cl-assert (not exwm-systemtray--embedder-window)) (unless exwm-systemtray-height (setq exwm-systemtray-height (max exwm-systemtray--icon-min-size - (line-pixel-height)))) + (with-selected-window (minibuffer-window) + (line-pixel-height))))) ;; Create a new connection. (setq exwm-systemtray--connection (xcb:connect)) (set-process-query-on-exit-flag (slot-value exwm-systemtray--connection From 8e0c5ee327f4196c71395407f9084e68d7322c45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Medra=C3=B1o=20Calvo?= Date: Tue, 22 Nov 2022 00:00:00 +0000 Subject: [PATCH 19/20] Reduce logging verbosity * exwm-input.el (exwm-input--on-echo-area-dirty) (exwm-input--on-echo-area-clear): Reduce logging verbosity. --- exwm-input.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exwm-input.el b/exwm-input.el index c27ee1b04..8fd0af50d 100644 --- a/exwm-input.el +++ b/exwm-input.el @@ -1121,16 +1121,16 @@ One use is to access the keymap bound to KEYS (as prefix keys) in char-mode." (defun exwm-input--on-echo-area-dirty () "Run when new message arrives to grab keyboard if necessary." - (exwm--log) (when (and (not (active-minibuffer-window)) (not (exwm-workspace--client-p)) cursor-in-echo-area) + (exwm--log) (exwm-input--on-minibuffer-setup))) (defun exwm-input--on-echo-area-clear () "Run in `echo-area-clear-hook' to release keyboard if necessary." - (exwm--log) (unless (current-message) + (exwm--log) (exwm-input--on-minibuffer-exit))) (defun exwm-input--init () From b62d5e79b0c1799f2cd941b4cec5bf8492cb322c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Medra=C3=B1o=20Calvo?= Date: Tue, 22 Nov 2022 00:00:00 +0000 Subject: [PATCH 20/20] Use `active-minibuffer-window' rather than `minibuffer-window' * exwm-layout.el (exwm-layout--on-minibuffer-setup) (exwm-layout--on-echo-area-change): Use `active-minibuffer-window`, instead of the minibuffer window of selected frame, as there's no guarantee that the selected frame is the frame containing the minibuffer. Also make sure the frame is an EXWM workspace. --- exwm-layout.el | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/exwm-layout.el b/exwm-layout.el index 3d78b4265..ea186fe5a 100644 --- a/exwm-layout.el +++ b/exwm-layout.el @@ -403,21 +403,22 @@ selected by `other-buffer'." (defun exwm-layout--on-minibuffer-setup () "Refresh layout when minibuffer grows." (exwm--log) - ;; Only when the minibuffer's frame is an EXWM frame. - ;; FIXME: would it be enough checking for workspace frames? - (when (exwm--terminal-p) - (exwm--defer 0 (lambda () - (when (< 1 (window-height (minibuffer-window))) - (exwm-layout--refresh)))))) + ;; Only when active minibuffer's frame is an EXWM frame. + (let* ((mini-window (active-minibuffer-window)) + (frame (window-frame mini-window))) + (when (exwm-workspace--workspace-p frame) + (exwm--defer 0 (lambda () + (when (< 1 (window-height mini-window))) + (exwm-layout--refresh frame)))))) (defun exwm-layout--on-echo-area-change (&optional dirty) "Run when message arrives or in `echo-area-clear-hook' to refresh layout." - (let ((frame (window-frame (minibuffer-window))) + (let ((frame (window-frame (active-minibuffer-window))) (msg (current-message))) ;; Check whether the frame where current window's minibuffer resides (not ;; current window's frame for floating windows!) must be adjusted. (when (and msg - (exwm--terminal-p frame) + (exwm-workspace--workspace-p frame) (or (cl-position ?\n msg) (> (length msg) (frame-width frame)))) (exwm--log)