Add auto-hiding minibuffer support
* exwm-floating.el (exwm-floating--set-floating): Take auto-hiding minibuffer into account when calculating available height. (exwm-floating--unset-floating): Restack the container to avoid further restacking. * exwm-input.el (exwm-input--update-focus): Use more accurate restacking. (exwm-input--on-minibuffer-setup): Replaced by `exwm-layout--on-minibuffer-setup' and `exwm-workspace--on-minibuffer-setup'. (exwm-input-command-whitelist, exwm-input--during-command) (exwm-input--on-KeyPress-line-mode): The functionality of `exwm-input-command-whitelist' is replaced by `exwm-input--during-command', which can automatically tell whether functions like `read-event' are being called. (exwm-input--init): Add/remove corresponding hooks. * exwm-layout.el (exwm-layout--on-minibuffer-setup): Also set input focus. (exwm-layout--on-echo-area-change): New function for refreshing layout when the size of echo area changes. (exwm-layout--init): Track size changes for fixed minibuffer and echo area. * exwm-manage.el (exwm-manage--on-ConfigureRequest): Never grant restacking requests initiated by other clients. * exwm-workspace.el (exwm-workspace--minibuffer): New variable for the auto-hiding minibuffer. (exwm-workspace-minibuffer-position): For setting the position of the auto-hiding minibuffer. (exwm-workspace-display-echo-area-timeout): Seconds before echo area auto-hides. (exwm-workspace--display-echo-area-timer): The corresponding timer. (exwm-workspace-switch): Configure the auto-hiding minibuffer when switching workspace. (exwm-workspace--update-minibuffer): New function for adjusting the height of the auto-hiding minibuffer. (exwm-workspace--on-ConfigureNotify): New function for configuring the container of the auto-hiding minibuffer. (exwm-workspace--display-buffer): New function for forcing `minibuffer-completion-help' to use the workspace frame. (exwm-workspace--show-minibuffer, exwm-workspace--hide-minibuffer): New functions for showing/hiding the auto-hiding minibuffer (container). (exwm-workspace--on-minibuffer-setup, exwm-workspace--on-minibuffer-exit): New functions called when the auto-hiding minibuffer entered/exists. (exwm-workspace--on-echo-area-dirty, exwm-workspace--on-echo-area-clear): New functions when the auto-hiding echo area is ready to show/hide. (exwm-workspace--init): Set up the auto-hiding minibuffer and workspace frames. Track sizes changes for auto-hiding minibuffer and echo area. No need to set OverrideRedirect on workspace frames. * exwm.el (exwm--init-icccm-ewmh): Correct the value of _NET_WORKAREA.
This commit is contained in:
		
							parent
							
								
									2d42fee327
								
							
						
					
					
						commit
						0e4055d339
					
				
					 6 changed files with 320 additions and 71 deletions
				
			
		|  | @ -106,8 +106,10 @@ | |||
