xref: /reactos/dll/win32/comctl32/theming.c (revision b893124a)
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 <stdarg.h>
23 
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "comctl32.h"
29 #include "uxtheme.h"
30 #include "wine/debug.h"
31 
32 WINE_DEFAULT_DEBUG_CHANNEL(theming);
33 
34 typedef LRESULT (CALLBACK* THEMING_SUBCLASSPROC)(HWND, UINT, WPARAM, LPARAM,
35     ULONG_PTR);
36 
37 #ifndef __REACTOS__ /* r73803 */
38 extern LRESULT CALLBACK THEMING_DialogSubclassProc (HWND, UINT, WPARAM, LPARAM,
39                                                     ULONG_PTR) DECLSPEC_HIDDEN;
40 #endif
41 extern LRESULT CALLBACK THEMING_ScrollbarSubclassProc (HWND, UINT, WPARAM, LPARAM,
42                                                        ULONG_PTR) DECLSPEC_HIDDEN;
43 
44 #ifndef __REACTOS__
45 static const WCHAR dialogClass[] = {'#','3','2','7','7','0',0};
46 #endif
47 
48 static const struct ThemingSubclass
49 {
50     const WCHAR* className;
51     THEMING_SUBCLASSPROC subclassProc;
52 } subclasses[] = {
53     /* Note: list must be sorted by class name */
54 #ifndef __REACTOS__ /* r73803 & r73871 */
55     {dialogClass,          THEMING_DialogSubclassProc},
56 #endif
57     {WC_SCROLLBARW,        THEMING_ScrollbarSubclassProc}
58 };
59 
60 #define NUM_SUBCLASSES        (ARRAY_SIZE(subclasses))
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 #ifndef __REACTOS__
89 MAKE_SUBCLASS_PROC(1)
90 #endif
91 
92 static const WNDPROC subclassProcs[NUM_SUBCLASSES] = {
93     subclass_proc0,
94 #ifndef __REACTOS__
95     subclass_proc1,
96 #endif
97 };
98 
99 /***********************************************************************
100  * THEMING_Initialize
101  *
102  * Register classes for standard controls that will shadow the system
103  * classes.
104  */
105 #ifdef __REACTOS__ /* r73803 */
106 void THEMING_Initialize(HANDLE hActCtx5, HANDLE hActCtx6)
107 #else
108 void THEMING_Initialize (void)
109 #endif
110 {
111     unsigned int i;
112     static const WCHAR subclassPropName[] =
113         { 'C','C','3','2','T','h','e','m','i','n','g','S','u','b','C','l',0 };
114     static const WCHAR refDataPropName[] =
115         { 'C','C','3','2','T','h','e','m','i','n','g','D','a','t','a',0 };
116 #ifdef __REACTOS__ /* r73803 */
117     ULONG_PTR ulCookie;
118     BOOL ret, bActivated;
119 #else
120     if (!IsThemeActive()) return;
121 #endif
122 
123     atSubclassProp = GlobalAddAtomW (subclassPropName);
124     atRefDataProp = GlobalAddAtomW (refDataPropName);
125 
126     for (i = 0; i < NUM_SUBCLASSES; i++)
127     {
128         WNDCLASSEXW class;
129 
130         class.cbSize = sizeof(class);
131 
132 #ifdef __REACTOS__ /* r73803 */
133         bActivated = ActivateActCtx(hActCtx5, &ulCookie);
134         ret = GetClassInfoExW (NULL, subclasses[i].className, &class);
135         if (bActivated)
136             DeactivateActCtx(0, ulCookie);
137 
138         if (!ret)
139 #else
140         if (!GetClassInfoExW (NULL, subclasses[i].className, &class))
141 #endif
142         {
143             ERR("Could not retrieve information for class %s\n",
144                 debugstr_w (subclasses[i].className));
145             continue;
146         }
147         originalProcs[i] = class.lpfnWndProc;
148         class.lpfnWndProc = subclassProcs[i];
149 #ifdef __REACTOS__ /* r73803 */
150         class.style |= CS_GLOBALCLASS;
151         class.hInstance = COMCTL32_hModule;
152 #endif
153 
154         if (!class.lpfnWndProc)
155         {
156             ERR("Missing proc for class %s\n",
157                 debugstr_w (subclasses[i].className));
158             continue;
159         }
160 
161 #ifdef __REACTOS__ /* r73803 */
162         bActivated = ActivateActCtx(hActCtx6, &ulCookie);
163 #endif
164         if (!RegisterClassExW (&class))
165         {
166 #ifdef __REACTOS__ /* r73803 */
167             WARN("Could not re-register class %s: %x\n",
168 #else
169             ERR("Could not re-register class %s: %x\n",
170 #endif
171                 debugstr_w (subclasses[i].className), GetLastError ());
172         }
173         else
174         {
175             TRACE("Re-registered class %s\n",
176                 debugstr_w (subclasses[i].className));
177         }
178 
179 #ifdef __REACTOS__ /* r73803 */
180         if (bActivated)
181             DeactivateActCtx(0, ulCookie);
182 #endif
183     }
184 }
185 
186 /***********************************************************************
187  * THEMING_Uninitialize
188  *
189  * Unregister shadow classes for standard controls.
190  */
191 void THEMING_Uninitialize (void)
192 {
193     unsigned int i;
194 
195     if (!atSubclassProp) return;  /* not initialized */
196 
197     for (i = 0; i < NUM_SUBCLASSES; i++)
198     {
199         UnregisterClassW (subclasses[i].className, NULL);
200     }
201 }
202 
203 /***********************************************************************
204  * THEMING_CallOriginalClass
205  *
206  * Determines the original window proc and calls it.
207  */
208 LRESULT THEMING_CallOriginalClass (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
209 {
210     INT_PTR subclass = (INT_PTR)GetPropW (wnd, (LPCWSTR)MAKEINTATOM(atSubclassProp));
211     WNDPROC oldProc = originalProcs[subclass];
212     return CallWindowProcW (oldProc, wnd, msg, wParam, lParam);
213 }
214 
215 /***********************************************************************
216  * THEMING_SetSubclassData
217  *
218  * Update the "refData" value of the subclassed window.
219  */
220 void THEMING_SetSubclassData (HWND wnd, ULONG_PTR refData)
221 {
222     SetPropW (wnd, (LPCWSTR)MAKEINTATOM(atRefDataProp), (HANDLE)refData);
223 }
224