[COMCTL32] Sync with Wine Staging 2.9. CORE-13362
[reactos.git] / reactos / dll / win32 / comctl32 / theming.c
1 /*
2 * Theming - Initialization
3 *
4 * Copyright (c) 2005 by Frank Richter
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 *
20 */
21
22 #include "comctl32.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(theming);
25
26 typedef LRESULT (CALLBACK* THEMING_SUBCLASSPROC)(HWND, UINT, WPARAM, LPARAM,
27 ULONG_PTR);
28
29 #ifndef __REACTOS__ /* r73871 */
30 extern LRESULT CALLBACK THEMING_ButtonSubclassProc (HWND, UINT, WPARAM, LPARAM,
31 ULONG_PTR) DECLSPEC_HIDDEN;
32 #endif
33 extern LRESULT CALLBACK THEMING_ComboSubclassProc (HWND, UINT, WPARAM, LPARAM,
34 ULONG_PTR) DECLSPEC_HIDDEN;
35 #ifndef __REACTOS__ /* r73803 */
36 extern LRESULT CALLBACK THEMING_DialogSubclassProc (HWND, UINT, WPARAM, LPARAM,
37 ULONG_PTR) DECLSPEC_HIDDEN;
38 #endif
39 extern LRESULT CALLBACK THEMING_EditSubclassProc (HWND, UINT, WPARAM, LPARAM,
40 ULONG_PTR) DECLSPEC_HIDDEN;
41 extern LRESULT CALLBACK THEMING_ListBoxSubclassProc (HWND, UINT, WPARAM, LPARAM,
42 ULONG_PTR) DECLSPEC_HIDDEN;
43 extern LRESULT CALLBACK THEMING_ScrollbarSubclassProc (HWND, UINT, WPARAM, LPARAM,
44 ULONG_PTR) DECLSPEC_HIDDEN;
45
46 static const WCHAR dialogClass[] = {'#','3','2','7','7','0',0};
47 static const WCHAR comboLboxClass[] = {'C','o','m','b','o','L','b','o','x',0};
48
49 static const struct ThemingSubclass
50 {
51 const WCHAR* className;
52 THEMING_SUBCLASSPROC subclassProc;
53 } subclasses[] = {
54 /* Note: list must be sorted by class name */
55 #ifndef __REACTOS__ /* r73803 & r73871 */
56 {dialogClass, THEMING_DialogSubclassProc},
57 {WC_BUTTONW, THEMING_ButtonSubclassProc},
58 #endif
59 {WC_COMBOBOXW, THEMING_ComboSubclassProc},
60 {comboLboxClass, THEMING_ListBoxSubclassProc},
61 {WC_EDITW, THEMING_EditSubclassProc},
62 {WC_LISTBOXW, THEMING_ListBoxSubclassProc},
63 {WC_SCROLLBARW, THEMING_ScrollbarSubclassProc}
64 };
65
66 #define NUM_SUBCLASSES (sizeof(subclasses)/sizeof(subclasses[0]))
67
68 static WNDPROC originalProcs[NUM_SUBCLASSES];
69 static ATOM atRefDataProp;
70 static ATOM atSubclassProp;
71
72 /* Generate a number of subclass window procs.
73 * With a single proc alone, we can't really reliably find out the superclass,
74 * so have one for each subclass. The subclass number is also stored in a prop
75 * since it's needed by THEMING_CallOriginalClass(). Then, the subclass
76 * proc and ref data are fetched and the proc called.
77 */
78 #define MAKE_SUBCLASS_PROC(N) \
79 static LRESULT CALLBACK subclass_proc ## N (HWND wnd, UINT msg, \
80 WPARAM wParam, LPARAM lParam) \
81 { \
82 LRESULT result; \
83 ULONG_PTR refData; \
84 SetPropW (wnd, (LPCWSTR)MAKEINTATOM(atSubclassProp), (HANDLE)N); \
85 refData = (ULONG_PTR)GetPropW (wnd, (LPCWSTR)MAKEINTATOM(atRefDataProp)); \
86 TRACE ("%d; (%p, %x, %lx, %lx, %lx)\n", N, wnd, msg, wParam, lParam, \
87 refData); \
88 result = subclasses[N].subclassProc (wnd, msg, wParam, lParam, refData);\
89 TRACE ("result = %lx\n", result); \
90 return result; \
91 }
92
93 MAKE_SUBCLASS_PROC(0)
94 MAKE_SUBCLASS_PROC(1)
95 MAKE_SUBCLASS_PROC(2)
96 MAKE_SUBCLASS_PROC(3)
97 MAKE_SUBCLASS_PROC(4)
98 #ifndef __REACTOS__ /* r73803 & r73871 */
99 MAKE_SUBCLASS_PROC(5)
100 MAKE_SUBCLASS_PROC(6)
101 #endif
102
103 static const WNDPROC subclassProcs[NUM_SUBCLASSES] = {
104 subclass_proc0,
105 subclass_proc1,
106 subclass_proc2,
107 subclass_proc3,
108 #ifdef __REACTOS__ /* r73871 */
109 subclass_proc4
110 #else
111 subclass_proc4,
112 subclass_proc5,
113 subclass_proc6
114 #endif
115 };
116
117 /***********************************************************************
118 * THEMING_Initialize
119 *
120 * Register classes for standard controls that will shadow the system
121 * classes.
122 */
123 #ifdef __REACTOS__ /* r73803 */
124 void THEMING_Initialize(HANDLE hActCtx5, HANDLE hActCtx6)
125 #else
126 void THEMING_Initialize (void)
127 #endif
128 {
129 unsigned int i;
130 static const WCHAR subclassPropName[] =
131 { 'C','C','3','2','T','h','e','m','i','n','g','S','u','b','C','l',0 };
132 static const WCHAR refDataPropName[] =
133 { 'C','C','3','2','T','h','e','m','i','n','g','D','a','t','a',0 };
134 #ifdef __REACTOS__ /* r73803 */
135 ULONG_PTR ulCookie;
136 BOOL ret, bActivated;
137 #else
138 if (!IsThemeActive()) return;
139 #endif
140
141 atSubclassProp = GlobalAddAtomW (subclassPropName);
142 atRefDataProp = GlobalAddAtomW (refDataPropName);
143
144 for (i = 0; i < NUM_SUBCLASSES; i++)
145 {
146 WNDCLASSEXW class;
147
148 class.cbSize = sizeof(class);
149
150 #ifdef __REACTOS__ /* r73803 */
151 bActivated = ActivateActCtx(hActCtx5, &ulCookie);
152 ret = GetClassInfoExW (NULL, subclasses[i].className, &class);
153 if (bActivated)
154 DeactivateActCtx(0, ulCookie);
155
156 if (!ret)
157 #else
158 if (!GetClassInfoExW (NULL, subclasses[i].className, &class))
159 #endif
160 {
161 ERR("Could not retrieve information for class %s\n",
162 debugstr_w (subclasses[i].className));
163 continue;
164 }
165 originalProcs[i] = class.lpfnWndProc;
166 class.lpfnWndProc = subclassProcs[i];
167 #ifdef __REACTOS__ /* r73803 */
168 class.style |= CS_GLOBALCLASS;
169 class.hInstance = COMCTL32_hModule;
170 #endif
171
172 if (!class.lpfnWndProc)
173 {
174 ERR("Missing proc for class %s\n",
175 debugstr_w (subclasses[i].className));
176 continue;
177 }
178
179 #ifdef __REACTOS__ /* r73803 */
180 bActivated = ActivateActCtx(hActCtx6, &ulCookie);
181 #endif
182 if (!RegisterClassExW (&class))
183 {
184 #ifdef __REACTOS__ /* r73803 */
185 WARN("Could not re-register class %s: %x\n",
186 #else
187 ERR("Could not re-register class %s: %x\n",
188 #endif
189 debugstr_w (subclasses[i].className), GetLastError ());
190 }
191 else
192 {
193 TRACE("Re-registered class %s\n",
194 debugstr_w (subclasses[i].className));
195 }
196
197 #ifdef __REACTOS__ /* r73803 */
198 if (bActivated)
199 DeactivateActCtx(0, ulCookie);
200 #endif
201 }
202 }
203
204 /***********************************************************************
205 * THEMING_Uninitialize
206 *
207 * Unregister shadow classes for standard controls.
208 */
209 void THEMING_Uninitialize (void)
210 {
211 unsigned int i;
212
213 if (!atSubclassProp) return; /* not initialized */
214
215 for (i = 0; i < NUM_SUBCLASSES; i++)
216 {
217 UnregisterClassW (subclasses[i].className, NULL);
218 }
219 }
220
221 /***********************************************************************
222 * THEMING_CallOriginalClass
223 *
224 * Determines the original window proc and calls it.
225 */
226 LRESULT THEMING_CallOriginalClass (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
227 {
228 INT_PTR subclass = (INT_PTR)GetPropW (wnd, (LPCWSTR)MAKEINTATOM(atSubclassProp));
229 WNDPROC oldProc = originalProcs[subclass];
230 return CallWindowProcW (oldProc, wnd, msg, wParam, lParam);
231 }
232
233 /***********************************************************************
234 * THEMING_SetSubclassData
235 *
236 * Update the "refData" value of the subclassed window.
237 */
238 void THEMING_SetSubclassData (HWND wnd, ULONG_PTR refData)
239 {
240 SetPropW (wnd, (LPCWSTR)MAKEINTATOM(atRefDataProp), (HANDLE)refData);
241 }