mirror of
https://github.com/emacs-exwm/exwm.git
synced 2024-11-27 14:57:59 +01:00
Prevent/Reduce flickering issues with floating X windows
* exwm-floating.el (exwm-floating--set-floating) (exwm-floating--unset-floating): Prevent flickering when creating/removing a floating X window. * exwm-layout.el (exwm-layout--show): Show X windows after resizing to prevent flickering. * exwm-manage.el (exwm-manage--unmanage-window): Reduce flickering by hiding the container. (exwm-manage--kill-buffer-query-function): Prevent flickering by hiding the container (except that the X window destroys itself after receiving the WM_DELETE_WINDOW client message).
This commit is contained in:
parent
33254c37df
commit
1c79e1c238
3 changed files with 78 additions and 29 deletions
|
@ -193,17 +193,42 @@
|
||||||
(remove-hook 'window-configuration-change-hook #'exwm-layout--refresh)
|
(remove-hook 'window-configuration-change-hook #'exwm-layout--refresh)
|
||||||
(set-window-buffer window (current-buffer)) ;this changes current buffer
|
(set-window-buffer window (current-buffer)) ;this changes current buffer
|
||||||
(add-hook 'window-configuration-change-hook #'exwm-layout--refresh)
|
(add-hook 'window-configuration-change-hook #'exwm-layout--refresh)
|
||||||
(set-window-dedicated-p window t)
|
(set-window-dedicated-p window t))
|
||||||
(exwm-layout--show id window))
|
(select-frame-set-input-focus frame)
|
||||||
(select-frame-set-input-focus frame))
|
;; `x_make_frame_visible' autoraises the frame. Force lowering it.
|
||||||
(run-hooks 'exwm-floating-setup-hook))
|
(xcb:+request exwm--connection
|
||||||
|
(make-instance 'xcb:ConfigureWindow
|
||||||
|
:window outer-id
|
||||||
|
:value-mask xcb:ConfigWindow:StackMode
|
||||||
|
:stack-mode xcb:StackMode:Below))
|
||||||
|
;; Show the X window with its container (and flush).
|
||||||
|
(exwm-layout--show id window))
|
||||||
|
(run-hooks 'exwm-floating-setup-hook)
|
||||||
|
;; Redraw the frame.
|
||||||
|
(redisplay))
|
||||||
|
|
||||||
(defun exwm-floating--unset-floating (id)
|
(defun exwm-floating--unset-floating (id)
|
||||||
"Make window ID non-floating."
|
"Make window ID non-floating."
|
||||||
(let ((buffer (exwm--id->buffer id)))
|
(let ((buffer (exwm--id->buffer id)))
|
||||||
(with-current-buffer buffer
|
(with-current-buffer buffer
|
||||||
;; Reparent the frame back to the root window.
|
|
||||||
(when exwm--floating-frame
|
(when exwm--floating-frame
|
||||||
|
;; The X window is already mapped.
|
||||||
|
;; Unmap the container to prevent flickering.
|
||||||
|
(xcb:+request exwm--connection
|
||||||
|
(make-instance 'xcb:UnmapWindow :window exwm--container))
|
||||||
|
(xcb:flush exwm--connection)
|
||||||
|
;; Unmap the X window.
|
||||||
|
(xcb:+request exwm--connection
|
||||||
|
(make-instance 'xcb:ChangeWindowAttributes
|
||||||
|
:window id :value-mask xcb:CW:EventMask
|
||||||
|
:event-mask xcb:EventMask:NoEvent))
|
||||||
|
(xcb:+request exwm--connection
|
||||||
|
(make-instance 'xcb:UnmapWindow :window id))
|
||||||
|
(xcb:+request exwm--connection
|
||||||
|
(make-instance 'xcb:ChangeWindowAttributes
|
||||||
|
:window id :value-mask xcb:CW:EventMask
|
||||||
|
:event-mask exwm--client-event-mask))
|
||||||
|
;; Reparent the floating frame back to the root window.
|
||||||
(let ((frame-id (frame-parameter exwm--floating-frame 'exwm-outer-id)))
|
(let ((frame-id (frame-parameter exwm--floating-frame 'exwm-outer-id)))
|
||||||
(xcb:+request exwm--connection
|
(xcb:+request exwm--connection
|
||||||
(make-instance 'xcb:UnmapWindow :window frame-id))
|
(make-instance 'xcb:UnmapWindow :window frame-id))
|
||||||
|
|
|
@ -53,14 +53,6 @@
|
||||||
(defun exwm-layout--show (id &optional window)
|
(defun exwm-layout--show (id &optional window)
|
||||||
"Show window ID exactly fit in the Emacs window WINDOW."
|
"Show window ID exactly fit in the Emacs window WINDOW."
|
||||||
(exwm--log "Show #x%x in %s" id window)
|
(exwm--log "Show #x%x in %s" id window)
|
||||||
(xcb:+request exwm--connection (make-instance 'xcb:MapWindow :window id))
|
|
||||||
(with-current-buffer (exwm--id->buffer id)
|
|
||||||
(xcb:+request exwm--connection
|
|
||||||
(make-instance 'xcb:MapWindow :window exwm--container)))
|
|
||||||
(xcb:+request exwm--connection
|
|
||||||
(make-instance 'xcb:icccm:set-WM_STATE
|
|
||||||
:window id :state xcb:icccm:WM_STATE:NormalState
|
|
||||||
:icon xcb:Window:None))
|
|
||||||
(let* ((edges (window-inside-absolute-pixel-edges window))
|
(let* ((edges (window-inside-absolute-pixel-edges window))
|
||||||
(width (- (elt edges 2) (elt edges 0)))
|
(width (- (elt edges 2) (elt edges 0)))
|
||||||
(height (- (elt edges 3) (elt edges 1))))
|
(height (- (elt edges 3) (elt edges 1))))
|
||||||
|
@ -93,7 +85,16 @@
|
||||||
(elt relative-edges 0)
|
(elt relative-edges 0)
|
||||||
(elt relative-edges 1)
|
(elt relative-edges 1)
|
||||||
width height
|
width height
|
||||||
(active-minibuffer-window)))))
|
(active-minibuffer-window))))
|
||||||
|
;; Make the resizing take effect.
|
||||||
|
(xcb:flush exwm--connection)
|
||||||
|
(xcb:+request exwm--connection (make-instance 'xcb:MapWindow :window id))
|
||||||
|
(xcb:+request exwm--connection
|
||||||
|
(make-instance 'xcb:MapWindow :window exwm--container))
|
||||||
|
(xcb:+request exwm--connection
|
||||||
|
(make-instance 'xcb:icccm:set-WM_STATE
|
||||||
|
:window id :state xcb:icccm:WM_STATE:NormalState
|
||||||
|
:icon xcb:Window:None)))
|
||||||
(xcb:+request exwm--connection
|
(xcb:+request exwm--connection
|
||||||
(make-instance 'xcb:SendEvent
|
(make-instance 'xcb:SendEvent
|
||||||
:propagate 0 :destination id
|
:propagate 0 :destination id
|
||||||
|
|
|
@ -213,14 +213,18 @@ corresponding buffer.")
|
||||||
(defun exwm-manage--unmanage-window (id &optional withdraw-only)
|
(defun exwm-manage--unmanage-window (id &optional withdraw-only)
|
||||||
"Unmanage window ID."
|
"Unmanage window ID."
|
||||||
(let ((buffer (exwm--id->buffer id)))
|
(let ((buffer (exwm--id->buffer id)))
|
||||||
(exwm--log "Unmanage #x%x (buffer: %s)" id buffer)
|
(exwm--log "Unmanage #x%x (buffer: %s, widthdraw: %s)"
|
||||||
|
id buffer withdraw-only)
|
||||||
(setq exwm--id-buffer-alist (assq-delete-all id exwm--id-buffer-alist))
|
(setq exwm--id-buffer-alist (assq-delete-all id exwm--id-buffer-alist))
|
||||||
(when (buffer-live-p buffer)
|
(when (buffer-live-p buffer)
|
||||||
(with-current-buffer buffer
|
(with-current-buffer buffer
|
||||||
;; Hide the floating frame as early as possible.
|
;; Flickering seems unavoidable here if the DestroyWindow request is
|
||||||
(when exwm--floating-frame (make-frame-invisible exwm--floating-frame))
|
;; not initiated by us.
|
||||||
|
;; What we can do is to hide the its container ASAP.
|
||||||
(xcb:+request exwm--connection
|
(xcb:+request exwm--connection
|
||||||
(make-instance 'xcb:UnmapWindow :window exwm--container))
|
(make-instance 'xcb:UnmapWindow :window exwm--container))
|
||||||
|
(xcb:flush exwm--connection)
|
||||||
|
;;
|
||||||
(setq exwm-workspace--switch-history-outdated t)
|
(setq exwm-workspace--switch-history-outdated t)
|
||||||
;;
|
;;
|
||||||
(when withdraw-only
|
(when withdraw-only
|
||||||
|
@ -254,12 +258,13 @@ corresponding buffer.")
|
||||||
:window id :property xcb:Atom:WM_STATE)))
|
:window id :property xcb:Atom:WM_STATE)))
|
||||||
;; Destroy the container (it seems it has to be delayed).
|
;; Destroy the container (it seems it has to be delayed).
|
||||||
(when exwm--floating-frame
|
(when exwm--floating-frame
|
||||||
(xcb:+request exwm--connection
|
;; Unmap the floating frame.
|
||||||
(make-instance 'xcb:ReparentWindow
|
(let ((window (frame-parameter exwm--floating-frame 'exwm-outer-id)))
|
||||||
:window (frame-parameter exwm--floating-frame
|
(xcb:+request exwm--connection
|
||||||
'exwm-outer-id)
|
(make-instance 'xcb:UnmapWindow :window window))
|
||||||
:parent exwm--root
|
(xcb:+request exwm--connection
|
||||||
:x 0 :y 0)))
|
(make-instance 'xcb:ReparentWindow
|
||||||
|
:window window :parent exwm--root :x 0 :y 0))))
|
||||||
(xcb:+request exwm--connection
|
(xcb:+request exwm--connection
|
||||||
(make-instance 'xcb:DestroyWindow :window exwm--container))
|
(make-instance 'xcb:DestroyWindow :window exwm--container))
|
||||||
(xcb:flush exwm--connection)
|
(xcb:flush exwm--connection)
|
||||||
|
@ -268,12 +273,12 @@ corresponding buffer.")
|
||||||
(kill-buffer)
|
(kill-buffer)
|
||||||
(when floating
|
(when floating
|
||||||
(select-window
|
(select-window
|
||||||
(frame-selected-window exwm-workspace--current))))))
|
(frame-selected-window exwm-workspace--current)))))
|
||||||
(xcb:+request exwm--connection ;update _NET_CLIENT_LIST
|
(xcb:+request exwm--connection ;update _NET_CLIENT_LIST
|
||||||
(make-instance 'xcb:ewmh:set-_NET_CLIENT_LIST
|
(make-instance 'xcb:ewmh:set-_NET_CLIENT_LIST
|
||||||
:window exwm--root
|
:window exwm--root
|
||||||
:data (vconcat (mapcar #'car exwm--id-buffer-alist))))
|
:data (vconcat (mapcar #'car exwm--id-buffer-alist))))
|
||||||
(xcb:flush exwm--connection)))
|
(xcb:flush exwm--connection))))
|
||||||
|
|
||||||
(defun exwm-manage--scan ()
|
(defun exwm-manage--scan ()
|
||||||
"Search for existing windows and try to manage them."
|
"Search for existing windows and try to manage them."
|
||||||
|
@ -300,6 +305,10 @@ corresponding buffer.")
|
||||||
(make-instance 'xcb:MapWindow :window exwm--id))
|
(make-instance 'xcb:MapWindow :window exwm--id))
|
||||||
;; The X window is no longer alive so just close the buffer.
|
;; The X window is no longer alive so just close the buffer.
|
||||||
;; Destroy the container.
|
;; Destroy the container.
|
||||||
|
;; Hide the container to prevent flickering.
|
||||||
|
(xcb:+request exwm--connection
|
||||||
|
(make-instance 'xcb:UnmapWindow :window exwm--container))
|
||||||
|
(xcb:flush exwm--connection)
|
||||||
(when exwm--floating-frame
|
(when exwm--floating-frame
|
||||||
(xcb:+request exwm--connection
|
(xcb:+request exwm--connection
|
||||||
(make-instance 'xcb:ReparentWindow
|
(make-instance 'xcb:ReparentWindow
|
||||||
|
@ -313,6 +322,9 @@ corresponding buffer.")
|
||||||
(throw 'return t))
|
(throw 'return t))
|
||||||
(unless (memq xcb:Atom:WM_DELETE_WINDOW exwm--protocols)
|
(unless (memq xcb:Atom:WM_DELETE_WINDOW exwm--protocols)
|
||||||
;; The X window does not support WM_DELETE_WINDOW; destroy it.
|
;; The X window does not support WM_DELETE_WINDOW; destroy it.
|
||||||
|
;; Hide the container to prevent flickering.
|
||||||
|
(xcb:+request exwm--connection
|
||||||
|
(make-instance 'xcb:UnmapWindow :window exwm--container))
|
||||||
(xcb:+request exwm--connection
|
(xcb:+request exwm--connection
|
||||||
(make-instance 'xcb:DestroyWindow :window exwm--id))
|
(make-instance 'xcb:DestroyWindow :window exwm--id))
|
||||||
(xcb:flush exwm--connection)
|
(xcb:flush exwm--connection)
|
||||||
|
@ -331,6 +343,10 @@ corresponding buffer.")
|
||||||
(unless (memq xcb:Atom:_NET_WM_PING exwm--protocols)
|
(unless (memq xcb:Atom:_NET_WM_PING exwm--protocols)
|
||||||
;; The window does not support _NET_WM_PING. To make sure it'll die,
|
;; The window does not support _NET_WM_PING. To make sure it'll die,
|
||||||
;; kill it after the time runs out.
|
;; kill it after the time runs out.
|
||||||
|
;; Hide the container to prevent flickering.
|
||||||
|
(xcb:+request exwm--connection
|
||||||
|
(make-instance 'xcb:UnmapWindow :window exwm--container))
|
||||||
|
(xcb:flush exwm--connection)
|
||||||
(run-with-timer exwm-manage-ping-timeout nil
|
(run-with-timer exwm-manage-ping-timeout nil
|
||||||
`(lambda () (exwm-manage--kill-client ,exwm--id)))
|
`(lambda () (exwm-manage--kill-client ,exwm--id)))
|
||||||
;; Wait for DestroyNotify event.
|
;; Wait for DestroyNotify event.
|
||||||
|
@ -368,6 +384,13 @@ Would you like to kill it? "
|
||||||
(defun exwm-manage--kill-client (&optional id)
|
(defun exwm-manage--kill-client (&optional id)
|
||||||
"Kill an X client."
|
"Kill an X client."
|
||||||
(unless id (setq id (exwm--buffer->id (current-buffer))))
|
(unless id (setq id (exwm--buffer->id (current-buffer))))
|
||||||
|
;; Hide the container to prevent flickering.
|
||||||
|
(let ((buffer (exwm--id->buffer id)))
|
||||||
|
(when buffer
|
||||||
|
(with-current-buffer buffer
|
||||||
|
(xcb:+request exwm--connection
|
||||||
|
(make-instance 'xcb:UnmapWindow :window exwm--container))
|
||||||
|
(xcb:flush exwm--connection))))
|
||||||
(let* ((response (xcb:+request-unchecked+reply exwm--connection
|
(let* ((response (xcb:+request-unchecked+reply exwm--connection
|
||||||
(make-instance 'xcb:ewmh:get-_NET_WM_PID :window id)))
|
(make-instance 'xcb:ewmh:get-_NET_WM_PID :window id)))
|
||||||
(pid (and response (slot-value response 'value)))
|
(pid (and response (slot-value response 'value)))
|
||||||
|
|
Loading…
Reference in a new issue