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