ab10bf51c461584757a4f2eace7bced8bfc300de
[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 return user32ApiHook.DefWindowProcW(hWnd,
190 Msg,
191 wParam,
192 lParam);
193 }
194
195 return ThemeWndProc(hWnd,
196 Msg,
197 wParam,
198 lParam,
199 user32ApiHook.DefWindowProcW);
200 }
201
202 static LRESULT CALLBACK
203 ThemeDefWindowProcA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
204 {
205 if(!IsAppThemed())
206 {
207 return user32ApiHook.DefWindowProcA(hWnd,
208 Msg,
209 wParam,
210 lParam);
211 }
212
213 return ThemeWndProc(hWnd,
214 Msg,
215 wParam,
216 lParam,
217 user32ApiHook.DefWindowProcA);
218 }
219
220 static LRESULT CALLBACK
221 ThemePreWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ret,PDWORD unknown)
222 {
223 switch(Msg)
224 {
225 case WM_THEMECHANGED:
226 if (GetAncestor(hWnd, GA_PARENT) == GetDesktopWindow())
227 UXTHEME_LoadTheme(TRUE);
228 case WM_NCCREATE:
229 {
230 PWND_CONTEXT pcontext = ThemeGetWndContext(hWnd);
231 if (pcontext == NULL)
232 return 0;
233 pcontext->DirtyThemeRegion = TRUE;
234 }
235 }
236
237 return 0;
238 }
239
240
241 static LRESULT CALLBACK
242 ThemePostWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ret,PDWORD unknown)
243 {
244 switch(Msg)
245 {
246 case WM_WINDOWPOSCHANGED:
247 {
248 return OnPostWinPosChanged(hWnd, (WINDOWPOS*)lParam);
249 }
250 case WM_DESTROY:
251 {
252 ThemeDestroyWndContext(hWnd);
253 return 0;
254 }
255 }
256
257 return 0;
258 }
259
260 int WINAPI ThemeSetWindowRgn(HWND hWnd, HRGN hRgn, BOOL bRedraw)
261 {
262 PWND_CONTEXT pcontext = ThemeGetWndContext(hWnd);
263 if(pcontext)
264 {
265 pcontext->HasAppDefinedRgn = TRUE;
266 pcontext->HasThemeRgn = FALSE;
267 }
268
269 return user32ApiHook.SetWindowRgn(hWnd, hRgn, bRedraw);
270 }
271
272 BOOL WINAPI ThemeGetScrollInfo(HWND hwnd, int fnBar, LPSCROLLINFO lpsi)
273 {
274 PWND_CONTEXT pwndContext;
275 DWORD style;
276 BOOL ret;
277
278 /* Avoid creating a window context if it is not needed */
279 if(!IsAppThemed())
280 goto dodefault;
281
282 style = GetWindowLongW(hwnd, GWL_STYLE);
283 if((style & (WS_HSCROLL|WS_VSCROLL))==0)
284 goto dodefault;
285
286 pwndContext = ThemeGetWndContext(hwnd);
287 if (pwndContext == NULL)
288 goto dodefault;
289
290 /*
291 * Uxtheme needs to handle the tracking of the scrollbar itself
292 * This means than if an application needs to get the track position
293 * with GetScrollInfo, it will get wrong data. So uxtheme needs to
294 * hook it and set the correct tracking position itself
295 */
296 ret = user32ApiHook.GetScrollInfo(hwnd, fnBar, lpsi);
297 if ( lpsi &&
298 (lpsi->fMask & SIF_TRACKPOS) &&
299 pwndContext->SCROLL_TrackingWin == hwnd &&
300 pwndContext->SCROLL_TrackingBar == fnBar)
301 {
302 lpsi->nTrackPos = pwndContext->SCROLL_TrackingVal;
303 }
304 return ret;
305
306 dodefault:
307 return user32ApiHook.GetScrollInfo(hwnd, fnBar, lpsi);
308 }
309
310 /**********************************************************************
311 * Exports
312 */
313
314 BOOL CALLBACK
315 ThemeInitApiHook(UAPIHK State, PUSERAPIHOOK puah)
316 {
317 if (!puah || State != uahLoadInit)
318 {
319 UXTHEME_LoadTheme(FALSE);
320 ThemeCleanupWndContext(NULL, 0);
321 gbThemeHooksActive = FALSE;
322 return TRUE;
323 }
324
325 gbThemeHooksActive = TRUE;
326
327 /* Store the original functions from user32 */
328 user32ApiHook = *puah;
329
330 puah->DefWindowProcA = ThemeDefWindowProcA;
331 puah->DefWindowProcW = ThemeDefWindowProcW;
332 puah->PreWndProc = ThemePreWindowProc;
333 puah->PostWndProc = ThemePostWindowProc;
334 puah->PreDefDlgProc = ThemePreWindowProc;
335 puah->PostDefDlgProc = ThemePostWindowProc;
336 puah->DefWndProcArray.MsgBitArray = gabDWPmessages;
337 puah->DefWndProcArray.Size = UAHOWP_MAX_SIZE;
338 puah->WndProcArray.MsgBitArray = gabMSGPmessages;
339 puah->WndProcArray.Size = UAHOWP_MAX_SIZE;
340 puah->DlgProcArray.MsgBitArray = gabMSGPmessages;
341 puah->DlgProcArray.Size = UAHOWP_MAX_SIZE;
342
343 puah->SetWindowRgn = ThemeSetWindowRgn;
344 puah->GetScrollInfo = ThemeGetScrollInfo;
345
346 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCPAINT);
347 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCACTIVATE);
348 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCMOUSEMOVE);
349 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCMOUSELEAVE);
350 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCHITTEST);
351 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCLBUTTONDOWN);
352 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCUAHDRAWCAPTION);
353 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCUAHDRAWFRAME);
354 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SETTEXT);
355 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_WINDOWPOSCHANGED);
356 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CONTEXTMENU);
357 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_STYLECHANGED);
358 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SETICON);
359 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCDESTROY);
360 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SYSCOMMAND);
361 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORMSGBOX);
362 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORBTN);
363 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORSTATIC);
364
365 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_CREATE);
366 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_SETTINGCHANGE);
367 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_DRAWITEM);
368 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MEASUREITEM);
369 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_WINDOWPOSCHANGING);
370 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_WINDOWPOSCHANGED);
371 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_STYLECHANGING);
372 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_STYLECHANGED);
373 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCCREATE);
374 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCDESTROY);
375 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCPAINT);
376 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MENUCHAR);
377 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MDISETMENU);
378 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_THEMECHANGED);
379 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_UAHINIT);
380
381 UXTHEME_LoadTheme(TRUE);
382
383 return TRUE;
384 }
385
386 typedef BOOL (WINAPI * PREGISTER_UAH_WINXP)(HINSTANCE hInstance, USERAPIHOOKPROC CallbackFunc);
387 typedef BOOL (WINAPI * PREGISTER_UUAH_WIN2003)(PUSERAPIHOOKINFO puah);
388
389 BOOL WINAPI
390 ThemeHooksInstall()
391 {
392 PVOID lpFunc;
393 OSVERSIONINFO osvi;
394 BOOL ret;
395
396 lpFunc = GetProcAddress(GetModuleHandle("user32.dll"), "RegisterUserApiHook");
397
398 ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
399 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
400 GetVersionEx(&osvi);
401
402 if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
403 {
404 PREGISTER_UAH_WINXP lpfuncxp = (PREGISTER_UAH_WINXP)lpFunc;
405 ret = lpfuncxp(hDllInst, ThemeInitApiHook);
406 }
407 else if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
408 {
409 PREGISTER_UUAH_WIN2003 lpfunc2003 = (PREGISTER_UUAH_WIN2003)lpFunc;
410 USERAPIHOOKINFO uah;
411
412 uah.m_size = sizeof(uah);
413 uah.m_dllname1 = L"uxtheme.dll";
414 uah.m_funname1 = L"ThemeInitApiHook";
415 uah.m_dllname2 = NULL;
416 uah.m_funname2 = NULL;
417
418 ret = lpfunc2003(&uah);
419 }
420 else
421 {
422 UNIMPLEMENTED;
423 ret = FALSE;
424 }
425
426 UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED);
427
428 return ret;
429 }
430
431 BOOL WINAPI
432 ThemeHooksRemove()
433 {
434 BOOL ret;
435
436 ret = UnregisterUserApiHook();
437
438 UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED);
439
440 return ret;
441 }
442
443 INT WINAPI ClassicSystemParametersInfoW(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni)
444 {
445 if (gbThemeHooksActive)
446 {
447 return user32ApiHook.SystemParametersInfoW(uiAction, uiParam, pvParam, fWinIni);
448 }
449
450 return SystemParametersInfoW(uiAction, uiParam, pvParam, fWinIni);
451 }
452
453 INT WINAPI ClassicSystemParametersInfoA(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni)
454 {
455 if (gbThemeHooksActive)
456 {
457 return user32ApiHook.SystemParametersInfoA(uiAction, uiParam, pvParam, fWinIni);
458 }
459
460 return SystemParametersInfoA(uiAction, uiParam, pvParam, fWinIni);
461 }
462
463 INT WINAPI ClassicGetSystemMetrics(int nIndex)
464 {
465 if (gbThemeHooksActive)
466 {
467 return user32ApiHook.GetSystemMetrics(nIndex);
468 }
469
470 return GetSystemMetrics(nIndex);
471 }
472
473 BOOL WINAPI ClassicAdjustWindowRectEx(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle)
474 {
475 if (gbThemeHooksActive)
476 {
477 return user32ApiHook.AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
478 }
479
480 return AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
481 }