[PATCH 0/2] MR11119: winewayland.drv: Add alpha-modifier-v1 protocol support for opacity.
From: chenjiangyi <chenjiangyi@uniontech.com> Signed-off-by: chenjiangyi <chenjiangyi@uniontech.com> --- dlls/winewayland.drv/Makefile.in | 1 + dlls/winewayland.drv/alpha-modifier-v1.xml | 103 +++++++++++++++++++++ dlls/winewayland.drv/wayland.c | 5 + dlls/winewayland.drv/wayland_surface.c | 29 ++++++ dlls/winewayland.drv/waylanddrv.h | 4 + dlls/winewayland.drv/window.c | 10 ++ 6 files changed, 152 insertions(+) create mode 100644 dlls/winewayland.drv/alpha-modifier-v1.xml diff --git a/dlls/winewayland.drv/Makefile.in b/dlls/winewayland.drv/Makefile.in index cbc49823cd6..95f690386a4 100644 --- a/dlls/winewayland.drv/Makefile.in +++ b/dlls/winewayland.drv/Makefile.in @@ -8,6 +8,7 @@ VER_FILEDESCRIPTION_STR = "Wine Wayland driver" SOURCES = \ cursor-shape-v1.xml \ + alpha-modifier-v1.xml \ display.c \ dllmain.c \ opengl.c \ diff --git a/dlls/winewayland.drv/alpha-modifier-v1.xml b/dlls/winewayland.drv/alpha-modifier-v1.xml new file mode 100644 index 00000000000..ab0a401d1ab --- /dev/null +++ b/dlls/winewayland.drv/alpha-modifier-v1.xml @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="UTF-8"?> +<protocol name="alpha_modifier_v1"> + <copyright> + Copyright © 2024 Xaver Hugl + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + </copyright> + + <interface name="wp_alpha_modifier_v1" version="1"> + <description summary="surface alpha modifier manager"> + This interface allows a client to set a factor for the alpha values on a + surface, which can be used to offload such operations to the compositor, + which can in turn for example offload them to KMS. + + Warning! The protocol described in this file is currently in the testing + phase. Backward compatible changes may be added together with the + corresponding interface version bump. Backward incompatible changes can + only be done by creating a new major version of the extension. + </description> + + <request name="destroy" type="destructor"> + <description summary="destroy the alpha modifier manager object"> + Destroy the alpha modifier manager. This doesn't destroy objects + created with the manager. + </description> + </request> + + <enum name="error"> + <entry name="already_constructed" value="0" + summary="wl_surface already has a alpha modifier object"/> + </enum> + + <request name="get_surface"> + <description summary="create a new alpha modifier surface object"> + Create a new alpha modifier surface object associated with the + given wl_surface. If there is already such an object associated with + the wl_surface, the already_constructed error will be raised. + </description> + <arg name="id" type="new_id" interface="wp_alpha_modifier_surface_v1"/> + <arg name="surface" type="object" interface="wl_surface"/> + </request> + </interface> + + <interface name="wp_alpha_modifier_surface_v1" version="1"> + <description summary="alpha modifier object for a surface"> + This interface allows the client to set a factor for the alpha values on + a surface, which can be used to offload such operations to the compositor. + The default factor is UINT32_MAX. + + This object has to be destroyed before the associated wl_surface. Once the + wl_surface is destroyed, all request on this object will raise the + no_surface error. + </description> + + <enum name="error"> + <entry name="no_surface" value="0" summary="wl_surface was destroyed"/> + </enum> + + <request name="destroy" type="destructor"> + <description summary="destroy the alpha modifier object"> + This destroys the object, and is equivalent to set_multiplier with + a value of UINT32_MAX, with the same double-buffered semantics as + set_multiplier. + </description> + </request> + + <request name="set_multiplier"> + <description summary="specify the alpha multiplier"> + Sets the alpha multiplier for the surface. The alpha multiplier is + double-buffered state, see wl_surface.commit for details. + + This factor is applied in the compositor's blending space, as an + additional step after the processing of per-pixel alpha values for the + wl_surface. The exact meaning of the factor is thus undefined, unless + the blending space is specified in a different extension. + + This multiplier is applied even if the buffer attached to the + wl_surface doesn't have an alpha channel; in that case an alpha value + of one is used instead. + + Zero means completely transparent, UINT32_MAX means completely opaque. + </description> + <arg name="factor" type="uint"/> + </request> + </interface> +</protocol> diff --git a/dlls/winewayland.drv/wayland.c b/dlls/winewayland.drv/wayland.c index b3d6b3c89e7..ba098685c46 100644 --- a/dlls/winewayland.drv/wayland.c +++ b/dlls/winewayland.drv/wayland.c @@ -205,6 +205,11 @@ static void registry_handle_global(void *data, struct wl_registry *registry, process_wayland.wp_pointer_warp_v1 = wl_registry_bind(registry, id, &wp_pointer_warp_v1_interface, 1); } + else if (strcmp(interface, "wp_alpha_modifier_v1") == 0) + { + process_wayland.wp_alpha_modifier_v1 = + wl_registry_bind(registry, id, &wp_alpha_modifier_v1_interface, 1); + } } static void registry_handle_global_remove(void *data, struct wl_registry *registry, diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index 4058c452a6f..b2a0f9d9836 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -173,6 +173,18 @@ struct wayland_surface *wayland_surface_create(HWND hwnd) ERR("Failed to create wp_viewport Wayland surface\n"); goto err; } + if (process_wayland.wp_alpha_modifier_v1) + { + COLORREF key; + DWORD flags; + BYTE alpha; + + surface->wp_alpha_modifier_surface_v1 = + wp_alpha_modifier_v1_get_surface(process_wayland.wp_alpha_modifier_v1, surface->wl_surface); + + if (!NtUserGetLayeredWindowAttributes(hwnd, &key, &alpha, &flags)) flags = 0; + wayland_surface_set_opacity(surface, alpha, flags); + } surface->window.scale = 1.0; @@ -212,6 +224,12 @@ void wayland_surface_destroy(struct wayland_surface *surface) wayland_surface_clear_role(surface); + if (surface->wp_alpha_modifier_surface_v1) + { + wp_alpha_modifier_surface_v1_destroy(surface->wp_alpha_modifier_surface_v1); + surface->wp_alpha_modifier_surface_v1 = NULL; + } + if (surface->wp_viewport) { wp_viewport_destroy(surface->wp_viewport); @@ -1362,3 +1380,14 @@ void wayland_surface_assign_icon(struct wayland_surface *surface) surface->xdg_toplevel, surface->xdg_toplevel_icon); } } + +void wayland_surface_set_opacity(struct wayland_surface *surface, BYTE alpha, UINT flags) +{ + if (surface->wp_alpha_modifier_surface_v1) + { + uint32_t opacity = (flags & LWA_ALPHA) ? (UINT32_MAX / 0xff) * alpha : UINT32_MAX; + wp_alpha_modifier_surface_v1_set_multiplier(surface->wp_alpha_modifier_surface_v1, opacity); + wl_surface_commit(surface->wl_surface); + wl_display_flush(process_wayland.wl_display); + } +} diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 5f4bd6a7cf6..3043a6044c9 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -39,6 +39,7 @@ #include "wlr-data-control-unstable-v1-client-protocol.h" #include "xdg-toplevel-icon-v1-client-protocol.h" #include "pointer-warp-v1-client-protocol.h" +#include "alpha-modifier-v1-client-protocol.h" #include "windef.h" #include "winbase.h" @@ -180,6 +181,7 @@ struct wayland struct xdg_toplevel_icon_manager_v1 *xdg_toplevel_icon_manager_v1; struct wp_cursor_shape_manager_v1 *wp_cursor_shape_manager_v1; struct wp_pointer_warp_v1 *wp_pointer_warp_v1; + struct wp_alpha_modifier_v1 *wp_alpha_modifier_v1; struct wayland_seat seat; struct wayland_keyboard keyboard; struct wayland_pointer pointer; @@ -286,6 +288,7 @@ struct wayland_surface HWND toplevel_hwnd; }; }; + struct wp_alpha_modifier_surface_v1 *wp_alpha_modifier_surface_v1; struct wayland_surface_config pending, requested, processing, current; BOOL resizing; @@ -337,6 +340,7 @@ void wayland_surface_ensure_contents(struct wayland_surface *surface); void wayland_surface_set_title(struct wayland_surface *surface, LPCWSTR title); void wayland_surface_assign_icon(struct wayland_surface *surface); void wayland_surface_set_icon_buffer(struct wayland_surface *surface, UINT type, const ICONINFO *ii); +void wayland_surface_set_opacity(struct wayland_surface *surface, BYTE alpha, UINT flags); static inline BOOL wayland_surface_is_toplevel(struct wayland_surface *surface) { diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index 88eee3421d7..f1862c6e241 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -673,9 +673,14 @@ LRESULT WAYLAND_DesktopWindowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) void WAYLAND_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags) { struct wayland_win_data *data; + struct wayland_surface *surface; if (!(data = wayland_win_data_get(hwnd))) return; + + if ((surface = data->wayland_surface)) + wayland_surface_set_opacity(surface, alpha, flags); data->layered_attribs_set = TRUE; + wayland_win_data_release(data); } @@ -727,6 +732,7 @@ void WAYLAND_SetWindowIcons(HWND hwnd, HICON icon, const ICONINFO *ii, HICON ico void WAYLAND_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style) { struct wayland_win_data *data; + struct wayland_surface *surface; DWORD changed = style->styleNew ^ style->styleOld; if (hwnd == NtUserGetDesktopWindow()) return; @@ -734,7 +740,11 @@ void WAYLAND_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style) /* Changing WS_EX_LAYERED resets attributes */ if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) + { + if ((surface = data->wayland_surface)) + wayland_surface_set_opacity(surface, 0, 0); data->layered_attribs_set = FALSE; + } wayland_win_data_release(data); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11119
From: chenjiangyi <chenjiangyi@uniontech.com> Signed-off-by: chenjiangyi <chenjiangyi@uniontech.com> --- dlls/winewayland.drv/waylanddrv.h | 1 + dlls/winewayland.drv/waylanddrv_main.c | 1 + dlls/winewayland.drv/window.c | 16 ++++++++++++++++ 3 files changed, 18 insertions(+) diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 3043a6044c9..53d3dbbfb15 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -458,6 +458,7 @@ void WAYLAND_SetWindowIcons(HWND hwnd, HICON icon, const ICONINFO *ii, HICON ico void WAYLAND_SetWindowStyle(HWND hwnd, INT offset, STYLESTRUCT *style); void WAYLAND_SetWindowText(HWND hwnd, LPCWSTR text); LRESULT WAYLAND_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam, const POINT *pos); +void WAYLAND_UpdateLayeredWindow(HWND hwnd, BYTE alpha, UINT flags); UINT WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manager, void *param); LRESULT WAYLAND_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags, diff --git a/dlls/winewayland.drv/waylanddrv_main.c b/dlls/winewayland.drv/waylanddrv_main.c index b7a8a29be70..5fae15c81eb 100644 --- a/dlls/winewayland.drv/waylanddrv_main.c +++ b/dlls/winewayland.drv/waylanddrv_main.c @@ -48,6 +48,7 @@ static const struct user_driver_funcs waylanddrv_funcs = .pSetWindowStyle = WAYLAND_SetWindowStyle, .pSetWindowText = WAYLAND_SetWindowText, .pSysCommand = WAYLAND_SysCommand, + .pUpdateLayeredWindow = WAYLAND_UpdateLayeredWindow, .pUpdateDisplayDevices = WAYLAND_UpdateDisplayDevices, .pWindowMessage = WAYLAND_WindowMessage, .pWindowPosChanged = WAYLAND_WindowPosChanged, diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index f1862c6e241..eb0ff222bf2 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -818,6 +818,22 @@ LRESULT WAYLAND_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam, const POINT return ret; } +/*********************************************************************** + * WAYLAND_UpdateLayeredWindow + */ +void WAYLAND_UpdateLayeredWindow(HWND hwnd, BYTE alpha, UINT flags) +{ + struct wayland_win_data *data; + struct wayland_surface *surface; + + if (!(data = wayland_win_data_get(hwnd))) return; + + if ((surface = data->wayland_surface)) + wayland_surface_set_opacity(surface, alpha, flags); + + wayland_win_data_release(data); +} + void set_client_surface(HWND hwnd, struct wayland_client_surface *new_client) { HWND toplevel = NtUserGetAncestor(hwnd, GA_ROOT); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11119
Looks good to me. Something of note is that the alpha multiplier will also affect all subsurfaces including subsurfaces that are supposed to be popups (unmanaged with an owner instead of it being a child window). But this issue will go away once xdg-popup is implemented which I have just is pending an MR. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11119#note_142776
This merge request was approved by Rémi Bernon. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11119
On Thu Jun 11 09:55:05 2026 +0000, Etaash Mathamsetty wrote:
Looks good to me. Something of note is that the alpha multiplier will also affect all subsurfaces including subsurfaces that are supposed to be popups (unmanaged with an owner instead of it being a child window). But this issue will go away once xdg-popup is implemented which I have just is pending an MR. It doesn't affect subsurfaces.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/11119#note_142798
On Thu Jun 11 17:55:42 2026 +0000, Julian Orth wrote:
It doesn't affect subsurfaces. It does, Xaver told me it's supposed to, but the protocol doesn't explicitly say it. But you can tell from the spec wording that it was supposed to affect subsurfaces too. For wine it does need to affect subsurfaces but not popups, which is how it was intended to work
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/11119#note_142863
On Thu Jun 11 17:56:09 2026 +0000, Etaash Mathamsetty wrote:
It does, Xaver told me it's supposed to, but the protocol doesn't explicitly say it. But you can tell from the spec wording that it was supposed to affect subsurfaces too. For wine it does need to affect subsurfaces but not popups, which is how it was intended to work Maybe it does behave like that on KWin then.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/11119#note_142865
On Thu Jun 11 18:02:02 2026 +0000, Julian Orth wrote:
Maybe it does behave like that on KWin then. Doesn't matter about kwin or not, if the intention from the protocol author was that it is supposed to affect subsurfaces then that's what it's supposed to do. Hopefully the spec wording will be fixed soon
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/11119#note_142870
On Thu Jun 11 18:06:01 2026 +0000, Etaash Mathamsetty wrote:
Doesn't matter about kwin or not, if the intention from the protocol author was that it is supposed to affect subsurfaces then that's what it's supposed to do. Hopefully the spec wording will be fixed soon There are several compositors that implement the spec wording as written, i.e. they only apply the alpha factor to the surface. I do not see any indication in the spec that it is supposed to apply to subsurfaces as well. A change in wording would therefore require at least a new protocol version or, rather, a flag that indicates which mode the client wants and which modes the compositor supports. Since many compositors simply won't be able to implement the subsurface variant without significant changes.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/11119#note_142871
On Thu Jun 11 18:12:10 2026 +0000, Julian Orth wrote:
There are several compositors that implement the spec wording as written, i.e. they only apply the alpha factor to the surface. I do not see any indication in the spec that it is supposed to apply to subsurfaces as well. A change in wording would therefore require at least a new protocol version or, rather, a flag that indicates which mode the client wants and which modes the compositor supports. Since many compositors simply won't be able to implement the subsurface variant without significant changes. Looks like Wayland protocols has some work to do then. Not sure if this should block the merging of this MR though
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/11119#note_142872
On Thu Jun 11 18:12:10 2026 +0000, Etaash Mathamsetty wrote:
Looks like Wayland protocols has some work to do then. Not sure if this should block the merging of this MR though I know nothing about the intended semantics on windows or whether wine uses subsurfaces in a way (other than popups) that would want one behavior or the other. For the popup case, it seemed that you didn't want the alpha to apply to them.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/11119#note_142873
On Thu Jun 11 18:15:06 2026 +0000, Julian Orth wrote:
I know nothing about the intended semantics on windows or whether wine uses subsurfaces in a way (other than popups) that would want one behavior or the other. For the popup case, it seemed that you didn't want the alpha to apply to them. there is two cases, one is where is a popup and the other is where its a child window (or subsurface). The child window needs to inherit the alpha like it does on windows. However, currently both are subsurfaces on winewayland.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/11119#note_142881
participants (4)
-
chenjiangyi -
Etaash Mathamsetty (@etaash.mathamsetty) -
Julian Orth (@mahkoh) -
Rémi Bernon (@rbernon)