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@codeweavers.com --- 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);