[COMCTL32]
[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 extern LRESULT CALLBACK THEMING_ButtonSubclassProc (HWND, UINT, WPARAM, LPARAM,
30 ULONG_PTR) DECLSPEC_HIDDEN;
31 extern LRESULT CALLBACK THEMING_ComboSubclassProc (HWND, UINT, WPARAM, LPARAM,
32 ULONG_PTR) DECLSPEC_HIDDEN;
33 extern LRESULT CALLBACK THEMING_EditSubclassProc (HWND, UINT, WPARAM, LPARAM,
34 ULONG_PTR) DECLSPEC_HIDDEN;
35 extern LRESULT CALLBACK THEMING_ListBoxSubclassProc (HWND, UINT, WPARAM, LPARAM,
36 ULONG_PTR) DECLSPEC_HIDDEN;
37 extern LRESULT CALLBACK THEMING_ScrollbarSubclassProc (HWND, UINT, WPARAM, LPARAM,
38 ULONG_PTR) DECLSPEC_HIDDEN;
39
40 static const WCHAR dialogClass[] = {'#','3','2','7','7','0',0};
41 static const WCHAR comboLboxClass[] = {'C','o','m','b','o','L','b','o','x',0};
42
43 static const struct ThemingSubclass
44 {
45 const WCHAR* className;
46 THEMING_SUBCLASSPROC subclassProc;
47 } subclasses[] = {
48 /* Note: list must be sorted by class name */
49 {WC_BUTTONW, THEMING_ButtonSubclassProc},
50 {WC_COMBOBOXW, THEMING_ComboSubclassProc},
51 {comboLboxClass, THEMING_ListBoxSubclassProc},
52 {WC_EDITW, THEMING_EditSubclassProc},
53 {WC_LISTBOXW, THEMING_ListBoxSubclassProc},
54 {WC_SCROLLBARW, THEMING_ScrollbarSubclassProc}
55 };
56
57 #define NUM_SUBCLASSES (sizeof(subclasses)/sizeof(subclasses[0]))
58
59 static WNDPROC originalProcs[NUM_SUBCLASSES];
60 static ATOM atRefDataProp;
61 static ATOM atSubclassProp;
62
63 /* Generate a number of subclass window procs.
64 * With a single proc alone, we can't really reliably find out the superclass,
65 * so have one for each subclass. The subclass number is also stored in a prop
66 * since it's needed by THEMING_CallOriginalClass(). Then, the subclass
67 * proc and ref data are fetched and the proc called.
68 */
69 #define MAKE_SUBCLASS_PROC(N) \
70 static LRESULT CALLBACK subclass_proc ## N (HWND wnd, UINT msg, \
71 WPARAM wParam, LPARAM lParam) \
72 { \
73 LRESULT result; \
74 ULONG_PTR refData; \
75 SetPropW (wnd, (LPCWSTR)MAKEINTATOM(atSubclassProp), (HANDLE)N); \
76 refData = (ULONG_PTR)GetPropW (wnd, (LPCWSTR)MAKEINTATOM(atRefDataProp)); \
77 TRACE ("%d; (%p, %x, %lx, %lx, %lx)\n", N, wnd, msg, wParam, lParam, \
78 refData); \
79 result = subclasses[N].subclassProc (wnd, msg, wParam, lParam, refData);\
80 TRACE ("result = %lx\n", result); \
81 return result; \
82 }
83
84 MAKE_SUBCLASS_PROC(0)
85 MAKE_SUBCLASS_PROC(1)
86 MAKE_SUBCLASS_PROC(2)
87 MAKE_SUBCLASS_PROC(3)
88 MAKE_SUBCLASS_PROC(4)
89 MAKE_SUBCLASS_PROC(5)
90
91 static const WNDPROC subclassProcs[NUM_SUBCLASSES] = {
92 subclass_proc0,
93 subclass_proc1,
94 subclass_proc2,
95 subclass_proc3,
96 subclass_proc4,
97 subclass_proc5
98 };
99
100 /***********************************************************************
101 * THEMING_Initialize
102 *
103 * Register classes for standard controls that will shadow the system
104 * classes.
105 */
106 void THEMING_Initialize (HANDLE hActCtx5, HANDLE hActCtx6)
107 {
108 unsigned int i;
109 static const WCHAR subclassPropName[] =
110 { 'C','C','3','2','T','h','e','m','i','n','g','S','u','b','C','l',0 };
111 static const WCHAR refDataPropName[] =
112 { 'C','C','3','2','T','h','e','m','i','n','g','D','a','t','a',0 };
113 ULONG_PTR ulCookie;
114 BOOL ret, bActivated;
115
116 atSubclassProp = GlobalAddAtomW (subclassPropName);
117 atRefDataProp = GlobalAddAtomW (refDataPropName);
118
119 for (i = 0; i < NUM_SUBCLASSES; i++)
120 {
121 WNDCLASSEXW class;
122
123 class.cbSize = sizeof(class);
124
125 bActivated = ActivateActCtx(hActCtx5, &ulCookie);
126 ret = GetClassInfoExW (NULL, subclasses[i].className, &class);
127 if (bActivated)
128 DeactivateActCtx(0, ulCookie);
129
130 if (!ret)
131 {
132 ERR("Could not retrieve information for class %s\n",
133 debugstr_w (subclasses[i].className));
134 continue;
135 }
136 originalProcs[i] = class.lpfnWndProc;
137 class.lpfnWndProc = subclassProcs[i];
138 class.style |= CS_GLOBALCLASS;
139 class.hInstance = COMCTL32_hModule;
140
141 if (!class.lpfnWndProc)
142 {
143 ERR("Missing proc for class %s\n",
144 debugstr_w (subclasses[i].className));
145 continue;
146 }
147
148 bActivated = ActivateActCtx(hActCtx6, &ulCookie);
149
150 if (!RegisterClassExW (&class))
151 {
152 WARN("Could not re-register class %s: %x\n",
153 debugstr_w (subclasses[i].className), GetLastError ());
154 }
155 else
156 {
157 TRACE("Re-registered class %s\n",
158 debugstr_w (subclasses[i].className));
159 }
160
161 if (bActivated)
162 DeactivateActCtx(0, ulCookie);
163 }
164 }
165
166 /***********************************************************************
167 * THEMING_Uninitialize
168 *
169 * Unregister shadow classes for standard controls.
170 */
171 void THEMING_Uninitialize (void)
172 {
173 unsigned int i;
174
175 if (!atSubclassProp) return; /* not initialized */
176
177 for (i = 0; i < NUM_SUBCLASSES; i++)
178 {
179 UnregisterClassW (subclasses[i].className, NULL);
180 }
181 }
182
183 /***********************************************************************
184 * THEMING_CallOriginalClass
185 *
186 * Determines the original window proc and calls it.
187 */
188 LRESULT THEMING_CallOriginalClass (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
189 {
190 INT_PTR subclass = (INT_PTR)GetPropW (wnd, (LPCWSTR)MAKEINTATOM(atSubclassProp));
191 WNDPROC oldProc = originalProcs[subclass];
192 return CallWindowProcW (oldProc, wnd, msg, wParam, lParam);
193 }
194
195 /***********************************************************************
196 * THEMING_SetSubclassData
197 *
198 * Update the "refData" value of the subclassed window.
199 */
200 void THEMING_SetSubclassData (HWND wnd, ULONG_PTR refData)
201 {
202 SetPropW (wnd, (LPCWSTR)MAKEINTATOM(atRefDataProp), (HANDLE)refData);
203 }