about summary refs log tree commit diff
diff options
context:
space:
mode:
authorChris Feng <chris.w.feng@gmail.com>2016-07-19T11·23+0800
committerChris Feng <chris.w.feng@gmail.com>2016-07-19T11·23+0800
commit3909f65bae17af118ea7b1acf714289b35ea1b3d (patch)
treeb03577683994e63873c5de26110a2862a9127c41
parent624c72945a529c8221d12882063c7115af15a4c5 (diff)
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).
-rw-r--r--exwm-input.el23
-rw-r--r--exwm-workspace.el149
2 files changed, 113 insertions, 59 deletions
diff --git a/exwm-input.el b/exwm-input.el
index b9e47058f003..b0c9b2c129ea 100644
--- a/exwm-input.el
+++ b/exwm-input.el
@@ -125,24 +125,11 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
             (exwm-input--set-focus exwm--id)
             (when exwm--floating-frame
               ;; Adjust stacking orders of the floating container.
-              (if (exwm-workspace--minibuffer-own-frame-p)
-                  ;; Put this floating X window just below the minibuffer.
-                  (xcb:+request exwm--connection
-                      (make-instance 'xcb:ConfigureWindow
-                                     :window exwm--container
-                                     :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)))
+              (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'.
               (when (exwm-layout--iconic-state-p)
                 (exwm-layout--set-state exwm--id
diff --git a/exwm-workspace.el b/exwm-workspace.el
index 438ccdc94fd0..060be3b47b54 100644
--- a/exwm-workspace.el
+++ b/exwm-workspace.el
@@ -308,20 +308,32 @@ Value nil means to use the default position which is fixed at bottom, while
                                     'exwm-container))
         y width)
     (setq y (if (eq exwm-workspace-minibuffer-position 'top)
-                0
-              (- (aref workarea 3)
-                 (frame-pixel-height exwm-workspace--minibuffer)))
+                (- (aref workarea 1)
+                   exwm-workspace--attached-minibuffer-height)
+              ;; 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))
     (xcb:+request exwm--connection
         (make-instance 'xcb:ConfigureWindow
                        :window container
-                       :value-mask (logior xcb:ConfigWindow:Y
+                       :value-mask (logior xcb:ConfigWindow:X
+                                           xcb:ConfigWindow:Y
                                            xcb:ConfigWindow:Width
                                            xcb:ConfigWindow:StackMode)
+                       :x (aref workarea 0)
                        :y y
                        :width width
-                       :stack-mode xcb:StackMode:Above))
-    (set-frame-width exwm-workspace--minibuffer width nil t)))
+                       :stack-mode xcb:StackMode:Below))
+    (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)
   "Allow selecting a workspace by number.
@@ -428,17 +440,11 @@ The optional FORCE option is for internal use only."
                                      ;; Might be aborted by then.
                                      (when (active-minibuffer-window)
                                        (abort-recursive-edit)))))
