a327f18e8f8e0d953a7508848b64f1a4f32caf8e
[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.dwStyle & WS_MINIMIZE)
101 iPart = WP_MINCAPTION;
102 else if (wi.dwExStyle & WS_EX_TOOLWINDOW)
103 iPart = WP_SMALLCAPTION;
104 else if (wi.dwStyle & WS_MAXIMIZE)
105 iPart = WP_MAXCAPTION;
106 else
107 iPart = WP_CAPTION;
108
109 CaptionHeight = wi.cyWindowBorders;
110 CaptionHeight += GetSystemMetrics(wi.dwExStyle & WS_EX_TOOLWINDOW ? SM_CYSMCAPTION : SM_CYCAPTION );
111
112 GetWindowRect(hWnd, &rcWindow);
113 rcWindow.right -= rcWindow.left;
114 rcWindow.bottom = CaptionHeight;
115 rcWindow.top = 0;
116 rcWindow.left = 0;
117
118 hTheme = MSSTYLES_OpenThemeClass(ActiveThemeFile, NULL, L"WINDOW");
119 GetThemeBackgroundRegion(hTheme, 0, iPart, FS_ACTIVE, &rcWindow, &hrgn);
120 CloseThemeData(hTheme);
121
122 GetWindowRect(hWnd, &rcWindow);
123 rcWindow.right -= rcWindow.left;
124 rcWindow.bottom -= rcWindow.top;
125 rcWindow.top = CaptionHeight;
126 rcWindow.left = 0;
127 hrgn1 = CreateRectRgnIndirect(&rcWindow);
128
129 CombineRgn(hrgn, hrgn, hrgn1, RGN_OR );
130
131 DeleteObject(hrgn1);
132
133 user32ApiHook.SetWindowRgn(hWnd, hrgn, TRUE);
134 }
135
136 int OnPostWinPosChanged(HWND hWnd, WINDOWPOS* pWinPos)
137 {
138 PWND_CONTEXT pcontext;
139 DWORD style;
140
141 /* We only proceed to change the window shape if it has a caption */
142 style = GetWindowLongW(hWnd, GWL_STYLE);
143 if((style & WS_CAPTION)!=WS_CAPTION)
144 return 0;
145
146 /* Get theme data for this window */
147 pcontext = ThemeGetWndContext(hWnd);
148 if (pcontext == NULL)
149 return 0;
150
151 /* Do not change the region of the window if its size wasn't changed */
152 if ((pWinPos->flags & SWP_NOSIZE) != 0 && pcontext->DirtyThemeRegion == FALSE)
153 return 0;
154
155 /* We don't touch the shape of the window if the application sets it on its own */
156 if (pcontext->HasAppDefinedRgn == TRUE)
157 return 0;
158
159 /* Calling SetWindowRgn will call SetWindowPos again so we need to avoid this recursion */
160 if (pcontext->UpdatingRgn == TRUE)
161 return 0;
162
163 if(!IsAppThemed())
164 {
165 if(pcontext->HasThemeRgn)
166 {
167 pcontext->HasThemeRgn = FALSE;
168 user32ApiHook.SetWindowRgn(hWnd, 0, TRUE);
169 }
170 return 0;
171 }
172
173 pcontext->DirtyThemeRegion = FALSE;
174 pcontext->HasThemeRgn = TRUE;
175 pcontext->UpdatingRgn = TRUE;
176 SetThemeRegion(hWnd);
177 pcontext->UpdatingRgn = FALSE;
178
179 return 0;
180 }
181
182 /**********************************************************************
183 * Hook Functions
184 */
185
186 static LRESULT CALLBACK
187 ThemeDefWindowProcW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
188 {
189 if(!IsAppThemed())
190 {
191 return user32ApiHook.DefWindowProcW(hWnd,
192 Msg,
193 wParam,
194 lParam);
195 }
196
197 return ThemeWndProc(hWnd,
198 Msg,
199 wParam,
200 lParam,
201 user32ApiHook.DefWindowProcW);
202 }
203
204 static LRESULT CALLBACK
205 ThemeDefWindowProcA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
206 {
207 if(!IsAppThemed())
208 {
209 return user32ApiHook.DefWindowProcA(hWnd,
210 Msg,
211 wParam,
212 lParam);
213 }
214
215 return ThemeWndProc(hWnd,
216 Msg,
217 wParam,
218 lParam,
219 user32ApiHook.DefWindowProcA);
220 }
221
222 static LRESULT CALLBACK
223 ThemePreWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ret,PDWORD unknown)
224 {
225 switch(Msg)
226 {
227 case WM_THEMECHANGED:
228 if (GetAncestor(hWnd, GA_PARENT) == GetDesktopWindow())
229 UXTHEME_LoadTheme(TRUE);
230 case WM_NCCREATE:
231 {
232 PWND_CONTEXT pcontext = ThemeGetWndContext(hWnd);
233 if (pcontext == NULL)
234 return 0;
235 pcontext->DirtyThemeRegion = TRUE;
236 }
237 }
238
239 return 0;
240 }
241
242
243 static LRESULT CALLBACK
244 ThemePostWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ret,PDWORD unknown)
245 {
246 switch(Msg)
247 {
248 case WM_WINDOWPOSCHANGED:
249 {
250 return OnPostWinPosChanged(hWnd, (WINDOWPOS*)lParam);
251 }
252 case WM_DESTROY:
253 {
254 ThemeDestroyWndContext(hWnd);
255 return 0;
256 }
257 }
258
259 return 0;
260 }
261
262 int WINAPI ThemeSetWindowRgn(HWND hWnd, HRGN hRgn, BOOL bRedraw)
263 {
264 PWND_CONTEXT pcontext = ThemeGetWndContext(hWnd);
265 if(pcontext)
266 {
267 pcontext->HasAppDefinedRgn = TRUE;
268 pcontext->HasThemeRgn = FALSE;
269 }
270
271 return user32ApiHook.SetWindowRgn(hWnd, hRgn, bRedraw);
272 }
273
274 BOOL WINAPI ThemeGetScrollInfo(HWND hwnd, int fnBar, LPSCROLLINFO lpsi)
275 {
276 PWND_CONTEXT pwndContext;
277 DWORD style;
278 BOOL ret;
279
280 /* Avoid creating a window context if it is not needed */
281 if(!IsAppThemed())
282 goto dodefault;
283
284 style = GetWindowLongW(hwnd, GWL_STYLE);
285 if((style & (WS_HSCROLL|WS_VSCROLL))==0)
286 goto dodefault;
287
288 pwndContext = ThemeGetWndContext(hwnd);
289 if (pwndContext == NULL)
290 goto dodefault;
291
292 /*
293 * Uxtheme needs to handle the tracking of the scrollbar itself
294 * This means than if an application needs to get the track position
295 * with GetScrollInfo, it will get wrong data. So uxtheme needs to
296 * hook it and set the correct tracking position itself
297 */
298 ret = user32ApiHook.GetScrollInfo(hwnd, fnBar, lpsi);
299 if ( lpsi &&
300 (lpsi->fMask & SIF_TRACKPOS) &&
301 pwndContext->SCROLL_TrackingWin == hwnd &&
302 pwndContext->SCROLL_TrackingBar == fnBar)
303 {
304 lpsi->nTrackPos = pwndContext->SCROLL_TrackingVal;
305 }
306 return ret;
307
308 dodefault:
309 return user32ApiHook.GetScrollInfo(hwnd, fnBar, lpsi);
310 }
311
312 /**********************************************************************
313 * Exports
314 */
315
316 BOOL CALLBACK
317 ThemeInitApiHook(UAPIHK State, PUSERAPIHOOK puah)
318 {
319 if (!puah || State != uahLoadInit)
320 {
321 UXTHEME_LoadTheme(FALSE);
322 ThemeCleanupWndContext(NULL, 0);
323 gbThemeHooksActive = FALSE;
324 return TRUE;
325 }
326
327 gbThemeHooksActive = TRUE;
328
329 /* Store the original functions from user32 */
330 user32ApiHook = *puah;
331
332 puah->DefWindowProcA = ThemeDefWindowProcA;
333 puah->DefWindowProcW = ThemeDefWindowProcW;
334 puah->PreWndProc = ThemePreWindowProc;
335 puah->PostWndProc = ThemePostWindowProc;
336 puah->PreDefDlgProc = ThemePreWindowProc;
337 puah->PostDefDlgProc = ThemePostWindowProc;
338 puah->DefWndProcArray.MsgBitArray = gabDWPmessages;
339 puah->DefWndProcArray.Size = UAHOWP_MAX_SIZE;
340 puah->WndProcArray.MsgBitArray = gabMSGPmessages;
341 puah->WndProcArray.Size = UAHOWP_MAX_SIZE;
342 puah->DlgProcArray.MsgBitArray = gabMSGPmessages;
343 puah->DlgProcArray.Size = UAHOWP_MAX_SIZE;
344
345 puah->SetWindowRgn = ThemeSetWindowRgn;
346 puah->GetScrollInfo = ThemeGetScrollInfo;
347
348 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCPAINT);
349 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCACTIVATE);
350 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCMOUSEMOVE);
351 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCMOUSELEAVE);
352 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCHITTEST);
353 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCLBUTTONDOWN);
354 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCUAHDRAWCAPTION);
355 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCUAHDRAWFRAME);
356 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SETTEXT);
357 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_WINDOWPOSCHANGED);
358 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CONTEXTMENU);
359 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_STYLECHANGED);
360 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SETICON);
361 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_NCDESTROY);
362 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_SYSCOMMAND);
363 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORMSGBOX);
364 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORBTN);
365 UAH_HOOK_MESSAGE(puah->DefWndProcArray, WM_CTLCOLORSTATIC);
366
367 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_CREATE);
368 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_SETTINGCHANGE);
369 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_DRAWITEM);
370 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MEASUREITEM);
371 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_WINDOWPOSCHANGING);
372 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_WINDOWPOSCHANGED);
373 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_STYLECHANGING);
374 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_STYLECHANGED);
375 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCCREATE);
376 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCDESTROY);
377 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_NCPAINT);
378 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MENUCHAR);
379 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_MDISETMENU);
380 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_THEMECHANGED);
381 UAH_HOOK_MESSAGE(puah->WndProcArray, WM_UAHINIT);
382
383 UXTHEME_LoadTheme(TRUE);
384
385 return TRUE;
386 }
387
388 typedef BOOL (WINAPI * PREGISTER_UAH_WINXP)(HINSTANCE hInstance, USERAPIHOOKPROC CallbackFunc);
389 typedef BOOL (WINAPI * PREGISTER_UUAH_WIN2003)(PUSERAPIHOOKINFO puah);
390
391 BOOL WINAPI
392 ThemeHooksInstall()
393 {
394 PVOID lpFunc;
395 OSVERSIONINFO osvi;
396 BOOL ret;
397
398 lpFunc = GetProcAddress(GetModuleHandle("user32.dll"), "RegisterUserApiHook");
399
400 ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
401 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
402 GetVersionEx(&osvi);
403
404 if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
405 {
406 PREGISTER_UAH_WINXP lpfuncxp = (PREGISTER_UAH_WINXP)lpFunc;
407 ret = lpfuncxp(hDllInst, ThemeInitApiHook);
408 }
409 else if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
410 {
411 PREGISTER_UUAH_WIN2003 lpfunc2003 = (PREGISTER_UUAH_WIN2003)lpFunc;
412 USERAPIHOOKINFO uah;
413
414 uah.m_size = sizeof(uah);
415 uah.m_dllname1 = L"uxtheme.dll";
416 uah.m_funname1 = L"ThemeInitApiHook";
417 uah.m_dllname2 = NULL;
418 uah.m_funname2 = NULL;
419
420 ret = lpfunc2003(&uah);
421 }
422 else
423 {
424 UNIMPLEMENTED;
425 ret = FALSE;
426 }
427
428 UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED);
429
430 return ret;
431 }
432
433 BOOL WINAPI
434 ThemeHooksRemove()
435 {
436 BOOL ret;
437
438 ret = UnregisterUserApiHook();
439
440 UXTHEME_broadcast_msg (NULL, WM_THEMECHANGED);
441
442 return ret;
443 }
444
445 INT WINAPI ClassicSystemParametersInfoW(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni)
446 {
447 if (gbThemeHooksActive)
448 {
449 return user32ApiHook.SystemParametersInfoW(uiAction, uiParam, pvParam, fWinIni);
450 }
451
452 return SystemParametersInfoW(uiAction, uiParam, pvParam, fWinIni);
453 }
454
455 INT WINAPI ClassicSystemParametersInfoA(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni)
456 {
457 if (gbThemeHooksActive)
458 {
459 return user32ApiHook.SystemParametersInfoA(uiAction, uiParam, pvParam, fWinIni);
460 }
461
462 return SystemParametersInfoA(uiAction, uiParam, pvParam, fWinIni);
463 }
464
465 INT WINAPI ClassicGetSystemMetrics(int nIndex)
466 {
467 if (gbThemeHooksActive)
468 {
469 return user32ApiHook.GetSystemMetrics(nIndex);
470 }
471
472 return GetSystemMetrics(nIndex);
473 }
474
475 BOOL WINAPI ClassicAdjustWindowRectEx(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle)
476 {
477 if (gbThemeHooksActive)
478 {
479 return user32ApiHook.AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
480 }
481
482 return AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
483 }