I am in the process of writing a window manager in Rust for learning purposes, using the xcb library. My code and several test windows (xterm
instances) are all running inside of a Xephyr session. I set my event mask on the root window as
xproto::EVENT_MASK_SUBSTRUCTURE_REDIRECT
| xproto::EVENT_MASK_SUBSTRUCTURE_NOTIFY
| xproto::EVENT_MASK_POINTER_MOTION
| xproto::EVENT_MASK_LEAVE_WINDOW
| xproto::EVENT_MASK_ENTER_WINDOW
| xproto::EVENT_MASK_BUTTON_PRESS
| xproto::EVENT_MASK_PROPERTY_CHANGE
| xproto::EVENT_MASK_FOCUS_CHANGE
and all child windows have an event mask of
xproto::EVENT_MASK_ENTER_WINDOW
| xproto::EVENT_MASK_LEAVE_WINDOW
| xproto::EVENT_MASK_BUTTON_PRESS
| xproto::EVENT_MASK_PROPERTY_CHANGE
| xproto::EVENT_MASK_POINTER_MOTION
| xproto::EVENT_MASK_FOCUS_CHANGE
| xproto::EVENT_MASK_STRUCTURE_NOTIFY
| xproto::EVENT_MASK_EXPOSURE
When I move the mouse over a non-root window, I use the EnterNotify
event to grab mouse buttons on that window, for click-to-focus purposes, and ungrab on LeaveNotify
. The sequence of events is:
EnterNotify
for non-root windowLeaveNotify
, while the mouse is still over the non-root windowLeaveNotify
LeaveNotify
for the non-root windowEnterNotify
for the root window, and grab mouse buttons on the root windowButtonPress
is sent for the root window, despite the cursor being over a non-root windowI'm genuinely unsure what the cause of this might be; using Google and the like has turned up nothing useful.
For anyone who might stumble across this later, a partial solution is:
SUBSTRUCTURE_REDIRECT | SUBSTRUCTURE_NOTIFY | BUTTON_PRESS
onlyLEAVE_WINDOW
onto non-root windows, and don't handle those eventsI don't want to add this as an answer because:
Take a look at the protocol reference manual. It describes (among lots of other things) the exact algorithm for generating enter and leave events: https://www.x.org/releases/X11R7.6/doc/xproto/x11protocol.html#events:pointer_window
In your specific case, I would expect the LeaveNotify
event to have mode: Grab
, which means that the window no longer has the "normal" pointer focus, because something (your program) grabbed the input.
If this is not the answer, I can recommend running your WM under xtrace / x11trace (available in Debian-based distros as package xtrace
). This program prints all X11 traffic that "goes through". This might help figuring out what is going on.