Add support for attachable/detachable minibuffer

* exwm-workspace.el (exwm-workspace--update-minibuffer-height): Renamed
from `exwm-workspace--update-minibuffer' to better reflect its usage.

* exwm-input.el (exwm-input--update-focus): Directly put the floating
X window at top since the minibuffer is no longer a sibling.
* exwm-workspace.el (exwm-workspace--resize-minibuffer-frame): Calculate
position in absolute coordinate; put minibuffer at bottom by default;
resize the minibuffer frame with ConfigureWindow rather than
`set-frame-width'.
(exwm-workspace-switch): No need to reparent minibuffer any more.
(exwm-workspace--on-ConfigureNotify): Calculate position in absolute
coordinate.
(exwm-workspace--show-minibuffer, exwm-workspace--hide-minibuffer):
Show/Hide the minibuffer by adjusting the stacking order rather than
mapping/unmapping.
(exwm-workspace--init): Map the minibuffer frame container on creation.

* exwm-workspace.el (exwm-workspace--minibuffer-attached-p):
New function telling whether the minibuffer is attached.
(exwm-workspace--attached-minibuffer-height): New variable storing the
height of the attached minibuffer.
(exwm-workspace-attach-minibuffer, exwm-workspace-detach-minibuffer):
New functions for attaching/detaching the minibuffer.

* exwm-workspace.el (exwm-workspace--show-minibuffer): Remove the
workaround for minibuffer cursor (seems fixed).
This commit is contained in:
Chris Feng 2016-07-19 19:23:37 +08:00
parent 624c72945a
commit 3909f65bae
2 changed files with 113 additions and 59 deletions

View file