-      (if (not (exwm-workspace--minibuffer-own-frame-p))
-          (setq default-minibuffer-frame frame)
-        ;; Resize/reposition the minibuffer frame
-        (xcb:+request exwm--connection
-            (make-instance 'xcb:ReparentWindow
-                           :window
-                           (frame-parameter exwm-workspace--minibuffer
-                                            'exwm-container)
-                           :parent (frame-parameter frame 'exwm-workspace)
-                           :x 0 :y 0))
-        (exwm-workspace--resize-minibuffer-frame))
+      (if (exwm-workspace--minibuffer-own-frame-p)
+          ;; Resize the minibuffer frame.
+          (exwm-workspace--resize-minibuffer-frame)
+        ;; Set a default minibuffer frame.
+        (setq default-minibuffer-frame frame))
       ;; Hide windows in other workspaces by preprending a space
       (unless exwm-workspace-show-all-buffers
         (dolist (i exwm--id-buffer-alist)
@@ -778,8 +784,59 @@ INDEX must not exceed the current number of workspaces."
     (xcb:flush exwm--connection)
     frame))
 
-(defun exwm-workspace--update-minibuffer (&optional echo-area)
-  "Update the minibuffer frame."
+(defsubst exwm-workspace--minibuffer-attached-p ()
+  "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
          (with-current-buffer
              (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)
   "Adjust the container to fit the minibuffer frame."
   (let ((obj (make-instance 'xcb:ConfigureNotify))
-        value-mask y)
+        workarea y)
     (xcb:unmarshal obj data)
     (with-slots (window height) obj
       (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
                              :value-mask xcb:ConfigWindow:Height
                              :height height)))
-        (if (eq exwm-workspace-minibuffer-position 'top)
-            (setq value-mask xcb:ConfigWindow:Height
-                  y 0)
-          (setq value-mask (logior xcb:ConfigWindow:Y xcb:ConfigWindow:Height)
-                y (- (aref (elt exwm-workspace--workareas
-                                exwm-workspace-current-index)
-                           3)
-                     height)))
+        (setq workarea (elt exwm-workspace--workareas
+                            exwm-workspace-current-index)
+              y (if (eq exwm-workspace-minibuffer-position 'top)
+                    (- (aref workarea 1)
+                       exwm-workspace--attached-minibuffer-height)
+                  (+ (aref workarea 1) (aref workarea 3) (- height)
+                     exwm-workspace--attached-minibuffer-height)))
         (xcb:+request exwm--connection
             (make-instance 'xcb:ConfigureWindow
                            :window (frame-parameter exwm-workspace--minibuffer
                                                     'exwm-container)
-                           :value-mask value-mask
+                           :value-mask (logior xcb:ConfigWindow:Y
+                                               xcb:ConfigWindow:Height)
                            :y y
                            :height height))
         (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))
   ;; Show the minibuffer frame.
   (xcb:+request exwm--connection
-      (make-instance 'xcb:MapWindow
+      (make-instance 'xcb:ConfigureWindow
                      :window (frame-parameter exwm-workspace--minibuffer
-                                              'exwm-container)))
+                                              'exwm-container)
+                     :value-mask xcb:ConfigWindow:StackMode
+                     :stack-mode xcb:StackMode:Above))
   (xcb:flush exwm--connection)
   ;; Unfortunately we need the following lines to workaround a cursor
   ;; flickering issue for line-mode floating X windows.  They just make the
   ;; minibuffer appear to be focused.
-  (with-current-buffer (window-buffer (minibuffer-window
-                                       exwm-workspace--minibuffer))
-    (setq cursor-in-non-selected-windows
-          (frame-parameter exwm-workspace--minibuffer 'cursor-type))))
-
+  ;; (FIXED?)
+  ;; (with-current-buffer (window-buffer (minibuffer-window
+  ;;                                      exwm-workspace--minibuffer))
+  ;;   (setq cursor-in-non-selected-windows
+  ;;         (frame-parameter exwm-workspace--minibuffer 'cursor-type)))
+  )
 
 (defun exwm-workspace--hide-minibuffer ()
   "Hide the minibuffer frame."
   ;; Hide the minibuffer frame.
   (xcb:+request exwm--connection
-      (make-instance 'xcb:UnmapWindow
+      (make-instance 'xcb:ConfigureWindow
                      :window (frame-parameter exwm-workspace--minibuffer
-                                              'exwm-container)))
+                                              'exwm-container)
+                     :value-mask xcb:ConfigWindow:StackMode
+                     :stack-mode xcb:StackMode:Below))
   (xcb:flush exwm--connection))
 
 (defun exwm-workspace--on-minibuffer-setup ()
@@ -878,7 +940,7 @@ INDEX must not exceed the current number of workspaces."
   (when (and (= 1 (minibuffer-depth))
              ;; Exclude non-graphical frames.
              (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)
     ;; Set input focus on the Emacs frame
     (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))
              ;; Exclude non-graphical frames.
              (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)))
 
 (defvar exwm-input--during-command)
@@ -900,7 +962,7 @@ INDEX must not exceed the current number of workspaces."
              (frame-parameter nil 'exwm-outer-id)
              (or (current-message)
                  cursor-in-echo-area))
-    (exwm-workspace--update-minibuffer t)
+    (exwm-workspace--update-minibuffer-height t)
     (exwm-workspace--show-minibuffer)
     (unless (or (not exwm-workspace-display-echo-area-timeout)
                 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
                             :window container
                             :data "Minibuffer container")))
+        ;; Reparent the minibuffer frame to the container.
         (xcb:+request exwm--connection
             (make-instance 'xcb:ReparentWindow
                            :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
         (xcb:+request exwm--connection
             (make-instance 'xcb:ChangeWindowAttributes