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