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