@ -125,24 +125,11 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
(exwm-input--set-focus exwm--id) (exwm-input--set-focus exwm--id)
(when exwm--floating-frame (when exwm--floating-frame
;; Adjust stacking orders of the floating container. ;; Adjust stacking orders of the floating container.
(if (exwm-workspace--minibuffer-own-frame-p) (xcb:+request exwm--connection
;; Put this floating X window just below the minibuffer. (make-instance 'xcb:ConfigureWindow
(xcb:+request exwm--connection :window exwm--container
(make-instance 'xcb:ConfigureWindow :value-mask xcb:ConfigWindow:StackMode
:window exwm--container :stack-mode xcb:StackMode:Above))
:value-mask
(logior xcb:ConfigWindow:Sibling
xcb:ConfigWindow:StackMode)
:sibling (frame-parameter
exwm-workspace--minibuffer
'exwm-container)
:stack-mode xcb:StackMode:Below))
;; Put this floating X window at top.
(xcb:+request exwm--connection
(make-instance 'xcb:ConfigureWindow
:window exwm--container
:value-mask xcb:ConfigWindow:StackMode
:stack-mode xcb:StackMode:Above)))
;; This floating X window might be hide by `exwm-floating-hide'. ;; This floating X window might be hide by `exwm-floating-hide'.
(when (exwm-layout--iconic-state-p) (when (exwm-layout--iconic-state-p)
(exwm-layout--set-state exwm--id (exwm-layout--set-state exwm--id

View file

@ -308,20 +308,32 @@ Value nil means to use the default position which is fixed at bottom, while
'exwm-container)) 'exwm-container))
y width) y width)
(setq y (if (eq exwm-workspace-minibuffer-position 'top) (setq y (if (eq exwm-workspace-minibuffer-position 'top)
0 (- (aref workarea 1)
(- (aref workarea 3) exwm-workspace--attached-minibuffer-height)
(frame-pixel-height exwm-workspace--minibuffer))) ;; Reset the frame size.
(set-frame-height exwm-workspace--minibuffer 1)
(redisplay) ;FIXME.
(+ (aref workarea 1) (aref workarea 3)
(- (frame-pixel-height exwm-workspace--minibuffer))
exwm-workspace--attached-minibuffer-height))
width (aref workarea 2)) width (aref workarea 2))
(xcb:+request exwm--connection (xcb:+request exwm--connection
(make-instance 'xcb:ConfigureWindow (make-instance 'xcb:ConfigureWindow
:window container :window container
:value-mask (logior xcb:ConfigWindow:Y :value-mask (logior xcb:ConfigWindow:X
xcb:ConfigWindow:Y
xcb:ConfigWindow:Width xcb:ConfigWindow:Width
xcb:ConfigWindow:StackMode) xcb:ConfigWindow:StackMode)
:x (aref workarea 0)
:y y :y y
:width width :width width
:stack-mode xcb:StackMode:Above)) :stack-mode xcb:StackMode:Below))
(set-frame-width exwm-workspace--minibuffer width nil t))) (xcb:+request exwm--connection
(make-instance 'xcb:ConfigureWindow
:window (frame-parameter exwm-workspace--minibuffer
'exwm-outer-id)
:value-mask xcb:ConfigWindow:Width
:width width))))
(defun exwm-workspace--switch-map-nth-prefix (&optional prefix-digits) (defun exwm-workspace--switch-map-nth-prefix (&optional prefix-digits)
"Allow selecting a workspace by number. "Allow selecting a workspace by number.
@ -428,17 +440,11 @@ The optional FORCE option is for internal use only."
;; Might be aborted by then. ;; Might be aborted by then.
(when (active-minibuffer-window) (when (active-minibuffer-window)
(abort-recursive-edit))))) (abort-recursive-edit)))))
(if (not (exwm-workspace--minibuffer-own-frame-p)) (if (exwm-workspace--minibuffer-own-frame-p)
(setq default-minibuffer-frame frame) ;; Resize the minibuffer frame.
;; Resize/reposition the minibuffer frame (exwm-workspace--resize-minibuffer-frame)
(xcb:+request exwm--connection ;; Set a default minibuffer frame.
(make-instance 'xcb:ReparentWindow (setq default-minibuffer-frame frame))
:window
(frame-parameter exwm-workspace--minibuffer
'exwm-container)
:parent (frame-parameter frame 'exwm-workspace)
:x 0 :y 0))
(exwm-workspace--resize-minibuffer-frame))
;; Hide windows in other workspaces by preprending a space ;; Hide windows in other workspaces by preprending a space
(unless exwm-workspace-show-all-buffers (unless exwm-workspace-show-all-buffers
(dolist (i exwm--id-buffer-alist) (dolist (i exwm--id-buffer-alist)
@ -778,8 +784,59 @@ INDEX must not exceed the current number of workspaces."
(xcb:flush exwm--connection) (xcb:flush exwm--connection)
frame)) frame))
(defun exwm-workspace--update-minibuffer (&optional echo-area) (defsubst exwm-workspace--minibuffer-attached-p ()
"Update the minibuffer frame." "Return non-nil if the minibuffer is attached.
Please check `exwm-workspace--minibuffer-own-frame-p' first."
(assq (frame-parameter exwm-workspace--minibuffer 'exwm-container)
exwm-workspace--id-struts-alist))
(defvar exwm-workspace--attached-minibuffer-height 0
"Height (in pixel) of the attached minibuffer.
If the minibuffer is detached, this value is 0.")
(defun exwm-workspace-attach-minibuffer ()
"Attach the minibuffer so that it always shows."
(interactive)
(when (and (exwm-workspace--minibuffer-own-frame-p)
(not (exwm-workspace--minibuffer-attached-p)))
;; Reset the frame size.
(set-frame-height exwm-workspace--minibuffer 1)
(redisplay) ;FIXME.
(setq exwm-workspace--attached-minibuffer-height
(frame-pixel-height exwm-workspace--minibuffer))
(let ((container (frame-parameter exwm-workspace--minibuffer
'exwm-container)))
(push (cons container
(if (eq exwm-workspace-minibuffer-position 'top)
(vector 0 0 exwm-workspace--attached-minibuffer-height 0)
(vector 0 0 0 exwm-workspace--attached-minibuffer-height)))
exwm-workspace--id-struts-alist)
(exwm-workspace--update-struts)
(exwm-workspace--update-workareas)
(dolist (f exwm-workspace--list)
(exwm-workspace--set-fullscreen f))
(exwm-workspace--show-minibuffer))))
(defun exwm-workspace-detach-minibuffer ()
"Detach the minibuffer so that it automatically hides."
(interactive)
(when (and (exwm-workspace--minibuffer-own-frame-p)
(exwm-workspace--minibuffer-attached-p))
(setq exwm-workspace--attached-minibuffer-height 0)
(let ((container (frame-parameter exwm-workspace--minibuffer
'exwm-container)))
(setq exwm-workspace--id-struts-alist
(assq-delete-all container exwm-workspace--id-struts-alist))
(exwm-workspace--update-struts)
(exwm-workspace--update-workareas)
(dolist (f exwm-workspace--list)
(exwm-workspace--set-fullscreen f))
(exwm-workspace--hide-minibuffer))))
(defun exwm-workspace--update-minibuffer-height (&optional echo-area)
"Update the minibuffer frame height."
(let ((height (let ((height
(with-current-buffer (with-current-buffer
(window-buffer (minibuffer-window exwm-workspace--minibuffer)) (window-buffer (minibuffer-window exwm-workspace--minibuffer))
@ -802,7 +859,7 @@ INDEX must not exceed the current number of workspaces."
(defun exwm-workspace--on-ConfigureNotify (data _synthetic) (defun exwm-workspace--on-ConfigureNotify (data _synthetic)
"Adjust the container to fit the minibuffer frame." "Adjust the container to fit the minibuffer frame."
(let ((obj (make-instance 'xcb:ConfigureNotify)) (let ((obj (make-instance 'xcb:ConfigureNotify))
value-mask y) workarea y)
(xcb:unmarshal obj data) (xcb:unmarshal obj data)
(with-slots (window height) obj (with-slots (window height) obj
(when (eq (frame-parameter exwm-workspace--minibuffer 'exwm-outer-id) (when (eq (frame-parameter exwm-workspace--minibuffer 'exwm-outer-id)
@ -818,19 +875,19 @@ INDEX must not exceed the current number of workspaces."
:window window :window window
:value-mask xcb:ConfigWindow:Height :value-mask xcb:ConfigWindow:Height
:height height))) :height height)))
(if (eq exwm-workspace-minibuffer-position 'top) (setq workarea (elt exwm-workspace--workareas
(setq value-mask xcb:ConfigWindow:Height exwm-workspace-current-index)
y 0) y (if (eq exwm-workspace-minibuffer-position 'top)
(setq value-mask (logior xcb:ConfigWindow:Y xcb:ConfigWindow:Height) (- (aref workarea 1)
y (- (aref (elt exwm-workspace--workareas exwm-workspace--attached-minibuffer-height)
exwm-workspace-current-index) (+ (aref workarea 1) (aref workarea 3) (- height)
3) exwm-workspace--attached-minibuffer-height)))
height)))
(xcb:+request exwm--connection (xcb:+request exwm--connection
(make-instance 'xcb:ConfigureWindow (make-instance 'xcb:ConfigureWindow
:window (frame-parameter exwm-workspace--minibuffer :window (frame-parameter exwm-workspace--minibuffer
'exwm-container) 'exwm-container)
:value-mask value-mask :value-mask (logior xcb:ConfigWindow:Y
xcb:ConfigWindow:Height)
:y y :y y
:height height)) :height height))
(xcb:flush exwm--connection))))) (xcb:flush exwm--connection)))))
@ -851,26 +908,31 @@ INDEX must not exceed the current number of workspaces."
(setq exwm-workspace--display-echo-area-timer nil)) (setq exwm-workspace--display-echo-area-timer nil))
;; Show the minibuffer frame. ;; Show the minibuffer frame.
(xcb:+request exwm--connection (xcb:+request exwm--connection
(make-instance 'xcb:MapWindow (make-instance 'xcb:ConfigureWindow
:window (frame-parameter exwm-workspace--minibuffer :window (frame-parameter exwm-workspace--minibuffer
'exwm-container))) 'exwm-container)
:value-mask xcb:ConfigWindow:StackMode
:stack-mode xcb:StackMode:Above))
(xcb:flush exwm--connection) (xcb:flush exwm--connection)
;; Unfortunately we need the following lines to workaround a cursor ;; Unfortunately we need the following lines to workaround a cursor
;; flickering issue for line-mode floating X windows. They just make the ;; flickering issue for line-mode floating X windows. They just make the
;; minibuffer appear to be focused. ;; minibuffer appear to be focused.
(with-current-buffer (window-buffer (minibuffer-window ;; (FIXED?)
exwm-workspace--minibuffer)) ;; (with-current-buffer (window-buffer (minibuffer-window
(setq cursor-in-non-selected-windows ;; exwm-workspace--minibuffer))
(frame-parameter exwm-workspace--minibuffer 'cursor-type)))) ;; (setq cursor-in-non-selected-windows
;; (frame-parameter exwm-workspace--minibuffer 'cursor-type)))
)
(defun exwm-workspace--hide-minibuffer () (defun exwm-workspace--hide-minibuffer ()
"Hide the minibuffer frame." "Hide the minibuffer frame."
;; Hide the minibuffer frame. ;; Hide the minibuffer frame.
(xcb:+request exwm--connection (xcb:+request exwm--connection
(make-instance 'xcb:UnmapWindow (make-instance 'xcb:ConfigureWindow
:window (frame-parameter exwm-workspace--minibuffer :window (frame-parameter exwm-workspace--minibuffer
'exwm-container))) 'exwm-container)
:value-mask xcb:ConfigWindow:StackMode
:stack-mode xcb:StackMode:Below))
(xcb:flush exwm--connection)) (xcb:flush exwm--connection))
(defun exwm-workspace--on-minibuffer-setup () (defun exwm-workspace--on-minibuffer-setup ()
@ -878,7 +940,7 @@ INDEX must not exceed the current number of workspaces."
(when (and (= 1 (minibuffer-depth)) (when (and (= 1 (minibuffer-depth))
;; Exclude non-graphical frames. ;; Exclude non-graphical frames.
(frame-parameter nil 'exwm-outer-id)) (frame-parameter nil 'exwm-outer-id))
(add-hook 'post-command-hook #'exwm-workspace--update-minibuffer) (add-hook 'post-command-hook #'exwm-workspace--update-minibuffer-height)
(exwm-workspace--show-minibuffer) (exwm-workspace--show-minibuffer)
;; Set input focus on the Emacs frame ;; Set input focus on the Emacs frame
(x-focus-frame (window-frame (minibuffer-selected-window))))) (x-focus-frame (window-frame (minibuffer-selected-window)))))
@ -888,7 +950,7 @@ INDEX must not exceed the current number of workspaces."
(when (and (= 1 (minibuffer-depth)) (when (and (= 1 (minibuffer-depth))
;; Exclude non-graphical frames. ;; Exclude non-graphical frames.
(frame-parameter nil 'exwm-outer-id)) (frame-parameter nil 'exwm-outer-id))
(remove-hook 'post-command-hook #'exwm-workspace--update-minibuffer) (remove-hook 'post-command-hook #'exwm-workspace--update-minibuffer-height)
(exwm-workspace--hide-minibuffer))) (exwm-workspace--hide-minibuffer)))
(defvar exwm-input--during-command) (defvar exwm-input--during-command)
@ -900,7 +962,7 @@ INDEX must not exceed the current number of workspaces."
(frame-parameter nil 'exwm-outer-id) (frame-parameter nil 'exwm-outer-id)
(or (current-message) (or (current-message)
cursor-in-echo-area)) cursor-in-echo-area))
(exwm-workspace--update-minibuffer t) (exwm-workspace--update-minibuffer-height t)
(exwm-workspace--show-minibuffer) (exwm-workspace--show-minibuffer)
(unless (or (not exwm-workspace-display-echo-area-timeout) (unless (or (not exwm-workspace-display-echo-area-timeout)
exwm-input--during-command ;e.g. read-event exwm-input--during-command ;e.g. read-event
@ -1217,9 +1279,14 @@ applied to all subsequently created X frames."
(make-instance 'xcb:ewmh:set-_NET_WM_NAME (make-instance 'xcb:ewmh:set-_NET_WM_NAME
:window container :window container
:data "Minibuffer container"))) :data "Minibuffer container")))
;; Reparent the minibuffer frame to the container.
(xcb:+request exwm--connection (xcb:+request exwm--connection
(make-instance 'xcb:ReparentWindow (make-instance 'xcb:ReparentWindow
:window outer-id :parent container :x 0 :y 0)) :window outer-id :parent container :x 0 :y 0))
;; Map the container.
(xcb:+request exwm--connection
(make-instance 'xcb:MapWindow
:window container))
;; Attach event listener for monitoring the frame ;; Attach event listener for monitoring the frame
(xcb:+request exwm--connection (xcb:+request exwm--connection
(make-instance 'xcb:ChangeWindowAttributes (make-instance 'xcb:ChangeWindowAttributes