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.
This commit is contained in:
		
							parent
							
								
									575162b6b6
								
							
						
					
					
						commit
						089afdc8cc
					
				
					 2 changed files with 47 additions and 42 deletions
				
			
		|  | @ -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) | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue