Zhiyi Zhang : comctl32/propsheet: Handle WM_ERASEBKGND in the property sheet page window procedure.
Alexandre Julliard
julliard at winehq.org
Tue Dec 7 15:58:44 CST 2021
Module: wine
Branch: master
Commit: 7c5a62b4c50cea12e71425bceaa88e08f58a4af6
URL: https://source.winehq.org/git/wine.git/?a=commit;h=7c5a62b4c50cea12e71425bceaa88e08f58a4af6
Author: Zhiyi Zhang <zzhang at codeweavers.com>
Date: Tue Dec 7 17:13:11 2021 +0800
comctl32/propsheet: Handle WM_ERASEBKGND in the property sheet page window procedure.
Handle WM_ERASEBKGND in the property sheet page window procedure and use a pattern brush created
from theme parts to fill background instead of calling DrawThemeBackground() directly.
Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/comctl32/propsheet.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++
dlls/uxtheme/dialog.c | 38 ----------------
2 files changed, 113 insertions(+), 38 deletions(-)
diff --git a/dlls/comctl32/propsheet.c b/dlls/comctl32/propsheet.c
index 4fe80241855..4c9b42e6ed7 100644
--- a/dlls/comctl32/propsheet.c
+++ b/dlls/comctl32/propsheet.c
@@ -63,6 +63,7 @@
#include "prsht.h"
#include "comctl32.h"
#include "uxtheme.h"
+#include "vsstyle.h"
#include "wine/debug.h"
@@ -140,6 +141,7 @@ typedef struct
*/
static const WCHAR PropSheetInfoStr[] = L"PropertySheetInfo";
+static const WCHAR PropSheetPageBackgroundBrush[] = L"PropSheetPageBackgroundBrush";
#define PSP_INTERNAL_UNICODE 0x80000000
@@ -1196,16 +1198,107 @@ PROPSHEET_WizardSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
+static HBRUSH get_propsheet_background_brush(HWND hwnd)
+{
+ HBITMAP bitmap, old_bitmap;
+ HDC hdc, hdc_screen;
+ HBRUSH brush;
+ HTHEME theme;
+ HRESULT hr;
+ RECT rect;
+ SIZE size;
+
+ brush = GetPropW(hwnd, PropSheetPageBackgroundBrush);
+ if (brush)
+ return brush;
+
+ 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, PropSheetPageBackgroundBrush, brush);
+ }
+
+ SelectObject(hdc, old_bitmap);
+ DeleteDC(hdc);
+ ReleaseDC(NULL, hdc_screen);
+ CloseThemeData(theme);
+ return brush;
+}
+
/* Subclassing window procedure for theming dialogs in property sheet pages */
static LRESULT CALLBACK PROPSHEET_ThemedSubclassProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
UINT_PTR id, DWORD_PTR ref)
{
+ POINT org, old_org;
+ LOGBRUSH logbrush;
WNDPROC dlgproc;
+ HBRUSH brush;
LRESULT lr;
+ RECT rect;
HDC hdc;
switch (msg)
{
+ case WM_THEMECHANGED:
+ {
+ brush = GetPropW(hwnd, PropSheetPageBackgroundBrush);
+ if (brush)
+ {
+ RemovePropW(hwnd, PropSheetPageBackgroundBrush);
+ if (GetObjectW(brush, sizeof(logbrush), &logbrush) == sizeof(logbrush))
+ DeleteObject((HBITMAP)logbrush.lbHatch);
+ DeleteObject(brush);
+ }
+ InvalidateRect(hwnd, NULL, TRUE);
+ break;
+ }
+ case WM_ERASEBKGND:
+ {
+ if (!IsThemeActive() || !IsThemeDialogTextureEnabled(hwnd))
+ break;
+
+ dlgproc = (WNDPROC)GetWindowLongPtrW(hwnd, DWLP_DLGPROC);
+ lr = CallWindowProcW(dlgproc, hwnd, msg, wp, lp);
+ if (lr)
+ return lr;
+
+ brush = get_propsheet_background_brush(hwnd);
+ 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 backgound 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:
{
if (!IsThemeActive() || !IsThemeDialogTextureEnabled(hwnd))
@@ -2385,6 +2478,8 @@ static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr);
HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
PropPageInfo* oldPages;
+ LOGBRUSH logbrush;
+ HBRUSH brush;
TRACE("index %d, hpage %p\n", index, hpage);
if (!psInfo) {
@@ -2445,6 +2540,14 @@ static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
else
{
RemoveWindowSubclass(psInfo->proppage[index].hwndPage, PROPSHEET_ThemedSubclassProc, 1);
+ brush = GetPropW(psInfo->proppage[index].hwndPage, PropSheetPageBackgroundBrush);
+ if (brush)
+ {
+ RemovePropW(psInfo->proppage[index].hwndPage, PropSheetPageBackgroundBrush);
+ if (GetObjectW(brush, sizeof(logbrush), &logbrush) == sizeof(logbrush))
+ DeleteObject((HBITMAP)logbrush.lbHatch);
+ DeleteObject(brush);
+ }
}
/* Destroy page dialog window */
@@ -2743,6 +2846,8 @@ static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE page, const PropSheetInfo* psIn
*/
static void PROPSHEET_CleanUp(HWND hwndDlg)
{
+ LOGBRUSH logbrush;
+ HBRUSH brush;
int i;
PropSheetInfo* psInfo = RemovePropW(hwndDlg, PropSheetInfoStr);
@@ -2766,6 +2871,14 @@ static void PROPSHEET_CleanUp(HWND hwndDlg)
else
{
RemoveWindowSubclass(psInfo->proppage[i].hwndPage, PROPSHEET_ThemedSubclassProc, 1);
+ brush = GetPropW(psInfo->proppage[i].hwndPage, PropSheetPageBackgroundBrush);
+ if (brush)
+ {
+ RemovePropW(psInfo->proppage[i].hwndPage, PropSheetPageBackgroundBrush);
+ if (GetObjectW(brush, sizeof(logbrush), &logbrush) == sizeof(logbrush))
+ DeleteObject((HBITMAP)logbrush.lbHatch);
+ DeleteObject(brush);
+ }
}
if(psInfo->proppage[i].hwndPage)
diff --git a/dlls/uxtheme/dialog.c b/dlls/uxtheme/dialog.c
index bbfdaba639b..776f54e1d31 100644
--- a/dlls/uxtheme/dialog.c
+++ b/dlls/uxtheme/dialog.c
@@ -36,9 +36,6 @@ LRESULT WINAPI UXTHEME_DefDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPa
{
HTHEME theme = GetWindowTheme ( hWnd );
static const WCHAR themeClass[] = L"Window";
- BOOL themingActive = IsThemeDialogTextureEnabled (hWnd);
- BOOL doTheming = themingActive && (theme != NULL);
- HRESULT hr = E_FAIL;
LRESULT result;
switch (msg)
@@ -54,41 +51,6 @@ LRESULT WINAPI UXTHEME_DefDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPa
OpenThemeData( hWnd, NULL );
return user_api.pDefDlgProc(hWnd, msg, wParam, lParam, unicode);
- case WM_THEMECHANGED:
- CloseThemeData ( theme );
- OpenThemeData( hWnd, themeClass );
- InvalidateRect( hWnd, NULL, TRUE );
- return 0;
-
- case WM_ERASEBKGND:
- if (!doTheming) return user_api.pDefDlgProc(hWnd, msg, wParam, lParam, unicode);
- {
- RECT rc;
- WNDPROC dlgp = (WNDPROC)GetWindowLongPtrW (hWnd, DWLP_DLGPROC);
- if (!CallWindowProcW(dlgp, hWnd, msg, wParam, lParam))
- {
- /* Draw background*/
- GetClientRect (hWnd, &rc);
- if (IsThemePartDefined (theme, WP_DIALOG, 0))
- /* Although there is a theme for the WINDOW class/DIALOG part,
- * but I[res] haven't seen Windows using it yet... Even when
- * dialog theming is activated, the good ol' BTNFACE
- * background seems to be used. */
-#if 0
- DrawThemeBackground (theme, (HDC)wParam, WP_DIALOG, 0, &rc,
- NULL);
-#endif
- return user_api.pDefDlgProc(hWnd, msg, wParam, lParam, unicode);
- /* We might have gotten a TAB theme class, so check if we can draw as a tab page */
- else if (IsThemePartDefined(theme, TABP_BODY, 0))
- hr = DrawThemeBackground(theme, (HDC)wParam, TABP_BODY, 0, &rc, NULL);
-
- if (FAILED(hr))
- return user_api.pDefDlgProc(hWnd, msg, wParam, lParam, unicode);
- }
- return 1;
- }
-
default:
/* Call old proc */
return user_api.pDefDlgProc(hWnd, msg, wParam, lParam, unicode);
More information about the wine-cvs
mailing list