dmime: Remove DECLSPEC_HIDDEN usage.
[wine.git] / dlls / uxtheme / dialog.c
bloba27382af784834cf3f6b8a39418ab3445ef11599
1 /*
2 * Dialog theming support
4 * Copyright 2022 Zhiyi Zhang for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "uxtheme.h"
28 #include "uxthemedll.h"
29 #include "vssym32.h"
31 extern ATOM atDialogThemeEnabled;
32 static const WCHAR wine_dialog_brush[] = L"wine_dialog_brush";
34 static HBRUSH get_dialog_background_brush(HWND hwnd, BOOL create)
36 HBITMAP bitmap, old_bitmap;
37 HDC hdc, hdc_screen;
38 HBRUSH brush;
39 HTHEME theme;
40 DWORD flag;
41 HRESULT hr;
42 RECT rect;
43 SIZE size;
45 if (!IsThemeActive())
46 return NULL;
48 flag = HandleToUlong(GetPropW(hwnd, (LPCWSTR)MAKEINTATOM(atDialogThemeEnabled)));
49 if (flag != ETDT_ENABLETAB && flag != ETDT_ENABLEAEROWIZARDTAB)
50 return NULL;
52 brush = GetPropW(hwnd, wine_dialog_brush);
53 if (brush)
54 return brush;
56 if (!create)
57 return NULL;
59 theme = OpenThemeData(NULL, L"Tab");
60 if (!theme)
61 return NULL;
63 hr = GetThemePartSize(theme, NULL, TABP_BODY, 0, NULL, TS_TRUE, &size);
64 if (FAILED(hr))
66 size.cx = 10;
67 size.cy = 600;
70 hdc_screen = GetDC(NULL);
71 hdc = CreateCompatibleDC(hdc_screen);
72 bitmap = CreateCompatibleBitmap(hdc_screen, size.cx, size.cy);
73 old_bitmap = SelectObject(hdc, bitmap);
75 SetRect(&rect, 0, 0, size.cx, size.cy);
76 /* FIXME: XP draws the tab body bitmap directly without transparency even if there is */
77 FillRect(hdc, &rect, GetSysColorBrush(COLOR_3DFACE));
78 hr = DrawThemeBackground(theme, hdc, TABP_BODY, 0, &rect, NULL);
79 if (SUCCEEDED(hr))
81 brush = CreatePatternBrush(bitmap);
82 SetPropW(hwnd, wine_dialog_brush, brush);
85 SelectObject(hdc, old_bitmap);
86 DeleteDC(hdc);
87 ReleaseDC(NULL, hdc_screen);
88 CloseThemeData(theme);
89 return brush;
92 static void destroy_dialog_brush(HWND hwnd)
94 LOGBRUSH logbrush;
95 HBRUSH brush;
97 brush = GetPropW(hwnd, wine_dialog_brush);
98 if (brush)
100 RemovePropW(hwnd, wine_dialog_brush);
101 if (GetObjectW(brush, sizeof(logbrush), &logbrush) == sizeof(logbrush))
102 DeleteObject((HBITMAP)logbrush.lbHatch);
103 DeleteObject(brush);
107 LRESULT WINAPI UXTHEME_DefDlgProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp, BOOL unicode)
109 POINT org, old_org;
110 WNDPROC dlgproc;
111 HBRUSH brush;
112 LRESULT lr;
113 RECT rect;
114 HDC hdc;
116 switch (msg)
118 case WM_NCDESTROY:
120 destroy_dialog_brush(hwnd);
121 break;
123 case WM_THEMECHANGED:
125 destroy_dialog_brush(hwnd);
126 InvalidateRect(hwnd, NULL, TRUE);
127 break;
129 case WM_ERASEBKGND:
131 dlgproc = (WNDPROC)GetWindowLongPtrW(hwnd, DWLP_DLGPROC);
132 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, 0);
133 lr = LOWORD(CallWindowProcW(dlgproc, hwnd, msg, wp, lp));
134 if (lr || !IsWindow(hwnd))
135 return GetWindowLongPtrW(hwnd, DWLP_MSGRESULT);
137 brush = get_dialog_background_brush(hwnd, TRUE);
138 if (!brush)
140 /* Copied from DEFDLG_Proc() */
141 brush = (HBRUSH)SendMessageW(hwnd, WM_CTLCOLORDLG, wp, (LPARAM)hwnd);
142 if (!brush)
143 brush = (HBRUSH)DefWindowProcW(hwnd, WM_CTLCOLORDLG, wp, (LPARAM)hwnd);
144 if (brush)
146 hdc = (HDC)wp;
147 GetClientRect(hwnd, &rect);
148 DPtoLP(hdc, (LPPOINT)&rect, 2);
149 FillRect(hdc, &rect, brush);
151 return TRUE;
154 /* Using FillRect() to draw background could introduce a tiling effect if the destination
155 * rectangle is larger than the pattern brush size, which is usually 10x600. This bug is
156 * visible on property sheet pages if system DPI is set to 192. However, the same bug also
157 * exists on XP and explains why vista+ don't use gradient tab body background anymore */
158 hdc = (HDC)wp;
159 GetViewportOrgEx(hdc, &org);
160 SetBrushOrgEx(hdc, org.x, org.y, &old_org);
161 GetClientRect(hwnd, &rect);
162 FillRect(hdc, &rect, brush);
163 SetBrushOrgEx(hdc, old_org.x, old_org.y, NULL);
164 return TRUE;
166 case WM_CTLCOLORMSGBOX:
167 case WM_CTLCOLORBTN:
168 case WM_CTLCOLORDLG:
169 case WM_CTLCOLORSTATIC:
171 dlgproc = (WNDPROC)GetWindowLongPtrW(hwnd, DWLP_DLGPROC);
172 lr = CallWindowProcW(dlgproc, hwnd, msg, wp, lp);
173 if (lr || !IsWindow(hwnd))
174 return lr;
176 brush = get_dialog_background_brush(hwnd, FALSE);
177 if (!brush)
178 return DefWindowProcW(hwnd, msg, wp, lp);
180 hdc = (HDC)wp;
181 SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
182 SetBkMode(hdc, TRANSPARENT);
184 org.x = 0;
185 org.y = 0;
186 MapWindowPoints((HWND)lp, hwnd, &org, 1);
187 SetBrushOrgEx(hdc, -org.x, -org.y, NULL);
188 return (LRESULT)brush;
192 return user_api.pDefDlgProc(hwnd, msg, wp, lp, unicode);