|     ;; FIXME: check normal hints restrictions | ||||
|     (let* ((display-width (frame-pixel-width original-frame)) | ||||
|            (display-height (- (frame-pixel-height original-frame) | ||||
|                               (window-pixel-height (minibuffer-window | ||||
|                                                     original-frame)) | ||||
|                               (if exwm-workspace-minibuffer-position | ||||
|                                   0 | ||||
|                                 (window-pixel-height (minibuffer-window | ||||
|                                                       original-frame))) | ||||
|                               (* 2 (window-mode-line-height)) | ||||
|                               (window-header-line-height window) | ||||
|                               (* 2 exwm-floating-border-width))) | ||||
|  | @ -180,12 +182,22 @@ | |||
|   (interactive) | ||||
|   (let ((buffer (exwm--id->buffer id))) | ||||
|     (with-current-buffer buffer | ||||
|       ;; Reparent the container to the workspace | ||||
|       (xcb:+request exwm--connection | ||||
|           (make-instance 'xcb:ReparentWindow | ||||
|                          :window exwm--container | ||||
|                          :parent (frame-parameter exwm-workspace--current | ||||
|                                                   'exwm-workspace) | ||||
|                          :x 0 :y 0)))   ;temporary position | ||||
|                          :x 0 :y 0))    ;temporary position | ||||
|       ;; Put the container just above the Emacs frame | ||||
|       (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--current | ||||
|                                                    'exwm-outer-id) | ||||
|                          :stack-mode xcb:StackMode:Above))) | ||||
|     (xcb:flush exwm--connection) | ||||
|     (with-current-buffer buffer | ||||
|       (when exwm--floating-frame        ;from floating to non-floating | ||||
|  |  | |||
|  | @ -110,26 +110,25 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.") | |||
|             (exwm--log "Set focus on #x%x" exwm--id) | ||||
|             (exwm-input--set-focus exwm--id) | ||||
|             ;; Adjust stacking orders | ||||
|             (if exwm--floating-frame | ||||
|             (when exwm--floating-frame | ||||
|               (if (memq exwm-workspace-minibuffer-position '(top bottom)) | ||||
|                   ;; 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:TopIf)) | ||||
|               ;; This should be the last X window but one in the siblings. | ||||
|               (with-slots (children) | ||||
|                   (xcb:+request-unchecked+reply exwm--connection | ||||
|                       (make-instance 'xcb:QueryTree | ||||
|                                      :window | ||||
|                                      (frame-parameter exwm--frame | ||||
|                                                       'exwm-workspace))) | ||||
|                 (unless (eq (cadr children) exwm--container) | ||||
|                   (xcb:+request exwm--connection | ||||
|                       (make-instance 'xcb:ConfigureWindow | ||||
|                                      :window exwm--container | ||||
|                                      :value-mask xcb:ConfigWindow:StackMode | ||||
|                                      :stack-mode xcb:StackMode:Below))))) | ||||
|                                    :stack-mode xcb:StackMode:Above)))) | ||||
|             ;; Make sure Emacs frames are at bottom. | ||||
|             (xcb:+request exwm--connection | ||||
|                 (make-instance 'xcb:ConfigureWindow | ||||
|  | @ -142,21 +141,9 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.") | |||
|         (when (eq (selected-window) exwm-input--focus-window) | ||||
|           (exwm--log "Focus on %s" exwm-input--focus-window) | ||||
|           (select-frame-set-input-focus (window-frame exwm-input--focus-window) | ||||
|                                         t) | ||||
|           (xcb:+request exwm--connection | ||||
|               (make-instance 'xcb:ConfigureWindow | ||||
|                              :window (frame-parameter | ||||
|                                       (window-frame exwm-input--focus-window) | ||||
|                                       'exwm-outer-id) | ||||
|                              :value-mask xcb:ConfigWindow:StackMode | ||||
|                              :stack-mode xcb:StackMode:Below)) | ||||
|           (xcb:flush exwm--connection))) | ||||
|                                         t))) | ||||
|       (setq exwm-input--focus-window nil)))) | ||||
| 
 | ||||
| (defun exwm-input--on-minibuffer-setup () | ||||
|   "Run in minibuffer-setup-hook to set input focus to the frame." | ||||
|   (x-focus-frame (selected-frame))) | ||||
| 
 | ||||
| (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 | ||||
|  | @ -278,12 +265,13 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.") | |||
|   (global-set-key key command) | ||||
|   (cl-pushnew key exwm-input--global-keys)) | ||||
| 
 | ||||
| ;; These commands usually call something like `read-char' without using the | ||||
| ;; minibuffer, so they will not get inputs after invoked.  It'd be better if we | ||||
| ;; can determine whether there's a command waiting for input so that this | ||||
| ;; variable can be removed. | ||||
| (defvar exwm-input-command-whitelist nil | ||||
|   "A list of commands that when active all keys should be forwarded to Emacs.") | ||||
| (make-obsolete-variable 'exwm-input-command-whitelist | ||||
|                         "This variable can be safely removed." "25.1") | ||||
| 
 | ||||
| (defvar exwm-input--during-command nil | ||||
|   "Indicate whether between `pre-command-hook' and `post-command-hook'.") | ||||
| 
 | ||||
