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:
Chris Feng 2016-10-06 12:47:56 +08:00
parent 575162b6b6
commit 089afdc8cc
2 changed files with 47 additions and 42 deletions

View file

@ -337,9 +337,11 @@ context of the corresponding buffer.")
(setq window-size-fixed nil (setq window-size-fixed nil
exwm--floating-frame nil exwm--floating-frame nil
exwm--frame exwm-workspace--current)) exwm--frame exwm-workspace--current))
;; Only show X windows in normal state.
(unless (exwm-layout--iconic-state-p) (unless (exwm-layout--iconic-state-p)
;; Only show X windows in normal state. ;; Show it in the selected Emacs window but skip the mini-window.
(let ((window (frame-selected-window exwm-workspace--current))) (let ((window (or (minibuffer-selected-window)
(frame-selected-window exwm-workspace--current))))
(set-window-buffer window buffer) (set-window-buffer window buffer)
(select-window window)))) (select-window window))))
(with-current-buffer (exwm--id->buffer id) (with-current-buffer (exwm--id->buffer id)

View file

@ -158,8 +158,7 @@ This value should always be overwritten.")
(defun exwm-input--on-buffer-list-update () (defun exwm-input--on-buffer-list-update ()
"Run in `buffer-list-update-hook' to track input focus." "Run in `buffer-list-update-hook' to track input focus."
(when (and (not (minibufferp)) ;Do not set input focus on minibuffer window. (when (and (eq (current-buffer) (window-buffer)) ;e.g. `with-temp-buffer'.
(eq (current-buffer) (window-buffer)) ;e.g. `with-temp-buffer'.
(not (eq this-command #'handle-switch-frame)) (not (eq this-command #'handle-switch-frame))
(not (exwm-workspace--client-p))) (not (exwm-workspace--client-p)))
(setq exwm-input--update-focus-window (selected-window)) (setq exwm-input--update-focus-window (selected-window))
@ -209,9 +208,7 @@ This value should always be overwritten.")
(defun exwm-input--update-focus (window) (defun exwm-input--update-focus (window)
"Update input focus." "Update input focus."
(setq exwm-input--update-focus-lock t) (setq exwm-input--update-focus-lock t)
(when (and (window-live-p window) (when (window-live-p window)
;; Do not update input focus when there's an active minibuffer.
(not (active-minibuffer-window)))
(with-current-buffer (window-buffer window) (with-current-buffer (window-buffer window)
(if (eq major-mode 'exwm-mode) (if (eq major-mode 'exwm-mode)
(if (not (eq exwm--frame exwm-workspace--current)) (if (not (eq exwm--frame exwm-workspace--current))
@ -238,7 +235,15 @@ This value should always be overwritten.")
;; so switch to it. ;; so switch to it.
(exwm-workspace-switch (selected-frame)) (exwm-workspace-switch (selected-frame))
;; The focus is still on the current workspace. ;; 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) (exwm-input--set-active-window)
(xcb:flush exwm--connection)))))) (xcb:flush exwm--connection))))))
(setq exwm-input--update-focus-lock nil)) (setq exwm-input--update-focus-lock nil))
@ -256,20 +261,6 @@ This value should always be overwritten.")
:window exwm--root :window exwm--root
:data (or id xcb:Window:None)))) :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" (declare-function exwm-floating--start-moveresize "exwm-floating.el"
(id &optional type)) (id &optional type))
(declare-function exwm-workspace--position "exwm-workspace.el" (frame)) (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 (defvar exwm-input--during-command nil
"Indicate whether between `pre-command-hook' and `post-command-hook'.") "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) (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." "Parse X KeyPress event to Emacs key event and then feed the command loop."
(with-slots (detail state) key-press (with-slots (detail state) key-press
(let ((keysym (xcb:keysyms:keycode->keysym exwm--connection detail state)) (let ((keysym (xcb:keysyms:keycode->keysym exwm--connection detail state))
event minibuffer-window mode) event mode)
(when (and (/= 0 (car keysym)) (when (and (/= 0 (car keysym))
(setq event (xcb:keysyms:keysym->event (setq event (xcb:keysyms:keysym->event
exwm--connection (car keysym) exwm--connection (car keysym)
(logand state (lognot (cdr keysym))))) (logand state (lognot (cdr keysym)))))
(or exwm-input--during-key-sequence (or exwm-input--line-mode-passthrough
exwm-input--during-command 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--global-prefix-keys)
(memq event exwm-input-prefix-keys) (memq event exwm-input-prefix-keys)
(memq event exwm-input--simulation-prefix-keys))) (memq event exwm-input--simulation-prefix-keys)))
(setq mode xcb:Allow:AsyncKeyboard) (setq mode xcb:Allow:AsyncKeyboard)
(unless minibuffer-window (setq exwm-input--during-key-sequence t)) (exwm-input--cache-event event))
;; Feed this event to command loop. Also force it to be added to
;; `this-command-keys'.
(exwm-input--unread-event event))
(unless mode (unless mode
(if (= 0 (logand #x6000 state)) ;Check the 13~14 bits. (if (= 0 (logand #x6000 state)) ;Check the 13~14 bits.
;; Not an XKB state; just replay it. ;; Not an XKB state; just replay it.
@ -469,15 +481,9 @@ This value should always be overwritten.")
exwm--connection (car keysym) exwm--connection (car keysym)
(logand state (lognot (cdr keysym)))))) (logand state (lognot (cdr keysym))))))
(when (eq major-mode 'exwm-mode) (when (eq major-mode 'exwm-mode)
;; FIXME: This functionality seems not working, e.g. when this (setq exwm-input--temp-line-mode t)
;; 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)
(exwm-input--grab-keyboard)) ;grab keyboard temporarily (exwm-input--grab-keyboard)) ;grab keyboard temporarily
(setq unread-command-events (exwm-input--cache-event event))))
(append unread-command-events (list event))))))
(xcb:+request exwm--connection (xcb:+request exwm--connection
(make-instance 'xcb:AllowEvents (make-instance 'xcb:AllowEvents
:mode xcb:Allow:AsyncKeyboard :mode xcb:Allow:AsyncKeyboard
@ -609,7 +615,7 @@ This value should always be overwritten.")
(let (key keys) (let (key keys)
(dotimes (i times) (dotimes (i times)
;; Skip events not from keyboard ;; Skip events not from keyboard
(setq exwm-input--during-key-sequence t) (setq exwm-input--line-mode-passthrough t)
(catch 'break (catch 'break
(while t (while t
(setq key (read-key (format "Send key: %s (%d/%d)" (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)) (when (and (listp key) (eq (car key) t))
(setq key (cdr key))) (setq key (cdr key)))
(unless (listp key) (throw 'break nil)))) (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))) (setq keys (vconcat keys (vector key)))
(exwm-input--fake-key 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) (xcb:+event exwm--connection 'xcb:FocusIn #'exwm-input--on-FocusIn)
;; The input focus should be set on the frame when minibuffer is active. ;; The input focus should be set on the frame when minibuffer is active.
(add-hook 'minibuffer-setup-hook #'exwm-input--on-minibuffer-setup) (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' ;; Control `exwm-input--during-command'
(add-hook 'pre-command-hook #'exwm-input--on-pre-command) (add-hook 'pre-command-hook #'exwm-input--on-pre-command)
(add-hook 'post-command-hook #'exwm-input--on-post-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 () (defun exwm-input--exit ()
"Exit the input module." "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 'pre-command-hook #'exwm-input--on-pre-command)
(remove-hook 'post-command-hook #'exwm-input--on-post-command) (remove-hook 'post-command-hook #'exwm-input--on-post-command)
(remove-hook 'buffer-list-update-hook #'exwm-input--on-buffer-list-update) (remove-hook 'buffer-list-update-hook #'exwm-input--on-buffer-list-update)