Hello,

I hope this is an acceptable question on this ML, please advise in case it 
wouldn't. 

TL/DR
The essential question is about how to synchronize size and position of one 
top-level window to match another top-level window without getting limited by 
window manager constraints.


While I'm new to X11 development, coming from Windows, I don't think that this 
is a beginner's question, as I couldn't find an answer even after ingesting 
tons of resources, documentation and source code over the past days.

The goal is quite simple: I have a transparent Electron window with browser 
content and I want to layer this on top of a video window - or rather underlay 
the video window below the Electron window, in a way that size, position are 
synchronized and the video window is always one below the Electron window in 
the stacking order.

This is what I've tried so far:


1. Reparent both windows into a new X11 window

This is how it works on Windows and you're done already, as there's no 
distinction between top-level and deeper-level windows - composition and 
painting are always managed by the DWM. If I understood correctly, in case of 
X11 it's the responsibility of the application to handle composition of child 
windows inside a top-level window. Maybe that's not quite accurate, but in 
either case it burns down to the way how the Electron window is implementing 
transparency. 
The result I'm getting from this approach is that the Electron window is still 
transparent but it's using the background of the (also transparent) top-level 
window (that I've created) even though the video window is stacked in-between 
(below the Electron window). So the video cannot be seen.
I've traced this down from the Electron source code, then further to the 
Chromium source code and there I could see that their window is implemented 
using a GTK widget class. That widget in turn is using Cairo for copying the 
visual of the top-level window's background as the Electron window background 
in order to achieve transparency.
I had looked further into possible ways to override this behavior, but 
eventually I figured that this would probably never be an ideal solution, 
because when it comes to things like 4k video playback, I'd really want a 
solution where the compositing is handled by the system compositor and can 
possibly be done in hardware. 
This brought me to 2..


2. Use and stack two top-level windows

This is working pretty well across common Linux distributions with their 
default window managers and compositors.
(I should note that I'm not concerned about non-mainstream or customized 
desktop environments without a compositor or with non-overlapping window 
management. For those it will fallback to in-browser video playback, even 
though that's much inferior)

But there's a little caveat with that approach: as it turns out, many window 
managers on Linux appear to be insanely restrictive with regards to window 
placement. That wouldn't be an issue normally, but unfortunately these are 
making a distinction between positioning that is initiated by user actions and 
positioning set by an application.
There might be reasonable ideas behind this, but I think it's valid to ask the 
question why an application shouldn't be allowed to synchronize the position of 
a window to exactly match the position of another window while it's 
interactively moved around by a user?

To recap in a more illustrative way: The Electron window has a title bar, the 
video window is frameless. When moving around the Electron window on screen, 
the video window follows to match size and position (by receiving events for 
the Electron window and applying the same bounds to the video window) - as long 
as the Electron window remains within the bounds of the screen. 
As soon as it is moved (partially) outside the screen, the video window doesn't 
follow any further. It remains within the bounds of the screen.

And that limitation is what I've tried to overcome in many different ways - 
with mixed success:


2.1. Using _NET_MOVERESIZE_WINDOW instead of ConfigureWindow

This appeared to be promising as it involves flags for "source indication" - 
i.e. whether it's a change initiated by the user or programmatically. 
Unfortunately it turned out that it doesn't have any effect on the window 
managers I tried. I looked into the Mutter source code and it completely 
ignores it. 
Using this method still turned out to be useful, because some window managers 
ignore ConfigureWindow during an ongoing drag operation but that way is still 
working. 
Other window managers totally ignore this message.


2.2. Setting _WM_NORMAL_HINTS and _WM_SIZE_HINTS

Another shine of hope from reading the docs: There are flags in the structure 
for indicating whether position and size are set by a user (USPositiion, 
USSize), but it appears that those values aren't used anymore (which I found to 
be confirmed later in some other docs).


2.3. Enabling override-redirect

The docs mention that setting override-redirect on a window will prevent the 
window manager from interfering, so I set this on the video window.
This is actually working in a way that the position constraints are no longer 
applied: the video window properly follows the position and size of the 
Electron window - but: In that case, the video window is always rendered on top 
of all other windows, so the Electron window does no longer render above the 
video window. 
I tried RaiseWindow() and _NET_WM_STATE_ABOVE on the Electron window and 
setting _NET_WM_STATE_BELOW on the video window, without success.
I haven't tried RestackWindows() since even setting "Always on Top" through the 
window menu didn't bring it above the video window.


2.4. Setting window types DESKTOP and DOCK

While studying the source code for Mutter, I've noticed that it doesn't apply 
its constraints to windows of type DOCK and DESKTOP and this actually turned 
out to work for getting around the window constraints. By setting the type of 
both windows to DOCK and raising the Electron window above, I get them properly 
stacked on top of all other windows, and by setting type to DESKTOP, they get 
properly stacked below all other windows.
But the drawback is that the two windows can only be on top or below all other 
windows but not in-between like normal windows.
So, when these windows are on top and another window is focused, they need to 
be send all way to the bottom upon loosing focus - again a pretty odd behavior 
which is undesired.


2.5. Hacking the constraint implementations

I noticed that the constraint implementations of all the window managers I've 
tested have one thing in common: Once a window has gone beyond the constraint 
rules, they aren’t being applied anymore. That means, when I configure the 
video window to have a title bar and bring it to the point where it doesn't 
move any further to follow the Electron window (which has gone partially 
outside the screen) - I just need to (manually) move the video window slightly 
outside of the screen bounds, and from then on, it perfectly follows the main 
Electron window on all sides of the screen.

Once it gets back to be fully inside the screen area, it's prevented again from 
being moved outside. 
The takeaway is that, it just needs to be slightly moved over the border in 
some way, each time when moving the main window outside. The following hacks 
are based on that:


2.5.1. Applying .....

From the Mutter source code I've seen that ....
Works with most window managers.


2.5.2. Setting .....

-----
Works with some, but not all window managers, but not the same as 2.5.1.

(I apologize for redacting, but if it would turn out that this is the only 
possible way, I wouldn't want anybody getting an idea to "fix" these)


2.5.3. Briefly switching target window during move, using _NET_WM_MOVERESIZE

The idea is to briefly change the mouse movement target to the video window 
while the user is dragging around the main window, just to move it beyond the 
constraint limit and then switch it back to the main window. I haven't got this 
working in a usable way so far.


3. Leads and ideas that I haven't explored yet

- Exploring GrabWindow and the likes
- Can setting specific window classes (WM_CLASS) affect window manager behavior?
- Using window/client groups - could this help in any way?
- Configuring the video window as "output-only"
- Look into "manager selections"


Wrapping Up
===========

Thanks a lot for reading all the way through. While I've come to a point where 
I got things working as desired (more or less), these hacks are really not the 
way how I want to go forward. I can't stop thinking that there must be a better 
way - like "the right way to do this with X11".

I'd be very glad and thankful for any insights and advice on this task.

Best wishes
softworkz











Reply via email to