Merge the following revisions from kernel-fun branch:
[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
11 USERAPIHOOK user32ApiHook;
12 BYTE gabDWPmessages[UAHOWP_MAX_SIZE];
13 BYTE gabMSGPmessages[UAHOWP_MAX_SIZE];
14 BOOL gbThemeHooksActive = FALSE;
15
16 PWND_CONTEXT ThemeGetWndContext(HWND hWnd)
17 {
18 PWND_CONTEXT pcontext;
19
20 pcontext = (PWND_CONTEXT)GetPropW(hWnd, (LPCWSTR)MAKEINTATOM(atWndContext));
21 if(pcontext == NULL)
22 {
23 pcontext = HeapAlloc(GetProcessHeap(),
24 HEAP_ZERO_MEMORY,
25 sizeof(WND_CONTEXT));
26 if(pcontext == NULL)
27 {
28 return NULL;
29 }
30
31 SetPropW( hWnd, (LPCWSTR)MAKEINTATOM(atWndContext), pcontext);
32 }
33
34 return pcontext;
35 }
36
37 void ThemeDestroyWndContext(HWND hWnd)
38 {
39 PWND_CONTEXT pContext;
40 DWORD ProcessId;
41
42 /*Do not destroy WND_CONTEXT of a window that belong to another process */
43 GetWindowThreadProcessId(hWnd, &ProcessId);
44 if(ProcessId != GetCurrentProcessId())
45 {
46 return;
47 }
48
49 pContext = (PWND_CONTEXT)GetPropW(hWnd, (LPCWSTR)MAKEINTATOM(atWndContext));
50 if(pContext == NULL)
51 {
52 return;
53 }
54
55 if(pContext->HasThemeRgn)
56 {
57 user32ApiHook.SetWindowRgn(hWnd, 0, TRUE);
58 }
59
60 HeapFree(GetProcessHeap(), 0, pContext);
61
62 SetPropW( hWnd, (LPCWSTR)MAKEINTATOM(atWndContext), NULL);
63 }
64
65 static BOOL CALLBACK ThemeCleanupChildWndContext (HWND hWnd, LPARAM msg)
66 {
67 ThemeDestroyWndContext(hWnd);
68 return TRUE;
69 }
70
71 static BOOL CALLBACK ThemeCleanupWndContext(HWND hWnd, LPARAM msg)
72 {
73 if (hWnd == NULL)
74 {
75 EnumWindows (ThemeCleanupWndContext, 0);
76 }
77 else
78 {
79 ThemeDestroyWndContext(hWnd);
80 EnumChildWindows (hWnd, ThemeCleanupChildWndContext, 0);
81 }
82
83 return TRUE;
84 }
85
86 void SetThemeRegion(HWND hWnd)
87 {
88 HTHEME hTheme;
89 RECT rcWindow;
90 HRGN hrgn, hrgn1;
91 int CaptionHeight, iPart;
92 WINDOWINFO wi;
93
94 TRACE("SetThemeRegion %d\n", hWnd);
95
96 wi.cbSize = sizeof(wi);
97 GetWindowInfo(hWnd, &wi);
98
99 /* Get the caption part id */
100 if (wi.dwExStyle & WS_EX_TOOLWINDOW)
101 iPart = WP_SMALLCAPTION;
102 else if (wi.dwStyle & WS_MAXIMIZE)
103 iPart = WP_MAXCAPTION;
104 else
105 iPart = WP_CAPTION;
106
107 CaptionHeight = wi.cyWindowBorders;
108 CaptionHeight += GetSystemMetrics(wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMCAPTION : SM_CYCAPTION );
109
110 GetWindowRect(hWnd, &rcWindow);
111 rcWindow.right -= rcWindow.left;
112 rcWindow.bottom = CaptionHeight;
113 rcWindow.top = 0;
114 rcWindow.left = 0;
115
116 hTheme = MSSTYLES_OpenThemeClass(ActiveThemeFile, NULL, L"WINDOW");
117 GetThemeBackgroundRegion(hTheme, 0, iPart, FS_ACTIVE, &rcWindow, &hrgn);
118 CloseThemeData(hTheme);
119
120 GetWindowRect(hWnd, &rcWindow);
121 rcWindow.right -= rcWindow.left;
122 rcWindow.bottom -= rcWindow.top;
123 rcWindow.top = CaptionHeight;
124 rcWindow.left = 0;
125 hrgn1 = CreateRectRgnIndirect(&rcWindow);
126
127 CombineRgn(hrgn, hrgn, hrgn1, RGN_OR );
128
129 DeleteObject(hrgn1);
130
131 user32ApiHook.SetWindowRgn(hWnd, hrgn, TRUE);
132 }
133
134 int OnPostWinPosChanged(HWND hWnd, WINDOWPOS* pWinPos)
135 {
136 PWND_CONTEXT pcontext;
137 DWORD style;
138
139 /* We only proceed to change the window shape if it has a caption */
140 style = GetWindowLongW(hWnd, GWL_STYLE);
141 if((style & WS_CAPTION)!=WS_CAPTION)
142 return 0;
143
144 /* Get theme data for this window */
145 pcontext = ThemeGetWndContext(hWnd);
146 if (pcontext == NULL)
147 return 0;
148
149 /* Do not change the region of the window if its size wasn't changed */
150 if ((pWinPos->flags & SWP_NOSIZE) != 0 && pcontext->DirtyThemeRegion == FALSE)
151 return 0;
152
153 /* We don't touch the shape of the window if the application sets it on its own */
154 if (pcontext->HasAppDefinedRgn == TRUE)
155 return 0;
156
157 /* Calling SetWindowRgn will call SetWindowPos again so we need to avoid this recursion */
158 if (pcontext->UpdatingRgn == TRUE)
159 return 0;
160
161 if(!IsAppThemed())
162 {
163 if(pcontext->HasThemeRgn)
164 {
165 pcontext->HasThemeRgn = FALSE;
166 user32ApiHook.SetWindowRgn(hWnd, 0, TRUE);
167 }
168 return 0;
169 }
170
171 pcontext->DirtyThemeRegion = FALSE;
172 pcontext->HasThemeRgn = TRUE;
173 pcontext->UpdatingRgn = TRUE;
174 SetThemeRegion(hWnd);
175 pcontext->UpdatingRgn = FALSE;
176
177 return 0;
178 }
179
180 /**********************************************************************
181 * Hook Functions
182 */
183
184 static LRESULT CALLBACK
185 ThemeDefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
186 {
187 if(!IsAppThemed())
188 {
189 if (Msg == WM_NCUAHDRAWCAPTION)
190 {
191 user32ApiHook.DrawCaption(hWnd, NULL, NULL, 0);
192 return 0;
193 }
194
195 return user32ApiHook.DefWindowProcW(hWnd,
196 Msg,
197 wParam,
198 lParam);
199 }
200
201 return ThemeWndProc(hWnd,
202 Msg,
203 wParam,
204 lParam,
205 user32ApiHook.DefWindowProcW);
206 }
207
208 static LRESULT CALLBACK
209 ThemeDefWindowProcA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
210 {
211 if(!IsAppThemed())
212 {
213 if (Msg == WM_NCUAHDRAWCAPTION)
214 {
215 user32ApiHook.DrawCaption(hWnd, NULL, NULL, 0);
216 return 0;
217 }
218
219 return user32ApiHook.DefWindowProcA(hWnd,
220 Msg,
221 wParam,
222 lParam);
223 }
224
225 return ThemeWndProc(hWnd,
226 Msg,
227 wParam,
228 lParam,
229 user32ApiHook.DefWindowProcA);
230 }
231
232 static LRESULT CALLBACK
233 ThemePreWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ret,PDWORD unknown)
234 {
235 switch(Msg)
236 {
237 case WM_THEMECHANGED:
238 if (GetAncestor(hWnd, GA_PARENT) == GetDesktopWindow())
239 UXTHEME_LoadTheme(TRUE);
240 case WM_NCCREATE:
241 {
242 PWND_CONTEXT pcontext = ThemeGetWndContext(hWnd);
243 if (pcontext == NULL)
244 return 0;
245 pcontext->DirtyThemeRegion = TRUE;
246 }
247 }
248
249 return 0;
250 }
251
252
253 static LRESULT CALLBACK
254 ThemePostWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ret,PDWORD unknown)
255 {
256 switch(Msg)
257 {
258 case WM_WINDOWPOSCHANGED:
259 {
260 return OnPostWinPosChanged(hWnd, (WINDOWPOS*)lParam);
261 }
262 case WM_DESTROY:
263 {
264 ThemeDestroyWndContext(hWnd);
265 return 0;
266 }
267 }
268
269 return 0;
270 }
271
272 int WINAPI ThemeSetWindowRgn(HWND hWnd, HRGN hRgn, BOOL bRedraw)
273 {
274 PWND_CONTEXT pcontext = ThemeGetWndContext(hWnd);
275 if(pcontext)
276 {
277 pcontext->HasAppDefinedRgn = TRUE;
278 pcontext->HasThemeRgn = FALSE;
279 }
280
281 return user32ApiHook.SetWindowRgn(hWnd, hRgn, bRedraw);
282 }
283
284 /**********************************************************************
285 * Exports
286 */
287
288 BOOL CALLBACK
289 ThemeInitApiHook(UAPIHK State, PUSERAPIHOOK puah)
290 {
291 if (!puah || State != uahLoadInit)
292 {
293 UXTHEME_LoadTheme(FALSE);
294 ThemeCleanupWndContext(NULL, 0);
295 gbThemeHooksActive = FALSE;
296 return TRUE;
297 }
298
299 gbThemeHooksActive = TRUE;
300
301 /* Store the original functions from user32 */
302 user32ApiHook = *puah;
303
304 puah->DefWindowProcA = ThemeDefWindowProcA;
305 puah->DefWindowProcW = ThemeDefWindowProcW;
306 puah->PreWndProc = ThemePreWindowProc;
307 puah->PostWndProc = ThemePostWindowProc;
308 puah->PreDefDlgProc = ThemePreWindowProc;
309 puah->PostDefDlgProc = ThemePostWindowProc;
310 puah->DefWndProcArray.MsgBitArray = gabDWPmessages;
311 puah->DefWndProcArray.Size = UAHOWP_MAX_SIZE;
312 puah->WndProcArray.MsgBitArray = gabMSGPmessages;
313 puah->WndProcArray.Size = UAHOWP_MAX_SIZE;
314 puah->DlgProcArray.MsgBitArray = gabMSGPmessages;
315 puah->DlgProcArray.Size = UAHOWP_MAX_SIZE;
316
317 puah->SetWindowRgn = ThemeSetWindowRgn;
318
319 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCPAINT);
320 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCACTIVATE);
321 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCMOUSEMOVE);
322 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCMOUSELEAVE);
323 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCHITTEST);
324 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCLBUTTONDOWN);
325 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCUAHDRAWCAPTION);
326 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCUAHDRAWFRAME);
327 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SETTEXT);
328 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_WINDOWPOSCHANGED);
329 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CONTEXTMENU);
330 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_STYLECHANGED);
331 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SETICON);
332 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCDESTROY);
333 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SYSCOMMAND);
334 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORMSGBOX);
335 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORBTN);
336 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORSTATIC);
337
338 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_CREATE);
339 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_SETTINGCHANGE);
340 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_DRAWITEM);
341 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MEASUREITEM);
342 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_WINDOWPOSCHANGING);
343 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_WINDOWPOSCHANGED);
344 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_STYLECHANGING);
345 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_STYLECHANGED);
346 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCCREATE);
347 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCDESTROY);
348 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCPAINT);
349 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MENUCHAR);
350 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MDISETMENU);
351 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_THEMECHANGED);
352 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_UAHINIT);
353
354 UXTHEME_LoadTheme(TRUE);
355
356 return TRUE;
357 }
358
359 typedef BOOL (WINAPI * PREGISTER_UAH_WINXP)(HINSTANCE hInstance, USERAPIHOOKPROC CallbackFunc);
360 typedef BOOL (WINAPI * PREGISTER_UUAH_WIN2003)(PUSERAPIHOOKINFO puah);
361
362 BOOL WINAPI
363 ThemeHooksInstall()
364 {
365 PVOID lpFunc;
366 OSVERSIONINFO osvi;
367 BOOL ret;
368
369 lpFunc = GetProcAddress(GetModuleHandle("user32.dll"), "RegisterUserApiHook");
370
371 ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
372 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
373 GetVersionEx(&osvi);
374
375 if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
376 {
377 PREGISTER_UAH_WINXP lpfuncxp = (PREGISTER_UAH_WINXP)lpFunc;
378 ret = lpfuncxp(hDllInst, ThemeInitApiHook);
379 }
380 else if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
381 {
382 PREGISTER_UUAH_WIN2003 lpfunc2003 = (PREGISTER_UUAH_WIN2003)lpFunc;
383 USERAPIHOOKINFO uah;
384
385 uah.m_size = sizeof(uah);
386 uah.m_dllname1 = L"uxtheme.dll";
387 uah.m_funname1 = L"ThemeInitApiHook";
388 uah.m_dllname2 = NULL;
389 uah.m_funname2 = NULL;
390
391 ret = lpfunc2003(&uah);
392 }
393 else
394 {
395 UNIMPLEMENTED;
396 ret = FALSE;
397 }
398
399 UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED);
400
401 return ret;
402 }
403
404 BOOL WINAPI
405 ThemeHooksRemove()
406 {
407 BOOL ret;
408
409 ret = UnregisterUserApiHook();
410
411 UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED);
412
413 return ret;
414 }
415
416 INT WINAPI ClassicSystemParametersInfoW(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni)
417 {
418 if (gbThemeHooksActive)
419 {
420 return user32ApiHook.SystemParametersInfoW(uiAction, uiParam, pvParam, fWinIni);
421 }
422
423 return SystemParametersInfoW(uiAction, uiParam, pvParam, fWinIni);
424 }
425
426 INT WINAPI ClassicSystemParametersInfoA(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni)
427 {
428 if (gbThemeHooksActive)
429 {
430 return user32ApiHook.SystemParametersInfoA(uiAction, uiParam, pvParam, fWinIni);
431 }
432
433 return SystemParametersInfoA(uiAction, uiParam, pvParam, fWinIni);
434 }
435
436 INT WINAPI ClassicGetSystemMetrics(int nIndex)
437 {
438 if (gbThemeHooksActive)
439 {
440 return user32ApiHook.GetSystemMetrics(nIndex);
441 }
442
443 return GetSystemMetrics(nIndex);
444 }
445
446 BOOL WINAPI ClassicAdjustWindowRectEx(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle)
447 {
448 if (gbThemeHooksActive)
449 {
450 return user32ApiHook.AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
451 }
452
453 return AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
454 }