 
            Set an empty Wayland input region for windows that is marked as both WS_EX_TRANSPARENT and WS_EX_LAYERED in order to match the Windows behavior.
Setting an empty input region prevents the compositor from giving the pointer focus to the corresponding surface in the first place, and improves consistency between the Win32 mouse and Wayland pointer focus states.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58650
-- v3: winewayland: Pass through mouse events for transparent, layered windows.
 
            From: Alexandros Frantzis alexandros.frantzis@collabora.com
Set an empty Wayland input region for windows that is marked as both WS_EX_TRANSPARENT and WS_EX_LAYERED in order to match the Windows behavior.
Setting an empty input region prevents the compositor from giving the pointer focus to the corresponding surface in the first place, and improves consistency between the Win32 mouse and Wayland pointer focus states.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58650 --- dlls/winewayland.drv/window.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index 3b94112dc6d..7816f832900 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -193,12 +193,13 @@ static BOOL wayland_win_data_create_wayland_surface(struct wayland_win_data *dat struct wayland_surface *surface; enum wayland_surface_role role; BOOL visible; + DWORD exstyle = NtUserGetWindowLongW(data->hwnd, GWL_EXSTYLE); + struct wl_region *input_region;
TRACE("hwnd=%p\n", data->hwnd);
visible = ((NtUserGetWindowLongW(data->hwnd, GWL_STYLE) & WS_VISIBLE) == WS_VISIBLE) && - (!(NtUserGetWindowLongW(data->hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) || - data->layered_attribs_set); + (!(exstyle & WS_EX_LAYERED) || data->layered_attribs_set);
if (!visible) role = WAYLAND_SURFACE_ROLE_NONE; else if (toplevel_surface) role = WAYLAND_SURFACE_ROLE_SUBSURFACE; @@ -214,6 +215,14 @@ static BOOL wayland_win_data_create_wayland_surface(struct wayland_win_data *dat
if (!(surface = data->wayland_surface) && !(surface = wayland_surface_create(data->hwnd))) return FALSE;
+ /* Pass through mouse events for layered, transparent windows, to match + * Windows behavior. */ + input_region = ((exstyle & WS_EX_TRANSPARENT) && (exstyle & WS_EX_LAYERED)) ? + wl_compositor_create_region(process_wayland.wl_compositor) : + NULL; + wl_surface_set_input_region(surface->wl_surface, input_region); + if (input_region) wl_region_destroy(input_region); + /* If the window is a visible toplevel make it a wayland * xdg_toplevel. Otherwise keep it role-less to avoid polluting the * compositor with empty xdg_toplevels. */
 
            Fwiw I could approve this if you think it helps winewayland, but I'm not completely sure this is the right thing to do.
I don't see anything like that on the X11 side, and from reading about it a bit it seems to me that WS_EX_TRANSPARENT has some specific behavior that we should be implementing instead of magically delegating to the compositor. There are some details about it that we would possibly miss by doing that.
 
            On Fri Oct 17 21:10:22 2025 +0000, Rémi Bernon wrote:
Fwiw I could approve this if you think it helps winewayland, but I'm not completely sure this is the right thing to do. I don't see anything like that on the X11 side, and from reading about it a bit it seems to me that WS_EX_TRANSPARENT has some specific behavior that we should be implementing instead of magically delegating to the compositor. There are some details about it that we would possibly miss by doing that.
This is implemented in wineserver based on the `is_window_transparent` function. It's not implemented in winex11.drv, but we could do so by setting the window's ShapeInput region to empty. That would allow us to click through to non-Wine windows.
Xalia uses this on Windows: https://github.com/madewokherd/xalia/blob/main/xalia/Sdl/Win32LayeredBox.cs#...
and ShapeInput on X11: https://github.com/madewokherd/xalia/blob/main/xalia/Sdl/XShapeBox.cs#L134
I have tested both approaches.
 
            This merge request was approved by Rémi Bernon.
 
            I don't see anything like that on the X11 side, and from reading about it a bit it seems to me that WS_EX_TRANSPARENT has some specific behavior that we should be implementing instead of magically delegating to the compositor. There are some details about it that we would possibly miss by doing that.
I was able to find information about WS_EX_TRANSPARENT, but information about the combo `WS_EX_TRANSPARENT|WS_EX_LAYERED` is limited, and I am not sure at which level of the stack this should be applied ideally. As Esme notes, doing this at the host window system level at least gives us pass through to host windows, but what we are giving up in terms of other behaviors, I don't know.
FWIW, I ran some quick tests (Win10) and at least `WindowFromPoint()` seems to respect (i.e., pass through) `WS_EX_TRANSPARENT|WS_EX_LAYERED`.
One reason I have gone for this approach for winewayland (mentioned in the second paragraph of the commit message), is that if we allow `WS_EX_TRANSPARENT|WS_EX_LAYERED` windows to get the Wayland input focus, the cursor many not be properly set leading to the linked bug (null cursor, pointer constraints kicking in etc). I tried a few ways to work around the focus issue, but in the end not allowing mouse input and focus at all was the simplest and seemed consistent with the spirit of the flags.
Actually, checking WineX11, it seems to not be handling the cursor part fully correctly either at the moment (screenshots of FL Studio 2025, the small text popup under the cursor is `WS_EX_TRANSPARENT|WS_EX_LAYERED` ):

Whereas on Win10 and winewayland + this MR we get:

Perhaps solving the cursor issue (if this is caused and fixed at the core level) could also help with winewayland and allow us to not *need* this MR (although we may still *want* it for the passthrough-to-host-windows feature).