| ;;;###autoload | ||||
| (defun exwm-input--on-KeyPress-line-mode (key-press) | ||||
|  | @ -295,8 +283,8 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.") | |||
|                  (setq event (xcb:keysyms:keysym->event exwm--connection | ||||
|                                                         keysym state)) | ||||
|                  (or exwm-input--during-key-sequence | ||||
|                      exwm-input--during-command | ||||
|                      (setq minibuffer-window (active-minibuffer-window)) | ||||
|                      (memq real-this-command exwm-input-command-whitelist) | ||||
|                      (memq event exwm-input--global-prefix-keys) | ||||
|                      (memq event exwm-input-prefix-keys) | ||||
|                      (memq event exwm-input--simulation-prefix-keys))) | ||||
|  | @ -501,9 +489,12 @@ SIMULATION-KEYS is a list of alist (key-sequence1 . key-sequence2)." | |||
|               #'exwm-floating--do-moveresize) | ||||
|   ;; `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 (lambda () (setq exwm-input--during-command t))) | ||||
|   (add-hook 'post-command-hook | ||||
|             (lambda () (setq exwm-input--during-command nil))) | ||||
|   ;; Update focus when buffer list updates | ||||
|   (add-hook 'buffer-list-update-hook #'exwm-input--on-buffer-list-update) | ||||
|   (add-hook 'minibuffer-setup-hook #'exwm-input--on-minibuffer-setup) | ||||
|   ;; Update prefix keys for global keys | ||||
|   (exwm-input--update-global-prefix-keys)) | ||||
| 
 | ||||
|  |  | |||
|  | @ -279,10 +279,20 @@ | |||
|   "Refresh layout when minibuffer grows." | ||||
|   (run-with-idle-timer 0.01 nil         ;FIXME | ||||
|                        (lambda () | ||||
|                          (when (and (< 1 (window-height (minibuffer-window))) | ||||
|                                     (not (and (eq major-mode 'exwm-mode) | ||||
|                                               exwm--floating-frame))) | ||||
|                            (exwm-layout--refresh))))) | ||||
|                          (when (< 1 (window-height (minibuffer-window))) | ||||
|                            (exwm-layout--refresh)))) | ||||
|   ;; Set input focus on the Emacs frame | ||||
|   (x-focus-frame (window-frame (minibuffer-selected-window)))) | ||||
| 
 | ||||
| (defun exwm-layout--on-echo-area-change (&optional dirty) | ||||
|   "Run when message arrives or in `echo-area-clear-hook' to refresh layout." | ||||
|   (when (and (current-message) | ||||
|              (or (cl-position ?\n (current-message)) | ||||
|                  (> (length (current-message)) | ||||
|                     (frame-width exwm-workspace--current)))) | ||||
|     (if dirty | ||||
|         (exwm-layout--refresh) | ||||
|       (run-with-idle-timer 0.01 nil #'exwm-layout--refresh)))) ;FIXME | ||||
| 
 | ||||
| (defun exwm-layout-enlarge-window (delta &optional horizontal) | ||||
|   "Make the selected window DELTA pixels taller. | ||||
|  | @ -383,8 +393,11 @@ See also `exwm-layout-enlarge-window'." | |||
|   "Initialize layout module." | ||||
|   ;; Auto refresh layout | ||||
|   (add-hook 'window-configuration-change-hook #'exwm-layout--refresh) | ||||
|   ;; Refresh when minibuffer grows | ||||
|   (add-hook 'minibuffer-setup-hook #'exwm-layout--on-minibuffer-setup t)) | ||||
|   (unless (memq exwm-workspace-minibuffer-position '(top bottom)) | ||||
|     ;; Refresh when minibuffer grows | ||||
|     (add-hook 'minibuffer-setup-hook #'exwm-layout--on-minibuffer-setup t) | ||||
|     (run-with-idle-timer 0 t #'exwm-layout--on-echo-area-change t) | ||||
|     (add-hook 'echo-area-clear-hook #'exwm-layout--on-echo-area-change))) | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
|  |  | |||
|  | @ -360,8 +360,7 @@ Would you like to kill it? " | |||
|   (let ((obj (make-instance 'xcb:ConfigureRequest)) | ||||
|         buffer edges) | ||||
|     (xcb:unmarshal obj data) | ||||
|     (with-slots (stack-mode window sibling x y width height border-width | ||||
|                             value-mask) | ||||
|     (with-slots (window x y width height border-width value-mask) | ||||
|         obj | ||||
|       (exwm--log "ConfigureRequest from #x%x (#x%x) @%dx%d%+d%+d, border: %d" | ||||
|                  window value-mask width height x y border-width) | ||||
|  | @ -391,14 +390,16 @@ Would you like to kill it? " | |||
|                                         :border-width 0 :override-redirect 0) | ||||
|                                        exwm--connection)))) | ||||
|         (exwm--log "ConfigureWindow (preserve geometry)") | ||||
|         ;; Configure unmanaged windows | ||||
|         ;; Configure the unmanaged window without changing the stacking order. | ||||
|         (xcb:+request exwm--connection | ||||
|             (make-instance 'xcb:ConfigureWindow | ||||
|                            :window window | ||||
|                            :value-mask value-mask | ||||
|                            :value-mask | ||||
|                            (logand value-mask | ||||
|                                    (lognot xcb:ConfigWindow:Sibling) | ||||
|                                    (lognot xcb:ConfigWindow:StackMode)) | ||||
|                            :x x :y y :width width :height height | ||||
|                            :border-width border-width | ||||
|                            :sibling sibling :stack-mode stack-mode))))) | ||||
|                            :border-width border-width))))) | ||||
|   (xcb:flush exwm--connection)) | ||||
| 
 | ||||
| (defun exwm-manage--on-MapRequest (data _synthetic) | ||||
|  |  | |||
|  | @ -24,7 +24,6 @@ | |||
| ;; This module adds workspace support for EXWM. | ||||
| 
 | ||||
| ;; Todo: | ||||
| ;; + Auto hide minibuffer, or allow users to place it elsewhere. | ||||
| ;; + Add system tray support. | ||||
| 
 | ||||
| ;;; Code: | ||||
|  | @ -100,6 +99,17 @@ | |||
| (defvar exwm-workspace-current-index 0 "Index of current active workspace.") | ||||
| (defvar exwm-workspace-show-all-buffers nil | ||||
|   "Non-nil to show buffers on other workspaces.") | ||||
| (defvar exwm-workspace--minibuffer nil | ||||
|   "The minibuffer frame shared among all frames.") | ||||
| (defvar exwm-workspace-minibuffer-position nil | ||||
|   "Position of the minibuffer frame. | ||||
| 
 | ||||
| Value nil means to use the default position which is fixed at bottom, while | ||||
| 'top and 'bottom mean to use an auto-hiding minibuffer.") | ||||
| (defvar exwm-workspace-display-echo-area-timeout 1 | ||||
|   "Timeout for displaying echo area.") | ||||
| (defvar exwm-workspace--display-echo-area-timer nil | ||||
|   "Timer for auto-hiding echo area.") | ||||
| 
 | ||||
| ;;;###autoload | ||||
| (defun exwm-workspace-switch (index &optional force) | ||||
|  | @ -135,7 +145,30 @@ The optional FORCE option is for internal use only." | |||
|         ;; Close the (possible) active minibuffer | ||||
|         (when (active-minibuffer-window) | ||||
|           (run-with-idle-timer 0 nil (lambda () (abort-recursive-edit)))) | ||||
|         (setq default-minibuffer-frame frame) | ||||
|         (if (not (memq exwm-workspace-minibuffer-position '(top bottom))) | ||||
|             (setq default-minibuffer-frame frame) | ||||
|           ;; Resize/reposition the minibuffer frame | ||||
|           (let ((x 0) | ||||
|                 (y (if (eq exwm-workspace-minibuffer-position 'top) | ||||
|                        0 | ||||
|                      (- (frame-pixel-height frame) | ||||
|                         (frame-pixel-height exwm-workspace--minibuffer)))) | ||||
|                 (width (x-display-pixel-width)) | ||||
|                 (container (frame-parameter exwm-workspace--minibuffer | ||||
|                                             'exwm-container))) | ||||
|             (xcb:+request exwm--connection | ||||
|                 (make-instance 'xcb:ReparentWindow | ||||
|                                :window container | ||||
|                                :parent (frame-parameter frame 'exwm-workspace) | ||||
|                                :x x :y y)) | ||||
|             (xcb:+request exwm--connection | ||||
|                 (make-instance 'xcb:ConfigureWindow | ||||
|                                :window container | ||||
|                                :value-mask (logior xcb:ConfigWindow:Width | ||||
|                                                    xcb:ConfigWindow:StackMode) | ||||
|                                :width width | ||||
|                                :stack-mode xcb:StackMode:Above)) | ||||
|             (set-frame-width exwm-workspace--minibuffer width nil t))) | ||||
|         ;; Hide windows in other workspaces by preprending a space | ||||
|         (unless exwm-workspace-show-all-buffers | ||||
|           (dolist (i exwm--id-buffer-alist) | ||||
|  | @ -266,6 +299,146 @@ The optional FORCE option is for internal use only." | |||
|     (xcb:flush exwm--connection) | ||||
|     frame)) | ||||
| 
 | ||||
| (defun exwm-workspace--update-minibuffer (&optional echo-area) | ||||
|   "Update the minibuffer frame." | ||||
|   (let ((height | ||||
|          (with-current-buffer | ||||
|              (window-buffer (minibuffer-window exwm-workspace--minibuffer)) | ||||
|            (max 1 | ||||
|                 (if echo-area | ||||
|                     (let ((width (frame-width exwm-workspace--minibuffer)) | ||||
|                           (result 0)) | ||||
|                       (mapc (lambda (i) | ||||
|                               (setq result | ||||
|                                     (+ result | ||||
|                                        (ceiling (1+ (length i)) width)))) | ||||
|                             (split-string (current-message) "\n")) | ||||
|                       result) | ||||
|                   (count-screen-lines)))))) | ||||
|     (when (and (integerp max-mini-window-height) | ||||
|                (> height max-mini-window-height)) | ||||
|       (setq height max-mini-window-height)) | ||||
|     (set-frame-height exwm-workspace--minibuffer height))) | ||||
| 
 | ||||
| (defun exwm-workspace--on-ConfigureNotify (data _synthetic) | ||||
|   "Adjust the container to fit the minibuffer frame." | ||||
|   (let ((obj (make-instance 'xcb:ConfigureNotify)) | ||||
|         value-mask y) | ||||
|     (xcb:unmarshal obj data) | ||||
|     (with-slots (window height) obj | ||||
|       (when (eq (frame-parameter exwm-workspace--minibuffer 'exwm-outer-id) | ||||
|                 window) | ||||
|         (when (and (floatp max-mini-window-height) | ||||
|                    (> height (* max-mini-window-height | ||||
|                                 (frame-pixel-height exwm-workspace--current)))) | ||||
|           (setq height (floor | ||||
|                         (* max-mini-window-height | ||||
|                            (frame-pixel-height exwm-workspace--current)))) | ||||
|           (xcb:+request exwm--connection | ||||
|               (make-instance 'xcb:ConfigureWindow | ||||
|                              :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 (- (frame-pixel-height exwm-workspace--current) height))) | ||||
|         (xcb:+request exwm--connection | ||||
|             (make-instance 'xcb:ConfigureWindow | ||||
|                            :window (frame-parameter exwm-workspace--minibuffer | ||||
|                                                     'exwm-container) | ||||
|                            :value-mask value-mask | ||||
|                            :y y | ||||
|                            :height height)) | ||||
|         (xcb:flush exwm--connection))))) | ||||
| 
 | ||||
| (defun exwm-workspace--display-buffer (buffer alist) | ||||
|   "Display buffer in the current workspace frame. | ||||
| 
 | ||||
| This functions is modified from `display-buffer-reuse-window' and | ||||
| `display-buffer-pop-up-window'." | ||||
|   (when (eq (selected-frame) exwm-workspace--minibuffer) | ||||
|     (setq buffer (get-buffer buffer))   ;convert string to buffer. | ||||
|     (let (window) | ||||
|       (if (setq window (get-buffer-window buffer exwm-workspace--current)) | ||||
|           (window--display-buffer buffer window 'reuse alist) | ||||
|         (when (setq window (or (window--try-to-split-window | ||||
|                                 (get-largest-window exwm-workspace--current t) | ||||
|                                 alist) | ||||
|                                (window--try-to-split-window | ||||
|                                 (get-lru-window exwm-workspace--current t) | ||||
|                                 alist))) | ||||
|           (window--display-buffer | ||||
|            buffer window 'window alist display-buffer-mark-dedicated)))))) | ||||
| 
 | ||||
| (defun exwm-workspace--show-minibuffer () | ||||
|   "Show the minibuffer frame." | ||||
|   ;; Cancel pending timer. | ||||
|   (when exwm-workspace--display-echo-area-timer | ||||
|     (cancel-timer exwm-workspace--display-echo-area-timer) | ||||
|     (setq exwm-workspace--display-echo-area-timer nil)) | ||||
|   ;; Show the minibuffer frame. | ||||
|   (xcb:+request exwm--connection | ||||
|       (make-instance 'xcb:MapWindow | ||||
|                      :window (frame-parameter exwm-workspace--minibuffer | ||||
|                                               'exwm-container))) | ||||
|   (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)))) | ||||
| 
 | ||||
| (defun exwm-workspace--hide-minibuffer () | ||||
|   "Hide the minibuffer frame." | ||||
|   ;; Hide the minibuffer frame. | ||||
|   (xcb:+request exwm--connection | ||||
|       (make-instance 'xcb:UnmapWindow | ||||
|                      :window (frame-parameter exwm-workspace--minibuffer | ||||
|                                               'exwm-container))) | ||||
|   (xcb:flush exwm--connection)) | ||||
| 
 | ||||
| (defun exwm-workspace--on-minibuffer-setup () | ||||
|   "Run in minibuffer-setup-hook to show the minibuffer and its container." | ||||
|   (unless (> -1 (minibuffer-depth)) | ||||
|     (add-hook 'post-command-hook #'exwm-workspace--update-minibuffer) | ||||
|     (exwm-workspace--show-minibuffer) | ||||
|     ;; Set input focus on the Emacs frame | ||||
|     (x-focus-frame (window-frame (minibuffer-selected-window))))) | ||||
| 
 | ||||
| (defun exwm-workspace--on-minibuffer-exit () | ||||
|   "Run in minibuffer-exit-hook to hide the minibuffer container." | ||||
|   (unless (> -1 (minibuffer-depth)) | ||||
|     (remove-hook 'post-command-hook #'exwm-workspace--update-minibuffer) | ||||
|     (exwm-workspace--hide-minibuffer))) | ||||
| 
 | ||||
| (defvar exwm-input--during-command) | ||||
| 
 | ||||
| (defun exwm-workspace--on-echo-area-dirty () | ||||
|   "Run when new message arrives to show the echo area and its container." | ||||
|   (when (and (not (active-minibuffer-window)) | ||||
|              (or (current-message) | ||||
|                  cursor-in-echo-area)) | ||||
|     (exwm-workspace--update-minibuffer t) | ||||
|     (exwm-workspace--show-minibuffer) | ||||
|     (unless (or (not exwm-workspace-display-echo-area-timeout) | ||||
|                 exwm-input--during-command ;e.g. read-event | ||||
|                 input-method-use-echo-area) | ||||
|       (setq exwm-workspace--display-echo-area-timer | ||||
|             (run-with-timer exwm-workspace-display-echo-area-timeout nil | ||||
|                             #'exwm-workspace--on-echo-area-clear))))) | ||||
| 
 | ||||
| (defun exwm-workspace--on-echo-area-clear () | ||||
|   "Run in echo-area-clear-hook to hide echo area container." | ||||
|   (unless (active-minibuffer-window) | ||||
|     (exwm-workspace--hide-minibuffer)) | ||||
|   (when exwm-workspace--display-echo-area-timer | ||||
|     (cancel-timer exwm-workspace--display-echo-area-timer) | ||||
|     (setq exwm-workspace--display-echo-area-timer nil))) | ||||
| 
 | ||||
| (defun exwm-workspace--init () | ||||
|   "Initialize workspace module." | ||||
|   (cl-assert (and (< 0 exwm-workspace-number) (>= 10 exwm-workspace-number))) | ||||
|  | @ -276,19 +449,79 @@ The optional FORCE option is for internal use only." | |||
|             (0 (y-or-n-p prompt)) | ||||
|             (x (yes-or-no-p (format "[EXWM] %d window%s currently alive. %s" | ||||
|                                     x (if (= x 1) "" "s") prompt)))))) | ||||
|   ;; Initialize workspaces | ||||
|   (setq exwm-workspace--list (frame-list)) | ||||
|   (when (< 1 (length exwm-workspace--list)) | ||||
|     ;; Emacs client creates an extra (but unusable) frame | ||||
|     (dolist (i exwm-workspace--list) | ||||
|       (unless (frame-parameter i 'window-id) | ||||
|         (setq exwm-workspace--list (delq i exwm-workspace--list)))) | ||||
|     (cl-assert (= 1 (length exwm-workspace--list))) | ||||
|     ;; Prevent user from deleting this frame by accident | ||||
|     (set-frame-parameter (car exwm-workspace--list) 'client nil)) | ||||
|   ;; Create remaining frames | ||||
|   (dotimes (_ (1- exwm-workspace-number)) | ||||
|     (nconc exwm-workspace--list (list (make-frame '((window-system . x)))))) | ||||
|   (if (not (memq exwm-workspace-minibuffer-position '(top bottom))) | ||||
|       ;; Initialize workspaces with minibuffers. | ||||
|       (progn | ||||
|         (setq exwm-workspace--list (frame-list)) | ||||
|         (when (< 1 (length exwm-workspace--list)) | ||||
|           ;; Emacs client creates an extra (but unusable) frame. | ||||
|           (dolist (i exwm-workspace--list) | ||||
|             (unless (frame-parameter i 'window-id) | ||||
|               (setq exwm-workspace--list (delq i exwm-workspace--list)))) | ||||
|           (cl-assert (= 1 (length exwm-workspace--list))) | ||||
|           ;; Prevent user from deleting this frame by accident. | ||||
|           (set-frame-parameter (car exwm-workspace--list) 'client nil)) | ||||
|         ;; Create remaining frames. | ||||
|         (dotimes (_ (1- exwm-workspace-number)) | ||||
|           (nconc exwm-workspace--list | ||||
|                  (list (make-frame '((window-system . x))))))) | ||||
|     ;; Initialize workspaces without minibuffers. | ||||
|     (let ((old-frames (frame-list))) | ||||
|       (setq exwm-workspace--minibuffer | ||||
|             (make-frame '((window-system . x) (minibuffer . only) | ||||
|                           (left . 10000) (right . 10000) | ||||
|                           (width . 0) (height . 0))) | ||||
|             default-minibuffer-frame exwm-workspace--minibuffer) | ||||
|       ;; Remove/hide existing frames. | ||||
|       (dolist (f old-frames) | ||||
|         (if (frame-parameter f 'client) | ||||
|             (make-frame-invisible f) | ||||
|           (delete-frame f)))) | ||||
|     (let ((outer-id (string-to-number | ||||
|                      (frame-parameter exwm-workspace--minibuffer | ||||
|                                       'outer-window-id))) | ||||
|           (container (xcb:generate-id exwm--connection))) | ||||
|       (set-frame-parameter exwm-workspace--minibuffer 'exwm-outer-id outer-id) | ||||
|       (set-frame-parameter exwm-workspace--minibuffer 'exwm-container | ||||
|                            container) | ||||
|       (xcb:+request exwm--connection | ||||
|           (make-instance 'xcb:CreateWindow | ||||
|                          :depth 0 :wid container :parent exwm--root | ||||
|                          :x -1 :y -1 :width 1 :height 1 | ||||
|                          :border-width 0 :class xcb:WindowClass:CopyFromParent | ||||
|                          :visual 0        ;CopyFromParent | ||||
|                          :value-mask xcb:CW:OverrideRedirect | ||||
|                          :override-redirect 1)) | ||||
|       (exwm--debug | ||||
|        (xcb:+request exwm--connection | ||||
|            (make-instance 'xcb:ewmh:set-_NET_WM_NAME | ||||
|                           :window container | ||||
|                           :data "Minibuffer container"))) | ||||
|       (xcb:+request exwm--connection | ||||
|           (make-instance 'xcb:ReparentWindow | ||||
|                          :window outer-id :parent container :x 0 :y 0)) | ||||
|       ;; Attach event listener for monitoring the frame | ||||
|       (xcb:+request exwm--connection | ||||
|           (make-instance 'xcb:ChangeWindowAttributes | ||||
|                          :window outer-id | ||||
|                          :value-mask xcb:CW:EventMask | ||||
|                          :event-mask xcb:EventMask:StructureNotify)) | ||||
|       (xcb:+event exwm--connection 'xcb:ConfigureNotify | ||||
|                   #'exwm-workspace--on-ConfigureNotify)) | ||||
|     ;; Show/hide minibuffer / echo area when they're active/inactive. | ||||
|     (add-hook 'minibuffer-setup-hook #'exwm-workspace--on-minibuffer-setup) | ||||
|     (add-hook 'minibuffer-exit-hook #'exwm-workspace--on-minibuffer-exit) | ||||
|     (run-with-idle-timer 0 t #'exwm-workspace--on-echo-area-dirty) | ||||
|     (add-hook 'echo-area-clear-hook #'exwm-workspace--on-echo-area-clear) | ||||
|     ;; Create workspace frames. | ||||
|     (dotimes (_ exwm-workspace-number) | ||||
|       (push (make-frame `((window-system . x) | ||||
|                           (minibuffer . ,(minibuffer-window | ||||
|                                           exwm-workspace--minibuffer)))) | ||||
|             exwm-workspace--list)) | ||||
|     ;; The default behavior of `display-buffer' (indirectly called by | ||||
|     ;; `minibuffer-completion-help') is not correct here. | ||||
|     (cl-pushnew '(exwm-workspace--display-buffer) display-buffer-alist)) | ||||
|   ;; Configure workspaces | ||||
|   (dolist (i exwm-workspace--list) | ||||
|     (let ((outer-id (string-to-number (frame-parameter i 'outer-window-id))) | ||||
|  | @ -296,11 +529,6 @@ The optional FORCE option is for internal use only." | |||
|       ;; Save window IDs | ||||
|       (set-frame-parameter i 'exwm-outer-id outer-id) | ||||
|       (set-frame-parameter i 'exwm-workspace workspace) | ||||
|       ;; Set OverrideRedirect on all frames | ||||
|       (xcb:+request exwm--connection | ||||
|           (make-instance 'xcb:ChangeWindowAttributes | ||||
|                          :window outer-id :value-mask xcb:CW:OverrideRedirect | ||||
|                          :override-redirect 1)) | ||||
|       (xcb:+request exwm--connection | ||||
|           (make-instance 'xcb:CreateWindow | ||||
|                          :depth 0 :wid workspace :parent exwm--root | ||||
|  |  | |||
							
								
								
									
										8
									
								
								exwm.el
									
										
									
									
									
								
							
							
						
						
									
										8
									
								
								exwm.el
									
										
									
									
									
								
							|  | @ -466,9 +466,13 @@ | |||
|       (make-instance 'xcb:ewmh:set-_NET_DESKTOP_VIEWPORT | ||||
|                      :window exwm--root | ||||
|                      :data (make-vector (* 2 exwm-workspace-number) 0))) | ||||
|   ;; Set _NET_WORKAREA (with minibuffer and bottom mode-line excluded) | ||||
|   ;; Set _NET_WORKAREA (with minibuffer excluded) | ||||
|   (let* ((workareas | ||||
|           (vector 0 0 (x-display-pixel-width) (x-display-pixel-height))) | ||||
|           (vector 0 0 (x-display-pixel-width) | ||||
|                   (- (x-display-pixel-height) | ||||
|                      (if exwm-workspace-minibuffer-position | ||||
|                          0 | ||||
|                        (window-pixel-height (minibuffer-window)))))) | ||||
|          (workareas (mapconcat (lambda (_) workareas) | ||||
|                                (make-list exwm-workspace-number 0) []))) | ||||
|     (xcb:+request exwm--connection | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue