X imposes a limitiation - that only 1 client can select for button presses on a window - this is due to the implicit grab nature of button press events in X. This poses a problem when more than one client wishes to select for these events on the same window - ie the root window, or in the case of a WM that has more than one root window (virtual root windows) any of these windows. The solution to this is to have the client that recieves these events handle any of the events it is interested in, and then ``proxy'' or ``pass on'' any events it doesnt not care about. Seeing the traditional model has always been that the WM selects for butotn presses on the desktop, it is only natural that it keep doing this BUT have a way of sending unwanted presses onto some other process(es) that may well be interested.
This is done as follows:
1. Set a property on the root window called _WIN_DESKTOP_BUTTON_PROXY. It is of the type cardinal - its value is the Window ID of another window that is not mapped that is created as an immediate child of the root window. This window also has this property set on it pointing to itself.
Display *disp; Window root, bpress_win; Atom atom_set; CARD32 val; atom_set = XInternAtom(disp, "_WIN_DESKTOP_BUTTON_PROXY", False); bpress_win = ECreateWindow(root, -80, -80, 24, 24, 0); val = bpress_win; XChangeProperty(disp, root, atom_set, XA_CARDINAL, 32, PropModeReplace, (unsigned char *), 1); XChangeProperty(disp, bpress_win, atom_set, XA_CARDINAL, 32, PropModeReplace, (unsigned char *), 1);2. Whenever the WM gets a button press or release event it can check the button on the mouse pressed, any modifiers etc. - if the WM wants the event it can deal with it as per normal and not proxy it on - if the WM does not wish to do anything as a result of this event, then it shoudl pass the event along like following:
Display *disp; Window bpress_win; XEvent *ev; XUngrabPointer(disp, CurrentTime); XSendEvent(disp, bpress_win, False, SubstructureNotifyMask, ev); |
where ev is a pointer to the actual Button press or release event it receives from the X Server (retaining timestamp, original window ID, co-ordinates etc.)
NB - the XUngrabPointer is only required before proxying a press, not a release.
The WM should proxy both button press and release events. It should only proxy a release if it also proxied the press corresponding to that release.
It is the responsibility of any apps listening for these events (and as many apps as want to can since they are being sent under the guise of SubstructureNotify events), to handle grabbing the pointer again and handling all events for the mouse while pressed until release etc.