[uxtheme]
[reactos.git] / reactos / dll / win32 / uxtheme / themehooks.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS uxtheme.dll
4 * FILE: dll/win32/uxtheme/themehooks.c
5 * PURPOSE: uxtheme user api hook functions
6 * PROGRAMMER: Giannis Adamopoulos
7 */
8
9 #include "uxthemep.h"
10 #include <wine/debug.h>
11
12 WINE_DEFAULT_DEBUG_CHANNEL(uxtheme);
13
14 USERAPIHOOK user32ApiHook;
15 BYTE gabDWPmessages[UAHOWP_MAX_SIZE];
16 BYTE gabMSGPmessages[UAHOWP_MAX_SIZE];
17 BOOL gbThemeHooksActive = FALSE;
18
19 PWND_CONTEXT ThemeGetWndContext(HWND hWnd)
20 {
21 PWND_CONTEXT pcontext;
22
23 pcontext = (PWND_CONTEXT)GetPropW(hWnd, (LPCWSTR)MAKEINTATOM(atWndContrext));
24 if(pcontext == NULL)
25 {
26 pcontext = HeapAlloc(GetProcessHeap(),
27 HEAP_ZERO_MEMORY,
28 sizeof(WND_CONTEXT));
29 if(pcontext == NULL)
30 {
31 return NULL;
32 }
33
34 SetPropW( hWnd, (LPCWSTR)MAKEINTATOM(atWndContrext), pcontext);
35 }
36
37 return pcontext;
38 }
39
40 void ThemeDetroyWndContext(HWND hWnd)
41 {
42 PWND_CONTEXT pContext;
43 DWORD ProcessId;
44
45 /*Do not destroy WND_CONTEXT of a window that belong to another process */
46 GetWindowThreadProcessId(hWnd, &ProcessId);
47 if(ProcessId != GetCurrentProcessId())
48 {
49 return;
50 }
51
52 pContext = (PWND_CONTEXT)GetPropW(hWnd, (LPCWSTR)MAKEINTATOM(atWndContrext));
53 if(pContext == NULL)
54 {
55 return;
56 }
57
58 if(pContext->HasThemeRgn)
59 {
60 user32ApiHook.SetWindowRgn(hWnd, 0, TRUE);
61 }
62
63 HeapFree(GetProcessHeap(), 0, pContext);
64
65 SetPropW( hWnd, (LPCWSTR)MAKEINTATOM(atWndContrext), NULL);
66 }
67
68 static BOOL CALLBACK ThemeCleanupChildWndContext (HWND hWnd, LPARAM msg)
69 {
70 ThemeDetroyWndContext(hWnd);
71 return TRUE;
72 }
73
74 static BOOL CALLBACK ThemeCleanupWndContext(HWND hWnd, LPARAM msg)
75 {
76 if (hWnd == NULL)
77 {
78 EnumWindows (ThemeCleanupWndContext, 0);
79 }
80 else
81 {
82 ThemeDetroyWndContext(hWnd);
83 EnumChildWindows (hWnd, ThemeCleanupChildWndContext, 0);
84 }
85
86 return TRUE;
87 }
88
89 void SetThemeRegion(HWND hWnd, PWND_CONTEXT pcontext)
90 {
91 HTHEME hTheme;
92 RECT rcWindow;
93 HRGN hrgn, hrgn1;
94 int CaptionHeight, iPart;
95 WINDOWINFO wi;
96
97 if(!IsAppThemed())
98 {
99 if(pcontext->HasThemeRgn)
100 {
101 pcontext->HasThemeRgn = FALSE;
102 user32ApiHook.SetWindowRgn(hWnd, 0, TRUE);
103 }
104 return;
105 }
106
107 wi.cbSize = sizeof(wi);
108
109 GetWindowInfo(hWnd, &wi);
110
111 if((wi.dwStyle & WS_CAPTION)!=WS_CAPTION)
112 {
113 return;
114 }
115
116 /* Get the caption part id */
117 if (wi.dwExStyle & WS_EX_TOOLWINDOW)
118 iPart = WP_SMALLCAPTION;
119 else if (wi.dwStyle & WS_MAXIMIZE)
120 iPart = WP_MAXCAPTION;
121 else
122 iPart = WP_CAPTION;
123
124 pcontext->HasThemeRgn = TRUE;
125
126 CaptionHeight = wi.cyWindowBorders;
127 CaptionHeight += GetSystemMetrics(wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMCAPTION : SM_CYCAPTION );
128
129 GetWindowRect(hWnd, &rcWindow);
130 rcWindow.right -= rcWindow.left;
131 rcWindow.bottom = CaptionHeight;
132 rcWindow.top = 0;
133 rcWindow.left = 0;
134
135 hTheme = OpenThemeData (hWnd, L"WINDOW");
136
137 GetThemeBackgroundRegion(hTheme, 0, iPart, FS_ACTIVE, &rcWindow, &hrgn);
138
139 CloseThemeData(hTheme);
140
141 GetWindowRect(hWnd, &rcWindow);
142 rcWindow.right -= rcWindow.left;
143 rcWindow.bottom -= rcWindow.top;
144 rcWindow.top = CaptionHeight;
145 rcWindow.left = 0;
146 hrgn1 = CreateRectRgnIndirect(&rcWindow);
147
148 CombineRgn(hrgn, hrgn, hrgn1, RGN_OR );
149
150 DeleteObject(hrgn1);
151
152 user32ApiHook.SetWindowRgn(hWnd, hrgn, TRUE);
153 }
154
155 int OnPostWinPosChanged(HWND hWnd)
156 {
157 PWND_CONTEXT pcontext = ThemeGetWndContext(hWnd);
158
159 if(pcontext &&
160 pcontext->HasAppDefinedRgn == FALSE &&
161 pcontext->UpdatingRgn == FALSE)
162 {
163 pcontext->UpdatingRgn = TRUE;
164 SetThemeRegion(hWnd, pcontext);
165 pcontext = ThemeGetWndContext(hWnd);
166 pcontext->UpdatingRgn = FALSE;
167 }
168 return 0;
169 }
170
171 /**********************************************************************
172 * Hook Functions
173 */
174
175 static LRESULT CALLBACK
176 ThemeDefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
177 {
178 if(!IsThemeActive())
179 {
180 return user32ApiHook.DefWindowProcW(hWnd,
181 Msg,
182 wParam,
183 lParam);
184 }
185
186 return ThemeWndProc(hWnd,
187 Msg,
188 wParam,
189 lParam,
190 user32ApiHook.DefWindowProcW);
191 }
192
193 static LRESULT CALLBACK
194 ThemeDefWindowProcA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
195 {
196 if(!IsThemeActive())
197 {
198 return user32ApiHook.DefWindowProcA(hWnd,
199 Msg,
200 wParam,
201 lParam);
202 }
203
204 return ThemeWndProc(hWnd,
205 Msg,
206 wParam,
207 lParam,
208 user32ApiHook.DefWindowProcA);
209 }
210
211 static LRESULT CALLBACK
212 ThemePreWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ret,PDWORD unknown)
213 {
214 switch(Msg)
215 {
216 case WM_THEMECHANGED:
217 UXTHEME_LoadTheme(TRUE);
218 return 0;
219 }
220
221 return 0;
222 }
223
224
225 static LRESULT CALLBACK
226 ThemePostWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ret,PDWORD unknown)
227 {
228 switch(Msg)
229 {
230 case WM_WINDOWPOSCHANGED:
231 {
232 return OnPostWinPosChanged(hWnd);
233 }
234 case WM_DESTROY:
235 {
236 ThemeDetroyWndContext(hWnd);
237 return 0;
238 }
239 }
240
241 return 0;
242 }
243
244 int WINAPI ThemeSetWindowRgn(HWND hWnd, HRGN hRgn, BOOL bRedraw)
245 {
246 PWND_CONTEXT pcontext = ThemeGetWndContext(hWnd);
247 if(pcontext)
248 {
249 pcontext->HasAppDefinedRgn = TRUE;
250 pcontext->HasThemeRgn = FALSE;
251 }
252
253 return user32ApiHook.SetWindowRgn(hWnd, hRgn, bRedraw);
254 }
255
256 /**********************************************************************
257 * Exports
258 */
259
260 BOOL CALLBACK
261 ThemeInitApiHook(UAPIHK State, PUSERAPIHOOK puah)
262 {
263 if (!puah || State != uahLoadInit)
264 {
265 UXTHEME_LoadTheme(FALSE);
266 ThemeCleanupWndContext(NULL, 0);
267 gbThemeHooksActive = FALSE;
268 return TRUE;
269 }
270
271 gbThemeHooksActive = TRUE;
272
273 /* Store the original functions from user32 */
274 user32ApiHook = *puah;
275
276 puah->DefWindowProcA = ThemeDefWindowProcA;
277 puah->DefWindowProcW = ThemeDefWindowProcW;
278 puah->PreWndProc = ThemePreWindowProc;
279 puah->PostWndProc = ThemePostWindowProc;
280 puah->PreDefDlgProc = ThemePreWindowProc;
281 puah->PostDefDlgProc = ThemePostWindowProc;
282 puah->DefWndProcArray.MsgBitArray = gabDWPmessages;
283 puah->DefWndProcArray.Size = UAHOWP_MAX_SIZE;
284 puah->WndProcArray.MsgBitArray = gabMSGPmessages;
285 puah->WndProcArray.Size = UAHOWP_MAX_SIZE;
286 puah->DlgProcArray.MsgBitArray = gabMSGPmessages;
287 puah->DlgProcArray.Size = UAHOWP_MAX_SIZE;
288
289 puah->SetWindowRgn = ThemeSetWindowRgn;
290
291 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCPAINT);
292 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCACTIVATE);
293 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCMOUSEMOVE);
294 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCMOUSELEAVE);
295 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCHITTEST);
296 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCLBUTTONDOWN);
297 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCUAHDRAWCAPTION);
298 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCUAHDRAWFRAME);
299 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SETTEXT);
300 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_WINDOWPOSCHANGED);
301 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CONTEXTMENU);
302 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_STYLECHANGED);
303 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SETICON);
304 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCDESTROY);
305 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SYSCOMMAND);
306 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORMSGBOX);
307 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORBTN);
308 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORSTATIC);
309
310 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_CREATE);
311 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_SETTINGCHANGE);
312 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_DRAWITEM);
313 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MEASUREITEM);
314 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_WINDOWPOSCHANGING);
315 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_WINDOWPOSCHANGED);
316 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_STYLECHANGING);
317 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_STYLECHANGED);
318 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCCREATE);
319 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCDESTROY);
320 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCPAINT);
321 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MENUCHAR);
322 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MDISETMENU);
323 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_THEMECHANGED);
324 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_UAHINIT);
325
326 UXTHEME_LoadTheme(TRUE);
327
328 return TRUE;
329 }
330
331 typedef BOOL (WINAPI * PREGISTER_UAH_WINXP)(HINSTANCE hInstance, USERAPIHOOKPROC CallbackFunc);
332 typedef BOOL (WINAPI * PREGISTER_UUAH_WIN2003)(PUSERAPIHOOKINFO puah);
333
334 BOOL WINAPI
335 ThemeHooksInstall()
336 {
337 PVOID lpFunc;
338 OSVERSIONINFO osvi;
339 BOOL ret;
340
341 lpFunc = GetProcAddress(GetModuleHandle("user32.dll"), "RegisterUserApiHook");
342
343 ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
344 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
345 GetVersionEx(&osvi);
346
347 if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
348 {
349 PREGISTER_UAH_WINXP lpfuncxp = (PREGISTER_UAH_WINXP)lpFunc;
350 ret = lpfuncxp(hDllInst, ThemeInitApiHook);
351 }
352 else if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
353 {
354 PREGISTER_UUAH_WIN2003 lpfunc2003 = (PREGISTER_UUAH_WIN2003)lpFunc;
355 USERAPIHOOKINFO uah;
356
357 uah.m_size = sizeof(uah);
358 uah.m_dllname1 = L"uxtheme.dll";
359 uah.m_funname1 = L"ThemeInitApiHook";
360 uah.m_dllname2 = NULL;
361 uah.m_funname2 = NULL;
362
363 ret = lpfunc2003(&uah);
364 }
365 else
366 {
367 UNIMPLEMENTED;
368 ret = FALSE;
369 }
370
371 UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED);
372
373 return ret;
374 }
375
376 BOOL WINAPI
377 ThemeHooksRemove()
378 {
379 BOOL ret;
380
381 ret = UnregisterUserApiHook();
382
383 UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED);
384
385 return ret;
386 }