I have a transparent, watermark like application that is written with XLib in C. Currently if you click anywhere on the application nothing happens but I would like it to pass mouse input to whatever is below it. e.g. If you click the X to close a window that is below the application it should close the application, not do nothing.
Well this is what I found.
Note that this feature was added in the last decade so if you have an old version of X11, this may or may not work.
First include these into your project as they would be needed:
#include <X11/extensions/shape.h>
#include <X11/extensions/Xfixes.h>
And to change the input geometry (that is the place where you can interact with the window), in this case we'll set it to 0 by 0 pixels which would mean none. This is an example:
XRectangle rect;
XserverRegion region = XFixesCreateRegion(display, &rect, 1);
XFixesSetWindowShapeRegion(display, window, ShapeInput, 0, 0, region);
XFixesDestroyRegion(display, region);
And add this to the project linker -lXfixes
If you don't want your "watermark" window to receive any input, and instead have the input go to the window below it, then I would look into the implementation behind gtk_widget_input_shape_combine_region
. I previously used its predecessor gtk_widget_input_shape_combine_mask
to cause all parts of a popup window not to receive any events.
I'm out of my comfort zone here, but it looks like XShapeCombineRectangles is the relevant call (the linked do_shape_combine_region
is called with shape = ShapeInput
for this case).
I think XQueryTree
could be of help. Execute it onto the root window and get the list of child windows, find their locations and pass the mouse/keyboard's XEvent
to the appropriate window.
Note: You have to take care of active/inactive windows, active/inactive area of window, child of another window, size and x/y location of other windows. Code is going to be messy for this.
XQueryTree
, it should work, but some WMs (Openbox) insert a whole bunch of window nodes so you'll likely hit one of your own and end up processing the same event in a loop. Use _NET_CLIENT_LIST_STACKING
atom on root to get the windows in stacking order instead, it's cheaper and works better. –
Edroi You need to implement small window manager which will listen all events on default root indow using XSelectInput.
Then do polling on fd = connectionNember(display).
Whenever you receive event. Check if this is Mouse event, it will give you x,y. You can find the correct window by traversing the window stack.
Then use XGrabPinter to report event to the underlying window.
Some additional notes:
- If you want to do this in xcb, make sure you query xfixes version 5.0 first otherwise you will get a nebulous
BadRequest
error - Here is an alternate method (stolen from picom source, who in turn stole it from compiz source ☺)
xcb_shape_mask(conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, window, 0, 0, 0);
xcb_shape_rectangles(conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, window, 0, 0, 0, NULL);
As for how that works, I do not have a clue. XShape is notoriously undocumented. However the outcome seems to be the same.
© 2022 - 2024 — McMap. All rights reserved.