mirror of
https://github.com/ch11ng/exwm.git
synced 2024-11-30 14:38:00 +01:00
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--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
|
(defvar exwm--guide-window nil
|
||||||
"An X window separating workspaces and X windows.")
|
"An X window separating workspaces and X windows.")
|
||||||
|
|
||||||
|
|
97
exwm.el
97
exwm.el
|
@ -529,12 +529,26 @@
|
||||||
(bury-buffer)))))
|
(bury-buffer)))))
|
||||||
(t (exwm--log "Unhandled client message: %s" obj)))))
|
(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 ()
|
(defun exwm--init-icccm-ewmh ()
|
||||||
"Initialize ICCCM/EWMH support."
|
"Initialize ICCCM/EWMH support."
|
||||||
;; Handle PropertyNotify event
|
;; Handle PropertyNotify event
|
||||||
(xcb:+event exwm--connection 'xcb:PropertyNotify #'exwm--on-PropertyNotify)
|
(xcb:+event exwm--connection 'xcb:PropertyNotify #'exwm--on-PropertyNotify)
|
||||||
;; Handle relevant client messages
|
;; Handle relevant client messages
|
||||||
(xcb:+event exwm--connection 'xcb:ClientMessage #'exwm--on-ClientMessage)
|
(xcb:+event exwm--connection 'xcb:ClientMessage #'exwm--on-ClientMessage)
|
||||||
|
;; Handle SelectionClear
|
||||||
|
(xcb:+event exwm--connection 'xcb:SelectionClear #'exwm--on-SelectionClear)
|
||||||
;; Set _NET_SUPPORTED
|
;; Set _NET_SUPPORTED
|
||||||
(xcb:+request exwm--connection
|
(xcb:+request exwm--connection
|
||||||
(make-instance 'xcb:ewmh:set-_NET_SUPPORTED
|
(make-instance 'xcb:ewmh:set-_NET_SUPPORTED
|
||||||
|
@ -667,6 +681,81 @@
|
||||||
:data [0 0]))
|
:data [0 0]))
|
||||||
(xcb:flush exwm--connection))
|
(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
|
;;;###autoload
|
||||||
(defun exwm-init (&optional frame)
|
(defun exwm-init (&optional frame)
|
||||||
"Initialize EXWM."
|
"Initialize EXWM."
|
||||||
|
@ -689,6 +778,11 @@
|
||||||
(slot-value (car (slot-value
|
(slot-value (car (slot-value
|
||||||
(xcb:get-setup exwm--connection) 'roots))
|
(xcb:get-setup exwm--connection) 'roots))
|
||||||
'root))
|
'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
|
(when (xcb:+request-checked+request-check exwm--connection
|
||||||
(make-instance 'xcb:ChangeWindowAttributes
|
(make-instance 'xcb:ChangeWindowAttributes
|
||||||
:window exwm--root :value-mask xcb:CW:EventMask
|
:window exwm--root :value-mask xcb:CW:EventMask
|
||||||
|
@ -697,9 +791,6 @@
|
||||||
;; Disable some features not working well with EXWM
|
;; Disable some features not working well with EXWM
|
||||||
(setq use-dialog-box nil
|
(setq use-dialog-box nil
|
||||||
confirm-kill-emacs #'exwm--confirm-kill-emacs)
|
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--lock)
|
||||||
(exwm--init-icccm-ewmh)
|
(exwm--init-icccm-ewmh)
|
||||||
(exwm-layout--init)
|
(exwm-layout--init)
|
||||||
|
|
Loading…
Reference in a new issue