Rework the X windows hierarchy model
This commit add workspace and X window containers support to avoid using Emacs frames as the parents of X windows. This should make it easier to set input focus. * exwm-core.el (exwm--container, exwm--floating-frame-position): New file local variables. (exwm--floating-frame-geometry): Removed file local variable. * exwm-floating.el (exwm-floating--set-floating) (exwm-floating--unset-floating, exwm-floating--do-moveresize) (exwm-floating-move): Use container. (exwm-floating--fit-frame-to-window): No longer adjust stacking order. (exwm-floating--fit-frame-to-window): The first member is changed to buffer. (exwm-floating--start-moveresize): Use container. Correctly set input focus. * exwm-input.el (exwm-input--redirected, exwm-input--on-focus-in): Removed. (exwm-input--on-buffer-list-update): Remove the restriction on floating frames which is no longer valid. (exwm-input--update-focus): Adjust stacking order. (exwm-input--on-minibuffer-setup): New function for setting focus on the Emacs frame when entering minibuffer. (exwm-input--on-KeyPress-line-mode): No longer compensate FocusOut event. (exwm-input--grab-keyboard, exwm-input--release-keyboard): Local keys are now grabbed on the X window container. (exwm-input--init): Add `exwm-input--on-minibuffer-setup' to `minibuffer-setup-hook'. * exwm-layout.el (exwm-layout--resize-container): New function to resize/reposition both the X window and its container. (exwm-layout--show, exwm-layout--hide): Use container. (exwm-layout-set-fullscreen): Use container. No longer save width and height. (exwm-layout-unset-fullscreen, exwm-layout--set-frame-fullscreen): Use container. (exwm-layout--refresh): Update a frame parameter. Remove dead code. * exwm-manage.el (exwm-manage--manage-window): Reparent unmanaged X windows to the workspace. Create X window container as the parent of the X window. (exwm-manage--unmanage-window): Unmap/destroy container when appropriate. Use the position of container. (exwm-manage--unmanage-window): Destroy the container. * exwm-randr.el (exwm-randr--refresh): Resize workspace using container. * exwm-workspace.el (exwm-workspace-switch): Raise workspace. Correctly set input focus. (exwm-workspace--on-focus-in): Removed. (exwm-workspace-move-window): Reparent to workspace container. (exwm-workspace--init): Create workspace frames as visible. Create workspace containers. Remove exwm-workspace--on-focus-in from focus-in-hook. Update _NET_VIRTUAL_ROOTS. * exwm.el (exwm-init): No longer disable hourglass window. Initialize workspace module before input. * exwm-core.el (exwm--debug): New macro for setting debug forms. * exwm-floating.el (exwm-floating--set-floating): No longer do `exwm--lock' and `exwm--unlock' since `make-frame' is already adviced to take care of everything. Correctly set input focus to the newly created floating X window. * exwm-core.el (exwm--floating-edges): Removed file local variable. * exwm-floating.el (exwm-floating--set-floating) (exwm-floating--unset-floating): * exwm-layout.el (exwm-layout--show, exwm-layout-enlarge-window): * exwm-manage.el (exwm-manage--on-ConfigureRequest): No longer use floating geometry. * exwm-input.el (exwm-input--update-global-prefix-keys): Grab global keys on workspaces containers instead of the root window (or input focus would transfer to the workspace containing the pointer when the grab is active). * exwm-workspace.el (exwm-workspace-switch): No longer move mouse.
This commit is contained in:
parent
07921a3731
commit
9c95c03e18
8 changed files with 356 additions and 354 deletions
140
exwm-input.el
140
exwm-input.el
|
|
@ -79,8 +79,6 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
|
|||
(xcb:flush exwm--connection))))
|
||||
|
||||
(defvar exwm-input--focus-window nil "The (Emacs) window to be focused.")
|
||||
(defvar exwm-input--redirected nil
|
||||
"Indicate next update on buffer list is actually a result of redirection.")
|
||||
(defvar exwm-input--timer nil "Currently running timer.")
|
||||
|
||||
(defun exwm-input--on-buffer-list-update ()
|
||||
|
|
@ -89,25 +87,12 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
|
|||
(window (selected-window))
|
||||
(buffer (current-buffer)))
|
||||
(when (and (not (minibufferp buffer))
|
||||
(frame-parameter frame 'exwm-window-id) ;e.g. emacsclient frame
|
||||
(frame-parameter frame 'exwm-outer-id) ;e.g. emacsclient frame
|
||||
(eq buffer (window-buffer))) ;e.g. `with-temp-buffer'
|
||||
(unless (and exwm-input--redirected
|
||||
exwm-input--focus-window
|
||||
(with-current-buffer (window-buffer
|
||||
exwm-input--focus-window)
|
||||
exwm--floating-frame))
|
||||
(setq exwm-input--focus-window window)
|
||||
(when exwm-input--timer (cancel-timer exwm-input--timer))
|
||||
(setq exwm-input--timer
|
||||
(run-with-idle-timer 0.01 nil #'exwm-input--update-focus)))
|
||||
(setq exwm-input--redirected nil))))
|
||||
|
||||
(defun exwm-input--on-focus-in ()
|
||||
"Run in focus-in-hook to remove redirected focus on frame."
|
||||
(let ((frame (selected-frame)))
|
||||
(when (and (frame-parameter frame 'exwm-window-id)
|
||||
(not (memq frame exwm-workspace--list)))
|
||||
(setq exwm-input--redirected t))))
|
||||
(when exwm-input--timer (cancel-timer exwm-input--timer))
|
||||
(setq exwm-input--focus-window window
|
||||
exwm-input--timer
|
||||
(run-with-idle-timer 0.01 nil #'exwm-input--update-focus)))))
|
||||
|
||||
(defun exwm-input--update-focus ()
|
||||
"Update input focus."
|
||||
|
|
@ -122,22 +107,42 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
|
|||
(force-mode-line-update)
|
||||
;; The application may have changed its input focus
|
||||
(exwm-workspace-switch exwm-workspace-current-index t))
|
||||
(when exwm--floating-frame
|
||||
(redirect-frame-focus exwm--floating-frame nil)
|
||||
(select-frame-set-input-focus exwm--floating-frame t))
|
||||
(exwm--log "Set focus on #x%x" exwm--id)
|
||||
(exwm-input--set-focus exwm--id))
|
||||
(exwm-input--set-focus exwm--id)
|
||||
;; Adjust stacking orders
|
||||
(xcb:+request exwm--connection
|
||||
(make-instance 'xcb:ConfigureWindow
|
||||
:window exwm--container
|
||||
:value-mask xcb:ConfigWindow:StackMode
|
||||
:stack-mode (if exwm--floating-frame
|
||||
xcb:StackMode:Above
|
||||
xcb:StackMode:Below)))
|
||||
(xcb:+request exwm--connection
|
||||
(make-instance 'xcb:ConfigureWindow
|
||||
:window (frame-parameter
|
||||
(or exwm--floating-frame exwm--frame)
|
||||
'exwm-outer-id)
|
||||
:value-mask xcb:ConfigWindow:StackMode
|
||||
:stack-mode xcb:StackMode:Below))
|
||||
(xcb:flush exwm--connection))
|
||||
(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)
|
||||
(dolist (pair exwm--id-buffer-alist)
|
||||
(with-current-buffer (cdr pair)
|
||||
(when (and exwm--floating-frame
|
||||
(eq exwm--frame exwm-workspace--current))
|
||||
(redirect-frame-focus exwm--floating-frame exwm--frame))))))
|
||||
(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)))
|
||||
(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
|
||||
|
|
@ -221,32 +226,38 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
|
|||
"Update `exwm-input--global-prefix-keys'."
|
||||
(when exwm--connection
|
||||
(let ((original exwm-input--global-prefix-keys)
|
||||
keysym keycode)
|
||||
keysym keycode ungrab-key grab-key workspace)
|
||||
(setq exwm-input--global-prefix-keys nil)
|
||||
(dolist (i exwm-input--global-keys)
|
||||
(cl-pushnew (elt i 0) exwm-input--global-prefix-keys))
|
||||
(unless (equal original exwm-input--global-prefix-keys)
|
||||
;; Grab global keys on root window
|
||||
(if (xcb:+request-checked+request-check exwm--connection
|
||||
(make-instance 'xcb:UngrabKey
|
||||
:key xcb:Grab:Any :grab-window exwm--root
|
||||
:modifiers xcb:ModMask:Any))
|
||||
(exwm--log "Failed to ungrab keys")
|
||||
(dolist (i exwm-input--global-prefix-keys)
|
||||
(setq keysym (xcb:keysyms:event->keysym exwm--connection i))
|
||||
(when (or (not keysym)
|
||||
(not (setq keycode (xcb:keysyms:keysym->keycode
|
||||
exwm--connection (car keysym))))
|
||||
(xcb:+request-checked+request-check exwm--connection
|
||||
(make-instance 'xcb:GrabKey
|
||||
:owner-events 0
|
||||
:grab-window exwm--root
|
||||
:modifiers (cadr keysym)
|
||||
:key keycode
|
||||
:pointer-mode xcb:GrabMode:Async
|
||||
:keyboard-mode xcb:GrabMode:Async)))
|
||||
(user-error "[EXWM] Failed to grab key: %s"
|
||||
(single-key-description i)))))))))
|
||||
(setq ungrab-key (make-instance 'xcb:UngrabKey
|
||||
:key xcb:Grab:Any :grab-window nil
|
||||
:modifiers xcb:ModMask:Any)
|
||||
grab-key (make-instance 'xcb:GrabKey
|
||||
:owner-events 0
|
||||
:grab-window nil
|
||||
:modifiers nil
|
||||
:key nil
|
||||
:pointer-mode xcb:GrabMode:Async
|
||||
:keyboard-mode xcb:GrabMode:Async))
|
||||
(dolist (w exwm-workspace--list)
|
||||
(setq workspace (frame-parameter w 'exwm-workspace))
|
||||
(setf (slot-value ungrab-key 'grab-window) workspace)
|
||||
(if (xcb:+request-checked+request-check exwm--connection ungrab-key)
|
||||
(exwm--log "Failed to ungrab keys")
|
||||
(dolist (k exwm-input--global-prefix-keys)
|
||||
(setq keysym (xcb:keysyms:event->keysym exwm--connection k)
|
||||
keycode (xcb:keysyms:keysym->keycode exwm--connection
|
||||
(car keysym)))
|
||||
(setf (slot-value grab-key 'grab-window) workspace
|
||||
(slot-value grab-key 'modifiers) (cadr keysym)
|
||||
(slot-value grab-key 'key) keycode)
|
||||
(when (or (not keycode)
|
||||
(xcb:+request-checked+request-check exwm--connection
|
||||
grab-key))
|
||||
(user-error "[EXWM] Failed to grab key: %s"
|
||||
(single-key-description k))))))))))
|
||||
|
||||
(defun exwm-input-set-key (key command)
|
||||
"Set a global key binding."
|
||||
|
|
@ -289,21 +300,6 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
|
|||
(with-slots (detail state) key-press
|
||||
(let ((keysym (xcb:keysyms:keycode->keysym exwm--connection detail state))
|
||||
event)
|
||||
;; Compensate FocusOut event (prevent cursor style change)
|
||||
(unless (eq major-mode 'exwm-mode)
|
||||
(let ((id (frame-parameter nil 'exwm-window-id)))
|
||||
(xcb:+request exwm--connection
|
||||
(make-instance 'xcb:SendEvent
|
||||
:propagate 0
|
||||
:destination id
|
||||
:event-mask xcb:EventMask:StructureNotify
|
||||
:event
|
||||
(xcb:marshal
|
||||
(make-instance 'xcb:FocusIn
|
||||
:detail xcb:NotifyDetail:Inferior
|
||||
:event id
|
||||
:mode xcb:NotifyMode:Normal)
|
||||
exwm--connection)))))
|
||||
(when (and keysym
|
||||
(setq event (xcb:keysyms:keysym->event exwm--connection
|
||||
keysym state)))
|
||||
|
|
@ -324,7 +320,10 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
|
|||
(when id
|
||||
(when (xcb:+request-checked+request-check exwm--connection
|
||||
(make-instance 'xcb:GrabKey
|
||||
:owner-events 0 :grab-window id
|
||||
:owner-events 0
|
||||
:grab-window
|
||||
(with-current-buffer (exwm--id->buffer id)
|
||||
exwm--container)
|
||||
:modifiers xcb:ModMask:Any
|
||||
:key xcb:Grab:Any
|
||||
:pointer-mode xcb:GrabMode:Async
|
||||
|
|
@ -338,7 +337,10 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
|
|||
(when id
|
||||
(when (xcb:+request-checked+request-check exwm--connection
|
||||
(make-instance 'xcb:UngrabKey
|
||||
:key xcb:Grab:Any :grab-window id
|
||||
:key xcb:Grab:Any
|
||||
:grab-window
|
||||
(with-current-buffer (exwm--id->buffer id)
|
||||
exwm--container)
|
||||
:modifiers xcb:ModMask:Any))
|
||||
(exwm--log "Failed to release keyboard for #x%x" id))
|
||||
(setq exwm--on-KeyPress #'exwm-input--on-KeyPress-char-mode)))
|
||||
|
|
@ -487,7 +489,7 @@ SIMULATION-KEYS is a list of alist (key-sequence1 . key-sequence2)."
|
|||
(add-hook 'pre-command-hook #'exwm-input--finish-key-sequence)
|
||||
;; Update focus when buffer list updates
|
||||
(add-hook 'buffer-list-update-hook #'exwm-input--on-buffer-list-update)
|
||||
(add-hook 'focus-in-hook #'exwm-input--on-focus-in)
|
||||
(add-hook 'minibuffer-setup-hook #'exwm-input--on-minibuffer-setup)
|
||||
;; Update prefix keys for global keys
|
||||
(exwm-input--update-global-prefix-keys))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue