From 089afdc8ccbd37647f3b9d3b6181db5bcf3e43e9 Mon Sep 17 00:00:00 2001 From: Chris Feng Date: Thu, 6 Oct 2016 12:47:56 +0800 Subject: [PATCH] Fix problems with active minibuffer * exwm-floating.el (exwm-floating--unset-floating): Never use the minibuffer window to display an `exwm-mode' buffer. * exwm-input.el (exwm-input--on-buffer-list-update) (exwm-input--update-focus): Allow updating input focus when the minibuffer is active. (exwm-input--update-focus): Handle the case when an auto-hiding minibuffer is active. (exwm-input--during-key-sequence): Renamed to `exwm-input--line-mode-passthrough'. (exwm-input--line-mode-passthrough): New variable for forcing all events to be passed to Emacs in line-mode. (exwm-input--on-KeyPress-line-mode, exwm-input-send-next-key): Use it. (exwm-input--finish-key-sequence, exwm-input--init, exwm-input--exit): Drop `exwm-input--finish-key-sequence'. (exwm-input--line-mode-cache): New variable for caching incomplete key sequences. (exwm-input--cache-event): New function for handling new key events. (exwm-input--on-KeyPress-line-mode, exwm-input--on-KeyPress-char-mode): Use it. --- exwm-floating.el | 6 ++-- exwm-input.el | 83 +++++++++++++++++++++++++----------------------- 2 files changed, 47 insertions(+), 42 deletions(-) diff --git a/exwm-floating.el b/exwm-floating.el index 1780e5f..dffdc3c 100644 --- a/exwm-floating.el +++ b/exwm-floating.el @@ -337,9 +337,11 @@ context of the corresponding buffer.") (setq window-size-fixed nil exwm--floating-frame nil exwm--frame exwm-workspace--current)) + ;; Only show X windows in normal state. (unless (exwm-layout--iconic-state-p) - ;; Only show X windows in normal state. - (let ((window (frame-selected-window exwm-workspace--current))) + ;; Show it in the selected Emacs window but skip the mini-window. + (let ((window (or (minibuffer-selected-window) + (frame-selected-window exwm-workspace--current)))) (set-window-buffer window buffer) (select-window window)))) (with-current-buffer (exwm--id->buffer id) diff --git a/exwm-input.el b/exwm-input.el index b956f5c..4a8fdbb 100644 --- a/exwm-input.el +++ b/exwm-input.el @@ -158,8 +158,7 @@ This value should always be overwritten.") (defun exwm-input--on-buffer-list-update () "Run in `buffer-list-update-hook' to track input focus." - (when (and (not (minibufferp)) ;Do not set input focus on minibuffer window. - (eq (current-buffer) (window-buffer)) ;e.g. `with-temp-buffer'. + (when (and (eq (current-buffer) (window-buffer)) ;e.g. `with-temp-buffer'. (not (eq this-command #'handle-switch-frame)) (not (exwm-workspace--client-p))) (setq exwm-input--update-focus-window (selected-window)) @@ -209,9 +208,7 @@ This value should always be overwritten.") (defun exwm-input--update-focus (window) "Update input focus." (setq exwm-input--update-focus-lock t) - (when (and (window-live-p window) - ;; Do not update input focus when there's an active minibuffer. - (not (active-minibuffer-window))) + (when (window-live-p window) (with-current-buffer (window-buffer window) (if (eq major-mode 'exwm-mode) (if (not (eq exwm--frame exwm-workspace--current)) @@ -238,7 +235,15 @@ This value should always be overwritten.") ;; so switch to it. (exwm-workspace-switch (selected-frame)) ;; The focus is still on the current workspace. - (select-frame-set-input-focus (window-frame window) t) + (if (not (and (exwm-workspace--minibuffer-own-frame-p) + (minibufferp))) + (select-frame-set-input-focus (window-frame window) t) + ;; X input focus should be set on the previously selected + ;; frame. + (select-frame-set-input-focus (window-frame + (minibuffer-selected-window)) + t) + (select-frame (window-frame window) t)) (exwm-input--set-active-window) (xcb:flush exwm--connection)))))) (setq exwm-input--update-focus-lock nil)) @@ -256,20 +261,6 @@ This value should always be overwritten.") :window exwm--root :data (or id xcb:Window:None)))) -(defvar exwm-input--during-key-sequence nil - "Non-nil indicates Emacs is waiting for more keys to form a key sequence.") -(defvar exwm-input--temp-line-mode nil - "Non-nil indicates it's in temporary line-mode for char-mode.") - -(defun exwm-input--finish-key-sequence () - "Mark the end of a key sequence (with the aid of `pre-command-hook')." - (when (and exwm-input--during-key-sequence - (not (equal [?\C-u] (this-single-command-keys)))) - (setq exwm-input--during-key-sequence nil) - (when exwm-input--temp-line-mode - (setq exwm-input--temp-line-mode nil) - (exwm-input--release-keyboard)))) - (declare-function exwm-floating--start-moveresize "exwm-floating.el" (id &optional type)) (declare-function exwm-workspace--position "exwm-workspace.el" (frame)) @@ -415,26 +406,47 @@ This value should always be overwritten.") (defvar exwm-input--during-command nil "Indicate whether between `pre-command-hook' and `post-command-hook'.") +(defvar exwm-input--line-mode-passthrough nil + "Non-nil makes 'line-mode' forwards all events to Emacs.") + +(defvar exwm-input--line-mode-cache nil "Cache for incomplete key sequence.") + +(defvar exwm-input--temp-line-mode nil + "Non-nil indicates it's in temporary line-mode for char-mode.") + +(defun exwm-input--cache-event (event) + "Cache EVENT." + (setq exwm-input--line-mode-cache + (vconcat exwm-input--line-mode-cache (vector event))) + ;; When the key sequence is complete. + (unless (keymapp (key-binding exwm-input--line-mode-cache)) + (setq exwm-input--line-mode-cache nil) + (when exwm-input--temp-line-mode + (setq exwm-input--temp-line-mode nil) + (exwm-input--release-keyboard))) + (exwm-input--unread-event event)) + (defun exwm-input--on-KeyPress-line-mode (key-press raw-data) "Parse X KeyPress event to Emacs key event and then feed the command loop." (with-slots (detail state) key-press (let ((keysym (xcb:keysyms:keycode->keysym exwm--connection detail state)) - event minibuffer-window mode) + event mode) (when (and (/= 0 (car keysym)) (setq event (xcb:keysyms:keysym->event exwm--connection (car keysym) (logand state (lognot (cdr keysym))))) - (or exwm-input--during-key-sequence + (or exwm-input--line-mode-passthrough exwm-input--during-command - (setq minibuffer-window (active-minibuffer-window)) + ;; Forward the event when there is an incomplete key + ;; sequence or when the minibuffer is active. + exwm-input--line-mode-cache + (eq (active-minibuffer-window) (selected-window)) + ;; (memq event exwm-input--global-prefix-keys) (memq event exwm-input-prefix-keys) (memq event exwm-input--simulation-prefix-keys))) (setq mode xcb:Allow:AsyncKeyboard) - (unless minibuffer-window (setq exwm-input--during-key-sequence t)) - ;; Feed this event to command loop. Also force it to be added to - ;; `this-command-keys'. - (exwm-input--unread-event event)) + (exwm-input--cache-event event)) (unless mode (if (= 0 (logand #x6000 state)) ;Check the 13~14 bits. ;; Not an XKB state; just replay it. @@ -469,15 +481,9 @@ This value should always be overwritten.") exwm--connection (car keysym) (logand state (lognot (cdr keysym)))))) (when (eq major-mode 'exwm-mode) - ;; FIXME: This functionality seems not working, e.g. when this - ;; command would activate the minibuffer, the temporary - ;; line-mode would actually quit before the minibuffer - ;; becomes active. - (setq exwm-input--temp-line-mode t - exwm-input--during-key-sequence t) + (setq exwm-input--temp-line-mode t) (exwm-input--grab-keyboard)) ;grab keyboard temporarily - (setq unread-command-events - (append unread-command-events (list event)))))) + (exwm-input--cache-event event)))) (xcb:+request exwm--connection (make-instance 'xcb:AllowEvents :mode xcb:Allow:AsyncKeyboard @@ -609,7 +615,7 @@ This value should always be overwritten.") (let (key keys) (dotimes (i times) ;; Skip events not from keyboard - (setq exwm-input--during-key-sequence t) + (setq exwm-input--line-mode-passthrough t) (catch 'break (while t (setq key (read-key (format "Send key: %s (%d/%d)" @@ -618,7 +624,7 @@ This value should always be overwritten.") (when (and (listp key) (eq (car key) t)) (setq key (cdr key))) (unless (listp key) (throw 'break nil)))) - (setq exwm-input--during-key-sequence nil) + (setq exwm-input--line-mode-passthrough nil) (setq keys (vconcat keys (vector key))) (exwm-input--fake-key key)))) @@ -739,8 +745,6 @@ Its usage is the same with `exwm-input-set-simulation-keys'." (xcb:+event exwm--connection 'xcb:FocusIn #'exwm-input--on-FocusIn) ;; The input focus should be set on the frame when minibuffer is active. (add-hook 'minibuffer-setup-hook #'exwm-input--on-minibuffer-setup) - ;; `pre-command-hook' marks the end of a key sequence (existing or not) - (add-hook 'pre-command-hook #'exwm-input--finish-key-sequence) ;; Control `exwm-input--during-command' (add-hook 'pre-command-hook #'exwm-input--on-pre-command) (add-hook 'post-command-hook #'exwm-input--on-post-command) @@ -753,7 +757,6 @@ Its usage is the same with `exwm-input-set-simulation-keys'." (defun exwm-input--exit () "Exit the input module." - (remove-hook 'pre-command-hook #'exwm-input--finish-key-sequence) (remove-hook 'pre-command-hook #'exwm-input--on-pre-command) (remove-hook 'post-command-hook #'exwm-input--on-post-command) (remove-hook 'buffer-list-update-hook #'exwm-input--on-buffer-list-update)