Support replacing and being replaced by other window managers
* exwm.el (exwm--on-SelectionClear, exwm--init-icccm-ewmh) (exwm--exit-icccm-ewmh, exwm--wmsn-acquire, exwm--wmsn-release): Get the window manager selection; die when it is cleared.
This commit is contained in:
parent
350950abfc
commit
7aae6efdcd
2 changed files with 103 additions and 3 deletions
|
@ -37,6 +37,15 @@
|
|||
|
||||
(defvar exwm--connection nil "X connection.")
|
||||
|
||||
(defvar exwm--wmsn-window nil
|
||||
"An X window owning the WM_S0 selection.")
|
||||
|
||||
(defvar exwm--wmsn-acquire-timeout 3
|
||||
"Number of seconds to wait for other window managers to release the selection.")
|
||||
|
||||
(defvar exwm--wmsn-replace 'ask
|
||||
"Replace existing window manager.")
|
||||
|
||||
(defvar exwm--guide-window nil
|
||||
"An X window separating workspaces and X windows.")
|
||||
|
||||
|
|
97
exwm.el
97
exwm.el
|
@ -529,12 +529,26 @@
|
|||
(bury-buffer)))))
|
||||
(t (exwm--log "Unhandled client message: %s" obj)))))
|
||||
|
||||
(defun exwm--on-SelectionClear (data _synthetic)
|
||||
"Handle SelectionClear events."
|
||||
(exwm--log "SelectionClear")
|
||||
(let ((obj (make-instance 'xcb:SelectionClear))
|
||||
owner selection)
|
||||
(xcb:unmarshal obj data)
|
||||
(setq owner (slot-value obj 'owner)
|
||||
selection (slot-value obj 'selection))
|
||||
(when (and (eq owner exwm--wmsn-window)
|
||||
(eq selection xcb:Atom:WM_S0))
|
||||
(exwm-exit))))
|
||||
|
||||
(defun exwm--init-icccm-ewmh ()
|
||||
"Initialize ICCCM/EWMH support."
|
||||
;; Handle PropertyNotify event
|
||||
(xcb:+event exwm--connection 'xcb:PropertyNotify #'exwm--on-PropertyNotify)
|
||||
;; Handle relevant client messages
|
||||
(xcb:+event exwm--connection 'xcb:ClientMessage #'exwm--on-ClientMessage)
|
||||
;; Handle SelectionClear
|
||||
(xcb:+event exwm--connection 'xcb:SelectionClear #'exwm--on-SelectionClear)
|
||||
;; Set _NET_SUPPORTED
|
||||
(xcb:+request exwm--connection
|
||||
(make-instance 'xcb:ewmh:set-_NET_SUPPORTED
|
||||
|
@ -667,6 +681,81 @@
|
|||
:data [0 0]))
|
||||
(xcb:flush exwm--connection))
|
||||
|
||||
(defun exwm--wmsn-acquire (replace)
|
||||
"Acquire the WM_Sn selection.
|
||||
|
||||
REPLACE specifies what to do in case there already is a window
|
||||
manager. If t, replace it, if nil, abort and if `ask'."
|
||||
(with-slots (owner)
|
||||
(xcb:+request-unchecked+reply exwm--connection
|
||||
(make-instance 'xcb:GetSelectionOwner
|
||||
:selection xcb:Atom:WM_S0))
|
||||
(when (/= owner xcb:Window:None)
|
||||
(when (eq replace 'ask)
|
||||
(setq replace (yes-or-no-p "Replace existing window manager?")))
|
||||
(when (not replace)
|
||||
(error "Other window manager detected")))
|
||||
(let ((new-owner (xcb:generate-id exwm--connection)))
|
||||
(xcb:+request exwm--connection
|
||||
(make-instance 'xcb:CreateWindow
|
||||
:depth 0
|
||||
:wid new-owner
|
||||
:parent exwm--root
|
||||
:x -1
|
||||
:y -1
|
||||
:width 1
|
||||
:height 1
|
||||
:border-width 0
|
||||
:class xcb:WindowClass:CopyFromParent
|
||||
:visual 0
|
||||
:value-mask 0
|
||||
:override-redirect 0))
|
||||
(xcb:+request exwm--connection
|
||||
(make-instance 'xcb:ewmh:set-_NET_WM_NAME
|
||||
:window new-owner :data "EXWM selection owner"))
|
||||
(xcb:+request-checked+request-check exwm--connection
|
||||
(make-instance 'xcb:SetSelectionOwner
|
||||
:selection xcb:Atom:WM_S0
|
||||
:owner new-owner
|
||||
:time xcb:Time:CurrentTime))
|
||||
(with-slots (owner)
|
||||
(xcb:+request-unchecked+reply exwm--connection
|
||||
(make-instance 'xcb:GetSelectionOwner
|
||||
:selection xcb:Atom:WM_S0))
|
||||
(unless (eq owner new-owner)
|
||||
(error "Could not acquire ownership of WM selection")))
|
||||
;; Wait for the other window manager to terminate.
|
||||
(when (/= owner xcb:Window:None)
|
||||
(let (reply)
|
||||
(cl-dotimes (i 10) ;exwm--wmsn-acquire-timeout)
|
||||
(setq reply (xcb:+request-unchecked+reply exwm--connection
|
||||
(make-instance 'xcb:GetGeometry :drawable owner)))
|
||||
(when (not reply)
|
||||
(cl-return))
|
||||
(message "Waiting for other window manager to quit... %ds" i)
|
||||
(sleep-for 1))
|
||||
(when reply
|
||||
(error "Other window manager did not release selection in time"))))
|
||||
;; announce
|
||||
(let* ((cmd (make-instance 'xcb:ClientMessageData
|
||||
:data32 (vector xcb:Time:CurrentTime
|
||||
xcb:Atom:WM_S0
|
||||
new-owner
|
||||
0
|
||||
0)))
|
||||
(cm (make-instance 'xcb:ClientMessage
|
||||
:window exwm--root
|
||||
:format 32
|
||||
:type xcb:Atom:MANAGER
|
||||
:data cmd))
|
||||
(se (make-instance 'xcb:SendEvent
|
||||
:propagate 0
|
||||
:destination exwm--root
|
||||
:event-mask xcb:EventMask:NoEvent
|
||||
:event (xcb:marshal cm exwm--connection))))
|
||||
(xcb:+request exwm--connection se))
|
||||
(setq exwm--wmsn-window new-owner))))
|
||||
|
||||
;;;###autoload
|
||||
(defun exwm-init (&optional frame)
|
||||
"Initialize EXWM."
|
||||
|
@ -689,6 +778,11 @@
|
|||
(slot-value (car (slot-value
|
||||
(xcb:get-setup exwm--connection) 'roots))
|
||||
'root))
|
||||
;; Initialize ICCCM/EWMH support
|
||||
(xcb:icccm:init exwm--connection t)
|
||||
(xcb:ewmh:init exwm--connection t)
|
||||
;; Try to register window manager selection.
|
||||
(exwm--wmsn-acquire 'ask)
|
||||
(when (xcb:+request-checked+request-check exwm--connection
|
||||
(make-instance 'xcb:ChangeWindowAttributes
|
||||
:window exwm--root :value-mask xcb:CW:EventMask
|
||||
|
@ -697,9 +791,6 @@
|
|||
;; Disable some features not working well with EXWM
|
||||
(setq use-dialog-box nil
|
||||
confirm-kill-emacs #'exwm--confirm-kill-emacs)
|
||||
;; Initialize ICCCM/EWMH support
|
||||
(xcb:icccm:init exwm--connection t)
|
||||
(xcb:ewmh:init exwm--connection t)
|
||||
(exwm--lock)
|
||||
(exwm--init-icccm-ewmh)
|
||||
(exwm-layout--init)
|
||||
|
|
Loading…
Reference in a new issue