Update timestamp for WM_TAKE_FOCUS ClientMessage
* exwm-input.el (exwm-input--timestamp-window) (exwm-input--timestamp-atom, exwm-input--timestamp-callback): New variables for updating timestamp. (exwm-input--set-focus): Send WM_TAKE_FOCUS ClientMessage with updated timestamp. (exwm-input--update-timestamp): New utility function for fetching timestamp. (exwm-input--on-PropertyNotify): New function for handling PropertyNotify event to extract the timestamp. (exwm-input--init): Create resources for updating timestamp; attach the event listener. (exwm-input--on-ButtonPress, exwm-input--on-KeyPress): * exwm.el (exwm--on-PropertyNotify): No longer update timestamp. * exwm-input.el (exwm-input--set-focus): Avoid setting input focus on already focused X windows, or when the input focus in not on a Emacs frame if globally active model is in use. * exwm-floating.el (exwm-floating--set-floating): * exwm-workspace.el (exwm-workspace-move-window) (exwm-workspace--add-frame-as-workspace, exwm-workspace--init): Set 'exwm-id' frame parameter as the numerical (inner) frame X ID.
This commit is contained in:
parent
767abdf9e6
commit
810b4716a1
4 changed files with 112 additions and 34 deletions
|
@ -99,7 +99,9 @@ context of the corresponding buffer.")
|
|||
(height . ,window-min-height)
|
||||
(unsplittable . t))))) ;and fix the size later
|
||||
(outer-id (string-to-number (frame-parameter frame 'outer-window-id)))
|
||||
(container (buffer-local-value 'exwm--container (exwm--id->buffer id)))
|
||||
(window-id (string-to-number (frame-parameter frame 'window-id)))
|
||||
(container (buffer-local-value 'exwm--container
|
||||
(exwm--id->buffer id)))
|
||||
(frame-container (xcb:generate-id exwm--connection))
|
||||
(window (frame-first-window frame)) ;and it's the only window
|
||||
(x (slot-value exwm--geometry 'x))
|
||||
|
@ -118,6 +120,7 @@ context of the corresponding buffer.")
|
|||
width height x y)
|
||||
;; Save frame parameters.
|
||||
(set-frame-parameter frame 'exwm-outer-id outer-id)
|
||||
(set-frame-parameter frame 'exwm-id window-id)
|
||||
(set-frame-parameter frame 'exwm-container frame-container)
|
||||
;; Fix illegal parameters
|
||||
;; FIXME: check normal hints restrictions
|
||||
|
|
129
exwm-input.el
129
exwm-input.el
|
@ -48,10 +48,9 @@
|
|||
(defvar exwm-input--resize-keysym nil)
|
||||
(defvar exwm-input--resize-mask nil)
|
||||
|
||||
(defvar exwm-input--timestamp xcb:Time:CurrentTime
|
||||
"A recent timestamp received from X server.
|
||||
|
||||
It's updated in several occasions, and only used by `exwm-input--set-focus'.")
|
||||
(defvar exwm-input--timestamp-window nil)
|
||||
(defvar exwm-input--timestamp-atom nil)
|
||||
(defvar exwm-input--timestamp-callback nil)
|
||||
|
||||
(defvar exwm-workspace--current)
|
||||
(defvar exwm-workspace--switch-history-outdated)
|
||||
|
@ -62,37 +61,81 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.")
|
|||
(defun exwm-input--set-focus (id)
|
||||
"Set input focus to window ID in a proper way."
|
||||
(when (exwm--id->buffer id)
|
||||
(with-current-buffer (exwm--id->buffer id)
|
||||
(if (and (not exwm--hints-input)
|
||||
(memq xcb:Atom:WM_TAKE_FOCUS exwm--protocols))
|
||||
(progn
|
||||
(exwm--log "Focus on #x%x with WM_TAKE_FOCUS" id)
|
||||
(let ((focus (slot-value (xcb:+request-unchecked+reply exwm--connection
|
||||
(make-instance 'xcb:GetInputFocus))
|
||||
'focus)))
|
||||
(unless (= focus id)
|
||||
(with-current-buffer (exwm--id->buffer id)
|
||||
(cond
|
||||
((and (not exwm--hints-input)
|
||||
(memq xcb:Atom:WM_TAKE_FOCUS exwm--protocols))
|
||||
(when (= focus (frame-parameter nil 'exwm-id))
|
||||
(exwm--log "Focus on #x%x with WM_TAKE_FOCUS" id)
|
||||
(exwm-input--update-timestamp
|
||||
(lambda (timestamp id)
|
||||
(let ((event (make-instance 'xcb:icccm:WM_TAKE_FOCUS
|
||||
:window id
|
||||
:time timestamp)))
|
||||
(setq event (xcb:marshal event exwm--connection))
|
||||
(xcb:+request exwm--connection
|
||||
(make-instance 'xcb:icccm:SendEvent
|
||||
:destination id
|
||||
:event event))
|
||||
(exwm-input--set-active-window id)
|
||||
(xcb:flush exwm--connection)))
|
||||
id)))
|
||||
(t
|
||||
(exwm--log "Focus on #x%x with SetInputFocus" id)
|
||||
(xcb:+request exwm--connection
|
||||
(make-instance 'xcb:icccm:SendEvent
|
||||
:destination id
|
||||
:event (xcb:marshal
|
||||
(make-instance 'xcb:icccm:WM_TAKE_FOCUS
|
||||
:window id
|
||||
:time
|
||||
exwm-input--timestamp)
|
||||
exwm--connection))))
|
||||
(exwm--log "Focus on #x%x with SetInputFocus" id)
|
||||
(xcb:+request exwm--connection
|
||||
(make-instance 'xcb:SetInputFocus
|
||||
:revert-to xcb:InputFocus:Parent
|
||||
:focus id
|
||||
:time xcb:Time:CurrentTime)))
|
||||
(exwm-input--set-active-window id)
|
||||
(xcb:flush exwm--connection))))
|
||||
(make-instance 'xcb:SetInputFocus
|
||||
:revert-to xcb:InputFocus:Parent
|
||||
:focus id
|
||||
:time xcb:Time:CurrentTime))
|
||||
(exwm-input--set-active-window id)
|
||||
(xcb:flush exwm--connection))))))))
|
||||
|
||||
(defun exwm-input--update-timestamp (callback &rest args)
|
||||
"Fetch the latest timestamp from the server and feed it to CALLBACK.
|
||||
|
||||
ARGS are additional arguments to CALLBACK."
|
||||
(setq exwm-input--timestamp-callback (cons callback args))
|
||||
(xcb:+request exwm--connection
|
||||
(make-instance 'xcb:ChangeProperty
|
||||
:mode xcb:PropMode:Replace
|
||||
:window exwm-input--timestamp-window
|
||||
:property exwm-input--timestamp-atom
|
||||
:type xcb:Atom:CARDINAL
|
||||
:format 32
|
||||
:data-len 0
|
||||
:data nil))
|
||||
(xcb:flush exwm--connection))
|
||||
|
||||
(defun exwm-input--on-PropertyNotify (data _synthetic)
|
||||
"Handle PropertyNotify events."
|
||||
(when exwm-input--timestamp-callback
|
||||
(let ((obj (make-instance 'xcb:PropertyNotify)))
|
||||
(xcb:unmarshal obj data)
|
||||
(when (= exwm-input--timestamp-window
|
||||
(slot-value obj 'window))
|
||||
(apply (car exwm-input--timestamp-callback)
|
||||
(slot-value obj 'time)
|
||||
(cdr exwm-input--timestamp-callback))
|
||||
(setq exwm-input--timestamp-callback nil)))))
|
||||
|
||||
(defun exwm-input--on-FocusIn (data _synthetic)
|
||||
"Handle FocusIn events."
|
||||
(let ((obj (make-instance 'xcb:FocusIn)))
|
||||
(xcb:unmarshal obj data)
|
||||
(when (= (slot-value obj 'detail) xcb:NotifyDetail:Inferior)
|
||||
;; Transfer input focus back to the workspace when the workspace
|
||||
;; container unexpectedly receives it.
|
||||
(x-focus-frame exwm-workspace--current))))
|
||||
;; Not sure if this is the right thing to do but the point is the
|
||||
;; input focus should not stay at the root window or any container,
|
||||
;; or the result would be unpredictable. `x-focus-frame' would
|
||||
;; first set the input focus to the (previously) selected frame, and
|
||||
;; then `select-window' would further update the input focus if the
|
||||
;; selected window is displaying an `exwm-mode' buffer. Perhaps we
|
||||
;; should carefully filter out FocusIn events with certain 'detail'
|
||||
;; and 'mode' combinations, but this just works.
|
||||
(x-focus-frame (selected-frame))
|
||||
(select-window (selected-window))))
|
||||
|
||||
(defun exwm-input--on-workspace-list-change ()
|
||||
"Run in `exwm-input--update-global-prefix-keys'."
|
||||
|
@ -247,7 +290,6 @@ This value should always be overwritten.")
|
|||
window buffer frame)
|
||||
(xcb:unmarshal obj data)
|
||||
(with-slots (detail time event state) obj
|
||||
(setq exwm-input--timestamp time)
|
||||
(setq window (get-buffer-window (exwm--id->buffer event) t)
|
||||
buffer (window-buffer window))
|
||||
(cond ((and (= state exwm-input--move-mask)
|
||||
|
@ -296,7 +338,6 @@ This value should always be overwritten.")
|
|||
"Handle KeyPress event."
|
||||
(let ((obj (make-instance 'xcb:KeyPress)))
|
||||
(xcb:unmarshal obj data)
|
||||
(setq exwm-input--timestamp (slot-value obj 'time))
|
||||
(if (eq major-mode 'exwm-mode)
|
||||
(funcall exwm--on-KeyPress obj data)
|
||||
(exwm-input--on-KeyPress-char-mode obj))))
|
||||
|
@ -657,7 +698,33 @@ Its usage is the same with `exwm-input-set-simulation-keys'."
|
|||
exwm-input--move-mask (cdr move-key)
|
||||
exwm-input--resize-keysym (car resize-key)
|
||||
exwm-input--resize-mask (cdr resize-key)))
|
||||
;; Create the X window and intern the atom used to fetch timestamp.
|
||||
(setq exwm-input--timestamp-window (xcb:generate-id exwm--connection))
|
||||
(xcb:+request exwm--connection
|
||||
(make-instance 'xcb:CreateWindow
|
||||
:depth 0
|
||||
:wid exwm-input--timestamp-window
|
||||
:parent exwm--root
|
||||
:x -1
|
||||
:y -1
|
||||
:width 1
|
||||
:height 1
|
||||
:border-width 0
|
||||
:class xcb:WindowClass:CopyFromParent
|
||||
:visual 0
|
||||
:value-mask xcb:CW:EventMask
|
||||
:event-mask xcb:EventMask:PropertyChange))
|
||||
(let ((atom "_TIME"))
|
||||
(setq exwm-input--timestamp-atom
|
||||
(slot-value (xcb:+request-unchecked+reply exwm--connection
|
||||
(make-instance 'xcb:InternAtom
|
||||
:only-if-exists 0
|
||||
:name-len (length atom)
|
||||
:name atom))
|
||||
'atom)))
|
||||
;; Attach event listeners
|
||||
(xcb:+event exwm--connection 'xcb:PropertyNotify
|
||||
#'exwm-input--on-PropertyNotify)
|
||||
(xcb:+event exwm--connection 'xcb:KeyPress #'exwm-input--on-KeyPress)
|
||||
(xcb:+event exwm--connection 'xcb:ButtonPress #'exwm-input--on-ButtonPress)
|
||||
(xcb:+event exwm--connection 'xcb:ButtonRelease
|
||||
|
|
|
@ -691,10 +691,13 @@ INDEX must not exceed the current number of workspaces."
|
|||
(outer-id (string-to-number
|
||||
(frame-parameter new-frame
|
||||
'outer-window-id)))
|
||||
(window-id (string-to-number
|
||||
(frame-parameter new-frame 'window-id)))
|
||||
(frame-container (frame-parameter old-frame
|
||||
'exwm-container))
|
||||
(window (frame-root-window new-frame)))
|
||||
(set-frame-parameter new-frame 'exwm-outer-id outer-id)
|
||||
(set-frame-parameter new-frame 'exwm-id window-id)
|
||||
(set-frame-parameter new-frame 'exwm-container
|
||||
frame-container)
|
||||
(make-frame-invisible new-frame)
|
||||
|
@ -1149,10 +1152,12 @@ Please check `exwm-workspace--minibuffer-own-frame-p' first."
|
|||
(setq exwm-workspace--list (nconc exwm-workspace--list (list frame)))
|
||||
(let ((outer-id (string-to-number (frame-parameter frame
|
||||
'outer-window-id)))
|
||||
(window-id (string-to-number (frame-parameter frame 'window-id)))
|
||||
(container (xcb:generate-id exwm--connection))
|
||||
(workspace (xcb:generate-id exwm--connection)))
|
||||
;; Save window IDs
|
||||
(set-frame-parameter frame 'exwm-outer-id outer-id)
|
||||
(set-frame-parameter frame 'exwm-id window-id)
|
||||
(set-frame-parameter frame 'exwm-container container)
|
||||
(set-frame-parameter frame 'exwm-workspace workspace)
|
||||
;; In case it's created by emacsclient.
|
||||
|
@ -1356,9 +1361,13 @@ applied to all subsequently created X frames."
|
|||
(let ((outer-id (string-to-number
|
||||
(frame-parameter exwm-workspace--minibuffer
|
||||
'outer-window-id)))
|
||||
(window-id (string-to-number
|
||||
(frame-parameter exwm-workspace--minibuffer
|
||||
'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-id window-id)
|
||||
(set-frame-parameter exwm-workspace--minibuffer 'exwm-container
|
||||
container)
|
||||
(xcb:+request exwm--connection
|
||||
|
|
3
exwm.el
3
exwm.el
|
@ -315,8 +315,7 @@
|
|||
atom id buffer)
|
||||
(xcb:unmarshal obj data)
|
||||
(setq id (slot-value obj 'window)
|
||||
atom (slot-value obj 'atom)
|
||||
exwm-input--timestamp (slot-value obj 'time))
|
||||
atom (slot-value obj 'atom))
|
||||
(setq buffer (exwm--id->buffer id))
|
||||
(if (not (buffer-live-p buffer))
|
||||
;; Properties of unmanaged X windows.
|
||||
|
|
Loading…
Reference in a new issue