Original patch description https://www.winehq.org/pipermail/wine-patches/2017-February/157574.html
winehq.org no longer provides the wine-patches archives, so it's necessary to dig into [web.archive.org](https://web.archive.org/web/20211011014926/https://www.winehq.org/pipermail/...):
https://web.archive.org/web/20211011014926/https://www.winehq.org/pipermail/...
https://web.archive.org/web/20211011014930/https://www.winehq.org/pipermail/...
===================================================================
Based on a patch by Dmitry Timoshkov.
## Signed-off-by: Sebastian Lackner sebastian@fds-team.de
Fixes https://bugs.winehq.org/show_bug.cgi?id=33943.
Battle.Net initially creates completely transparent popup windows and afterwards uses UpdateLayeredWindow without hdcSrc to let them fade in. Testing confirms that this works fine on Windows - on Wine however the original content is lost and no longer available. To avoid that, this patch stores the original content in the surface and uses _NET_WM_WINDOW_OPACITY to create a transparency effect. The same method is already used by SetLayeredWindowAttributes. If compositing is disabled, the window content will be visible immediately.
Dmitrys original patch used a different approach, and manually implemented the alpha blending in x11drv_surface_flush using additional buffers, however this shouldn't really be necessary (yet). We can still use it later if there is any benefit compared to using _NET_WM_WINDOW_OPACITY.
-- v4: winex11: Fix alpha blending in X11DRV_UpdateLayeredWindow.
From: Sebastian Lackner sebastian@fds-team.de
Based on a patch by Dmitry Timoshkov.
Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/win32u/driver.c | 6 +++--- dlls/win32u/window.c | 9 ++++++--- dlls/winemac.drv/macdrv.h | 2 +- dlls/winemac.drv/window.c | 4 ++-- dlls/winex11.drv/window.c | 6 +++++- dlls/winex11.drv/x11drv.h | 2 +- include/wine/gdi_driver.h | 2 +- 7 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 22e48fa6782..5edac6a0c8a 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -862,7 +862,7 @@ static LRESULT nulldrv_SysCommand( HWND hwnd, WPARAM wparam, LPARAM lparam, cons return -1; }
-static void nulldrv_UpdateLayeredWindow( HWND hwnd, UINT flags ) +static void nulldrv_UpdateLayeredWindow( HWND hwnd, BYTE alpha, UINT flags ) { }
@@ -1221,9 +1221,9 @@ static void loaderdrv_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw ) load_driver()->pSetWindowRgn( hwnd, hrgn, redraw ); }
-static void loaderdrv_UpdateLayeredWindow( HWND hwnd, UINT flags ) +static void loaderdrv_UpdateLayeredWindow( HWND hwnd, BYTE alpha, UINT flags ) { - load_driver()->pUpdateLayeredWindow( hwnd, flags ); + load_driver()->pUpdateLayeredWindow( hwnd, alpha, flags ); }
static UINT loaderdrv_VulkanInit( UINT version, void *vulkan_handle, const struct vulkan_driver_funcs **driver_funcs ) diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 0a3d6b28e47..c681333aa4a 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -2481,7 +2481,11 @@ BOOL WINAPI NtUserUpdateLayeredWindow( HWND hwnd, HDC hdc_dst, const POINT *pts_ apply_window_pos( hwnd, 0, swp_flags, surface, &new_rects, NULL ); if (!surface) return FALSE;
- if (!hdc_src || surface == &dummy_surface) ret = TRUE; + if (!hdc_src || surface == &dummy_surface) + { + user_driver->pUpdateLayeredWindow( hwnd, blend->SourceConstantAlpha, flags ); + ret = TRUE; + } else { BLENDFUNCTION src_blend = { AC_SRC_OVER, 0, 255, 0 }; @@ -2502,7 +2506,6 @@ BOOL WINAPI NtUserUpdateLayeredWindow( HWND hwnd, HDC hdc_dst, const POINT *pts_ if (pts_src) OffsetRect( &src_rect, pts_src->x, pts_src->y ); NtGdiTransformPoints( hdc_src, (POINT *)&src_rect, (POINT *)&src_rect, 2, NtGdiDPtoLP );
- if (flags & ULW_ALPHA) src_blend = *blend; ret = NtGdiAlphaBlend( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, hdc_src, src_rect.left, src_rect.top, src_rect.right - src_rect.left, src_rect.bottom - src_rect.top, *(DWORD *)&src_blend, 0 ); @@ -2514,7 +2517,7 @@ BOOL WINAPI NtUserUpdateLayeredWindow( HWND hwnd, HDC hdc_dst, const POINT *pts_ if (!(flags & ULW_COLORKEY)) key = CLR_INVALID; window_surface_set_layered( surface, key, -1, 0xff000000 );
- user_driver->pUpdateLayeredWindow( hwnd, flags ); + user_driver->pUpdateLayeredWindow( hwnd, blend->SourceConstantAlpha, flags ); window_surface_flush( surface ); }
diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 4457a7e186c..4673d69654a 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -145,7 +145,7 @@ extern void macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alph extern void macdrv_SetWindowText(HWND hwnd, LPCWSTR text); extern UINT macdrv_ShowWindow(HWND hwnd, INT cmd, RECT *rect, UINT swp); extern LRESULT macdrv_SysCommand(HWND hwnd, WPARAM wparam, LPARAM lparam, const POINT *pos); -extern void macdrv_UpdateLayeredWindow(HWND hwnd, UINT flags); +extern void macdrv_UpdateLayeredWindow(HWND hwnd, BYTE alpha, UINT flags); extern LRESULT macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); extern BOOL macdrv_WindowPosChanging(HWND hwnd, UINT swp_flags, BOOL shaped, const struct window_rects *rects); extern BOOL macdrv_GetWindowStyleMasks(HWND hwnd, UINT style, UINT ex_style, UINT *style_mask, UINT *ex_style_mask); diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index 05126678264..70d25dd8259 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -1627,7 +1627,7 @@ done: /*********************************************************************** * UpdateLayeredWindow (MACDRV.@) */ -void macdrv_UpdateLayeredWindow(HWND hwnd, UINT flags) +void macdrv_UpdateLayeredWindow(HWND hwnd, BYTE alpha, UINT flags) { struct macdrv_win_data *data;
@@ -1638,7 +1638,7 @@ void macdrv_UpdateLayeredWindow(HWND hwnd, UINT flags) show_window(data);
/* The ULW flags are a superset of the LWA flags. */ - sync_window_opacity(data, 255, TRUE, flags); + sync_window_opacity(data, alpha, FALSE, flags); release_win_data(data); } } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 615fb9da086..28026bbbfc3 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -3207,12 +3207,16 @@ void X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWO /*********************************************************************** * UpdateLayeredWindow (X11DRV.@) */ -void X11DRV_UpdateLayeredWindow( HWND hwnd, UINT flags ) +void X11DRV_UpdateLayeredWindow( HWND hwnd, BYTE alpha, UINT flags ) { struct x11drv_win_data *data; BOOL mapped;
if (!(data = get_win_data( hwnd ))) return; + + if (data->whole_window) + sync_window_opacity( data->display, data->whole_window, alpha, flags ); + mapped = data->desired_state.wm_state != WithdrawnState; release_win_data( data );
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 91811cfd766..a5bab864ad9 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -239,7 +239,7 @@ extern UINT X11DRV_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp ); extern LRESULT X11DRV_SysCommand( HWND hwnd, WPARAM wparam, LPARAM lparam, const POINT *pos ); extern LRESULT X11DRV_ClipboardWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ); extern void X11DRV_UpdateClipboard(void); -extern void X11DRV_UpdateLayeredWindow( HWND hwnd, UINT flags ); +extern void X11DRV_UpdateLayeredWindow( HWND hwnd, BYTE alpha, UINT flags ); extern LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ); extern BOOL X11DRV_WindowPosChanging( HWND hwnd, UINT swp_flags, BOOL shaped, const struct window_rects *rects ); extern BOOL X11DRV_GetWindowStyleMasks( HWND hwnd, UINT style, UINT ex_style, UINT *style_mask, UINT *ex_style_mask ); diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 51a095fd2b0..2774ab6e53a 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -381,7 +381,7 @@ struct user_driver_funcs void (*pSetWindowText)(HWND,LPCWSTR); UINT (*pShowWindow)(HWND,INT,RECT*,UINT); LRESULT (*pSysCommand)(HWND,WPARAM,LPARAM,const POINT*); - void (*pUpdateLayeredWindow)(HWND,UINT); + void (*pUpdateLayeredWindow)(HWND,BYTE,UINT); LRESULT (*pWindowMessage)(HWND,UINT,WPARAM,LPARAM); BOOL (*pWindowPosChanging)(HWND,UINT,BOOL,const struct window_rects *); BOOL (*pGetWindowStyleMasks)(HWND,UINT,UINT,UINT*,UINT*);
On Tue Mar 18 12:27:39 2025 +0000, Dmitry Timoshkov wrote:
Other places in dlls/winemac.drv/window.c including macdrv_SetLayeredWindowAttributes() call sync_window_opacity() with per_pixel_alpha set to FALSE.
Yes but ULW windows *have* per pixel alpha I believe. Anyway, I'll check.
Closing in preference to https://gitlab.winehq.org/wine/wine/-/merge_requests/7616
This merge request was closed by Dmitry Timoshkov.