Fix controls on OpenMPT's channel setting dialog having incorrect background.
Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- dlls/user32/defdlg.c | 34 +++++-- dlls/user32/hook.c | 1 + dlls/user32/user_private.h | 1 + dlls/uxtheme/Makefile.in | 1 + dlls/uxtheme/dialog.c | 176 ++++++++++++++++++++++++++++++++++++ dlls/uxtheme/system.c | 1 + dlls/uxtheme/tests/system.c | 20 +--- dlls/uxtheme/uxthemedll.h | 1 + include/winuser.h | 1 + 9 files changed, 210 insertions(+), 26 deletions(-) create mode 100644 dlls/uxtheme/dialog.c
diff --git a/dlls/user32/defdlg.c b/dlls/user32/defdlg.c index 81c7cb0f207..4f44a93cd49 100644 --- a/dlls/user32/defdlg.c +++ b/dlls/user32/defdlg.c @@ -354,10 +354,7 @@ out: return dlgInfo; }
-/*********************************************************************** - * DefDlgProcA (USER32.@) - */ -LRESULT WINAPI DefDlgProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) +static LRESULT USER_DefDlgProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { DIALOGINFO *dlgInfo; DLGPROC dlgproc; @@ -411,10 +408,7 @@ LRESULT WINAPI DefDlgProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) return GetWindowLongPtrW( hwnd, DWLP_MSGRESULT ); }
-/*********************************************************************** - * DefDlgProcW (USER32.@) - */ -LRESULT WINAPI DefDlgProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) +static LRESULT USER_DefDlgProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { DIALOGINFO *dlgInfo; DLGPROC dlgproc; @@ -467,3 +461,27 @@ LRESULT WINAPI DefDlgProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
return GetWindowLongPtrW( hwnd, DWLP_MSGRESULT ); } + +LRESULT WINAPI USER_DefDlgProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode ) +{ + if (unicode) + return USER_DefDlgProcW( hwnd, msg, wParam, lParam ); + else + return USER_DefDlgProcA( hwnd, msg, wParam, lParam ); +} + +/*********************************************************************** + * DefDlgProcA (USER32.@) + */ +LRESULT WINAPI DefDlgProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + return user_api->pDefDlgProc( hwnd, msg, wParam, lParam, FALSE ); +} + +/*********************************************************************** + * DefDlgProcW (USER32.@) + */ +LRESULT WINAPI DefDlgProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + return user_api->pDefDlgProc( hwnd, msg, wParam, lParam, TRUE ); +} diff --git a/dlls/user32/hook.c b/dlls/user32/hook.c index 159797020f2..f5b4c6ab8a1 100644 --- a/dlls/user32/hook.c +++ b/dlls/user32/hook.c @@ -83,6 +83,7 @@ WINE_DECLARE_DEBUG_CHANNEL(relay);
static struct user_api_hook original_user_api = { + USER_DefDlgProc, USER_ScrollBarDraw, USER_ScrollBarProc, }; diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 6923ddb2906..7a9845adeb9 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -303,6 +303,7 @@ extern BOOL get_icon_size( HICON handle, SIZE *size ) DECLSPEC_HIDDEN; #endif
extern struct user_api_hook *user_api DECLSPEC_HIDDEN; +LRESULT WINAPI USER_DefDlgProc(HWND, UINT, WPARAM, LPARAM, BOOL) DECLSPEC_HIDDEN; LRESULT WINAPI USER_ScrollBarProc(HWND, UINT, WPARAM, LPARAM, BOOL) DECLSPEC_HIDDEN; void WINAPI USER_ScrollBarDraw(HWND, HDC, INT, enum SCROLL_HITTEST, const struct SCROLL_TRACKING_INFO *, BOOL, BOOL, RECT *, INT, INT, diff --git a/dlls/uxtheme/Makefile.in b/dlls/uxtheme/Makefile.in index 01751d3243a..933650f4261 100644 --- a/dlls/uxtheme/Makefile.in +++ b/dlls/uxtheme/Makefile.in @@ -5,6 +5,7 @@ DELAYIMPORTS = msimg32
C_SRCS = \ buffer.c \ + dialog.c \ draw.c \ main.c \ metric.c \ diff --git a/dlls/uxtheme/dialog.c b/dlls/uxtheme/dialog.c new file mode 100644 index 00000000000..87c2b7d1c13 --- /dev/null +++ b/dlls/uxtheme/dialog.c @@ -0,0 +1,176 @@ +/* + * Dialog theming support + * + * Copyright 2022 Zhiyi Zhang for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "uxtheme.h" +#include "uxthemedll.h" +#include "vssym32.h" + +extern ATOM atDialogThemeEnabled; +static const WCHAR wine_dialog_brush[] = L"wine_dialog_brush"; + +static HBRUSH get_dialog_background_brush(HWND hwnd, BOOL create) +{ + HBITMAP bitmap, old_bitmap; + HDC hdc, hdc_screen; + HBRUSH brush; + HTHEME theme; + DWORD flag; + HRESULT hr; + RECT rect; + SIZE size; + + if (!IsThemeActive()) + return NULL; + + flag = HandleToUlong(GetPropW(hwnd, (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled))); + if (flag != ETDT_ENABLETAB && flag != ETDT_ENABLEAEROWIZARDTAB) + return NULL; + + brush = GetPropW(hwnd, wine_dialog_brush); + if (brush) + return brush; + + if (!create) + return NULL; + + theme = OpenThemeData(NULL, L"Tab"); + if (!theme) + return NULL; + + hr = GetThemePartSize(theme, NULL, TABP_BODY, 0, NULL, TS_TRUE, &size); + if (FAILED(hr)) + { + size.cx = 10; + size.cy = 600; + } + + hdc_screen = GetDC(NULL); + hdc = CreateCompatibleDC(hdc_screen); + bitmap = CreateCompatibleBitmap(hdc_screen, size.cx, size.cy); + old_bitmap = SelectObject(hdc, bitmap); + + SetRect(&rect, 0, 0, size.cx, size.cy); + /* FIXME: XP draws the tab body bitmap directly without transparency even if there is */ + FillRect(hdc, &rect, GetSysColorBrush(COLOR_3DFACE)); + hr = DrawThemeBackground(theme, hdc, TABP_BODY, 0, &rect, NULL); + if (SUCCEEDED(hr)) + { + brush = CreatePatternBrush(bitmap); + SetPropW(hwnd, wine_dialog_brush, brush); + } + + SelectObject(hdc, old_bitmap); + DeleteDC(hdc); + ReleaseDC(NULL, hdc_screen); + CloseThemeData(theme); + return brush; +} + +static void destroy_dialog_brush(HWND hwnd) +{ + LOGBRUSH logbrush; + HBRUSH brush; + + brush = GetPropW(hwnd, wine_dialog_brush); + if (brush) + { + RemovePropW(hwnd, wine_dialog_brush); + if (GetObjectW(brush, sizeof(logbrush), &logbrush) == sizeof(logbrush)) + DeleteObject((HBITMAP)logbrush.lbHatch); + DeleteObject(brush); + } +} + +LRESULT WINAPI UXTHEME_DefDlgProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp, BOOL unicode) +{ + POINT org, old_org; + WNDPROC dlgproc; + HBRUSH brush; + LRESULT lr; + RECT rect; + HDC hdc; + + switch (msg) + { + case WM_NCDESTROY: + { + destroy_dialog_brush(hwnd); + break; + } + case WM_THEMECHANGED: + { + destroy_dialog_brush(hwnd); + InvalidateRect(hwnd, NULL, TRUE); + break; + } + case WM_ERASEBKGND: + { + dlgproc = (WNDPROC)GetWindowLongPtrW(hwnd, DWLP_DLGPROC); + lr = CallWindowProcW(dlgproc, hwnd, msg, wp, lp); + if (lr) + return lr; + + brush = get_dialog_background_brush(hwnd, TRUE); + if (!brush) + break; + + /* Using FillRect() to draw background could introduce a tiling effect if the destination + * rectangle is larger than the pattern brush size, which is usually 10x600. This bug is + * visible on property sheet pages if system DPI is set to 192. However, the same bug also + * exists on XP and explains why vista+ don't use gradient tab body background anymore */ + hdc = (HDC)wp; + GetViewportOrgEx(hdc, &org); + SetBrushOrgEx(hdc, org.x, org.y, &old_org); + GetClientRect(hwnd, &rect); + FillRect(hdc, &rect, brush); + SetBrushOrgEx(hdc, old_org.x, old_org.y, NULL); + return TRUE; + } + case WM_CTLCOLORSTATIC: + { + dlgproc = (WNDPROC)GetWindowLongPtrW(hwnd, DWLP_DLGPROC); + lr = CallWindowProcW(dlgproc, hwnd, msg, wp, lp); + if (lr) + return lr; + + brush = get_dialog_background_brush(hwnd, FALSE); + if (!brush) + break; + + hdc = (HDC)wp; + SetBkColor(hdc, GetSysColor(COLOR_BTNFACE)); + SetBkMode(hdc, TRANSPARENT); + + org.x = 0; + org.y = 0; + MapWindowPoints((HWND)lp, hwnd, &org, 1); + SetBrushOrgEx(hdc, -org.x, -org.y, NULL); + return (LRESULT)brush; + } + } + + return user_api.pDefDlgProc(hwnd, msg, wp, lp, unicode); +} diff --git a/dlls/uxtheme/system.c b/dlls/uxtheme/system.c index 61a608e5962..37c484387ec 100644 --- a/dlls/uxtheme/system.c +++ b/dlls/uxtheme/system.c @@ -1245,6 +1245,7 @@ BOOL WINAPI ThemeHooksInstall(void) { struct user_api_hook hooks;
+ hooks.pDefDlgProc = UXTHEME_DefDlgProc; hooks.pScrollBarDraw = UXTHEME_ScrollBarDraw; hooks.pScrollBarWndProc = UXTHEME_ScrollbarWndProc; return RegisterUserApiHook(&hooks, &user_api); diff --git a/dlls/uxtheme/tests/system.c b/dlls/uxtheme/tests/system.c index 4a5a6d291fc..540cd7d2fcd 100644 --- a/dlls/uxtheme/tests/system.c +++ b/dlls/uxtheme/tests/system.c @@ -1772,7 +1772,6 @@ static void test_EnableThemeDialogTexture(void) lr = SendMessageA(dialog, WM_ERASEBKGND, (WPARAM)child_hdc, 0); ok(lr != 0, "WM_ERASEBKGND failed.\n"); brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); - todo_wine ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected brush changed.\n");
/* Test disabling theme dialog texture should change the brush immediately */ @@ -1780,7 +1779,6 @@ static void test_EnableThemeDialogTexture(void) hr = EnableThemeDialogTexture(dialog, ETDT_DISABLE); ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr); brush2 = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); - todo_wine ok(brush2 != brush, "Expected a different brush.\n"); ok(brush2 == GetSysColorBrush(COLOR_BTNFACE), "Expected brush %p, got %p.\n", GetSysColorBrush(COLOR_BTNFACE), brush2); @@ -1799,7 +1797,6 @@ static void test_EnableThemeDialogTexture(void) hr = EnableThemeDialogTexture(dialog, ETDT_USETABTEXTURE); ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr); brush2 = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); - todo_wine ok(brush2 != brush, "Expected a different brush.\n");
/* Test ETDT_ENABLE | ETDT_USEAEROWIZARDTABTEXTURE should change the brush immediately */ @@ -1811,7 +1808,6 @@ static void test_EnableThemeDialogTexture(void) if (LOBYTE(LOWORD(GetVersion())) < 6) ok(brush2 == brush, "Expected the same brush.\n"); else - todo_wine ok(brush2 != brush, "Expected a different brush.\n");
hr = EnableThemeDialogTexture(dialog, ETDT_DISABLE); @@ -1832,7 +1828,6 @@ static void test_EnableThemeDialogTexture(void) SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); ret = GetBrushOrgEx(child_hdc, &org); ok(ret, "GetBrushOrgEx failed, error %u.\n", GetLastError()); - todo_wine ok(org.x == -1 && org.y == -2, "Expected (-1,-2), got %s.\n", wine_dbgstr_point(&org));
/* Test that WM_CTLCOLORSTATIC changes background mode when dialog texture is on */ @@ -1840,7 +1835,6 @@ static void test_EnableThemeDialogTexture(void) ok(old_mode != 0, "SetBkMode failed.\n"); SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); mode = SetBkMode(child_hdc, old_mode); - todo_wine ok(mode == TRANSPARENT, "Expected mode %#x, got %#x.\n", TRANSPARENT, mode);
/* Test that WM_CTLCOLORSTATIC changes background color when dialog texture is on */ @@ -1859,15 +1853,12 @@ static void test_EnableThemeDialogTexture(void) memset(&log_brush, 0, sizeof(log_brush)); count = GetObjectA(brush, sizeof(log_brush), &log_brush); ok(count == sizeof(log_brush), "GetObjectA failed, error %u.\n", GetLastError()); - todo_wine ok(log_brush.lbColor == 0, "Expected brush color %#x, got %#x.\n", 0, log_brush.lbColor); - todo_wine ok(log_brush.lbStyle == BS_PATTERN, "Expected brush style %#x, got %#x.\n", BS_PATTERN, log_brush.lbStyle);
memset(&bmp, 0, sizeof(bmp)); count = GetObjectA((HBITMAP)log_brush.lbHatch, sizeof(bmp), &bmp); - todo_wine ok(count == sizeof(bmp), "GetObjectA failed, error %u.\n", GetLastError());
theme = OpenThemeData(NULL, L"Tab"); @@ -1877,16 +1868,13 @@ static void test_EnableThemeDialogTexture(void) size.cy = 0; hr = GetThemePartSize(theme, NULL, TABP_BODY, 0, NULL, TS_TRUE, &size); ok(hr == S_OK, "GetThemePartSize failed, hr %#x.\n", hr); - todo_wine ok(bmp.bmWidth == size.cx, "Expected width %d, got %d.\n", size.cx, bmp.bmWidth); - todo_wine ok(bmp.bmHeight == size.cy, "Expected height %d, got %d.\n", size.cy, bmp.bmHeight);
CloseThemeData(theme);
/* Test that DefDlgProcA/W() are hooked for WM_CTLCOLORSTATIC */ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); - todo_wine ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected a different brush.\n"); brush2 = (HBRUSH)DefDlgProcW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); ok(brush2 == brush, "Expected the same brush.\n"); @@ -1895,11 +1883,12 @@ static void test_EnableThemeDialogTexture(void)
/* Test that DefWindowProcA/W() are also hooked for WM_CTLCOLORSTATIC */ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); - todo_wine ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected a different brush.\n"); brush2 = (HBRUSH)DefWindowProcW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); + todo_wine ok(brush2 == brush, "Expected the same brush.\n"); brush2 = (HBRUSH)DefWindowProcA(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); + todo_wine ok(brush2 == brush, "Expected the same brush.\n");
/* Test that DefWindowProcA/W() are not hooked for WM_ERASEBKGND. So the background is still @@ -1951,13 +1940,11 @@ static void test_EnableThemeDialogTexture(void) SetLastError(0xdeadbeef); ret = GetObjectA(brush, sizeof(log_brush), &log_brush); error = GetLastError(); - todo_wine ok(!ret || broken(ret) /* XP */, "GetObjectA succeeded.\n"); todo_wine ok(error == ERROR_INVALID_PARAMETER || broken(error == 0xdeadbeef) /* XP */, "Expected error %u, got %u.\n", ERROR_INVALID_PARAMETER, error); ret = DeleteObject(brush); - todo_wine ok(!ret || broken(ret) /* XP */, "DeleteObject succeeded.\n");
/* Should still report the same brush handle after the brush handle was freed */ @@ -1971,7 +1958,6 @@ static void test_EnableThemeDialogTexture(void) lr = SendMessageA(dialog, WM_THEMECHANGED, 0, 0); ok(lr == 0, "WM_THEMECHANGED failed.\n"); brush2 = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); - todo_wine ok(brush2 != brush, "Expected a different brush.\n");
ReleaseDC(child, child_hdc); @@ -2027,7 +2013,6 @@ static void test_EnableThemeDialogTexture(void) ok(lr != 0, "WM_ERASEBKGND failed.\n"); brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child); if (flags[i] == ETDT_ENABLETAB || flags[i] == ETDT_ENABLEAEROWIZARDTAB) - todo_wine ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture enabled.\n"); else ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture disabled.\n"); @@ -2054,7 +2039,6 @@ static void test_EnableThemeDialogTexture(void) || ((flags[i] | flags[j]) & ETDT_ENABLEAEROWIZARDTAB) == ETDT_ENABLEAEROWIZARDTAB) && !((flags[i] | flags[j]) & ETDT_DISABLE))) && (((flags[i] | flags[j]) & (ETDT_ENABLETAB | ETDT_ENABLEAEROWIZARDTAB)) != (ETDT_ENABLETAB | ETDT_ENABLEAEROWIZARDTAB))) - todo_wine ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture enabled.\n"); else ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture disabled.\n"); diff --git a/dlls/uxtheme/uxthemedll.h b/dlls/uxtheme/uxthemedll.h index c43ad703884..67130774392 100644 --- a/dlls/uxtheme/uxthemedll.h +++ b/dlls/uxtheme/uxthemedll.h @@ -106,6 +106,7 @@ extern HRESULT UXTHEME_SetActiveTheme(PTHEME_FILE tf) DECLSPEC_HIDDEN; extern void UXTHEME_UninitSystem(void) DECLSPEC_HIDDEN;
extern struct user_api_hook user_api DECLSPEC_HIDDEN; +LRESULT WINAPI UXTHEME_DefDlgProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL unicode) DECLSPEC_HIDDEN; void WINAPI UXTHEME_ScrollBarDraw(HWND hwnd, HDC dc, INT bar, enum SCROLL_HITTEST hit_test, const struct SCROLL_TRACKING_INFO *tracking_info, BOOL draw_arrows, BOOL draw_interior, RECT *rect, INT arrowsize, diff --git a/include/winuser.h b/include/winuser.h index 1d37bd44344..898c9034e33 100644 --- a/include/winuser.h +++ b/include/winuser.h @@ -4435,6 +4435,7 @@ struct SCROLL_TRACKING_INFO
struct user_api_hook { + LRESULT (WINAPI *pDefDlgProc)(HWND, UINT, WPARAM, LPARAM, BOOL); void (WINAPI *pScrollBarDraw)(HWND, HDC, INT, enum SCROLL_HITTEST, const struct SCROLL_TRACKING_INFO *, BOOL, BOOL, RECT *, INT, INT, INT, BOOL);