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