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