| /* |
| * Theming - Initialization |
| * |
| * Copyright (c) 2005 by Frank Richter |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| * |
| */ |
| |
| #include <stdarg.h> |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wingdi.h" |
| #include "winuser.h" |
| #include "comctl32.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(theming); |
| |
| typedef LRESULT (CALLBACK* THEMING_SUBCLASSPROC)(HWND, UINT, WPARAM, LPARAM, |
| ULONG_PTR); |
| |
| extern LRESULT CALLBACK THEMING_ComboSubclassProc (HWND, UINT, WPARAM, LPARAM, |
| ULONG_PTR); |
| extern LRESULT CALLBACK THEMING_EditSubclassProc (HWND, UINT, WPARAM, LPARAM, |
| ULONG_PTR); |
| extern LRESULT CALLBACK THEMING_ListBoxSubclassProc (HWND, UINT, WPARAM, LPARAM, |
| ULONG_PTR); |
| |
| static const WCHAR comboLboxClass[] = {'C','o','m','b','o','L','b','o','x',0}; |
| |
| static const struct ThemingSubclass |
| { |
| const WCHAR* className; |
| THEMING_SUBCLASSPROC subclassProc; |
| } subclasses[] = { |
| /* Note: list must be sorted by class name */ |
| {WC_COMBOBOXW, THEMING_ComboSubclassProc}, |
| {comboLboxClass, THEMING_ListBoxSubclassProc}, |
| {WC_EDITW, THEMING_EditSubclassProc}, |
| {WC_LISTBOXW, THEMING_ListBoxSubclassProc} |
| }; |
| |
| #define NUM_SUBCLASSES (sizeof(subclasses)/sizeof(subclasses[0])) |
| |
| static WNDPROC originalProcs[NUM_SUBCLASSES]; |
| static ATOM atRefDataProp; |
| static ATOM atSubclassProp; |
| |
| /*********************************************************************** |
| * THEMING_SubclassProc |
| * |
| * The window proc registered to the subclasses. Fetches the subclass |
| * proc and ref data and call the proc. |
| */ |
| static LRESULT CALLBACK THEMING_SubclassProc (HWND wnd, UINT msg, |
| WPARAM wParam, LPARAM lParam) |
| { |
| int subclass = (int)GetPropW (wnd, MAKEINTATOMW (atSubclassProp)); |
| LRESULT result; |
| ULONG_PTR refData; |
| |
| refData = (ULONG_PTR)GetPropW (wnd, MAKEINTATOMW (atRefDataProp)); |
| |
| TRACE ("%d; (%p, %x, %x, %lx, %lx)", subclass, wnd, msg, wParam, lParam, |
| refData); |
| result = subclasses[subclass].subclassProc (wnd, msg, wParam, lParam, refData); |
| TRACE (" = %lx\n", result); |
| return result; |
| } |
| |
| /* Generate a number of subclass window procs. |
| * With a single proc alone, we can't really reliably find out the superclass, |
| * hence, the first time the subclass is called, these "stubs" are used which |
| * just save the internal ID of the subclass. |
| */ |
| #define MAKE_SUBCLASS_STUB(N) \ |
| static LRESULT CALLBACK subclass_stub ## N (HWND wnd, UINT msg, \ |
| WPARAM wParam, LPARAM lParam) \ |
| { \ |
| SetPropW (wnd, MAKEINTATOMW (atSubclassProp), (HANDLE)N); \ |
| SetWindowLongPtrW (wnd, GWLP_WNDPROC, (LONG_PTR)THEMING_SubclassProc); \ |
| return THEMING_SubclassProc (wnd, msg, wParam, lParam); \ |
| } |
| |
| MAKE_SUBCLASS_STUB(0) |
| MAKE_SUBCLASS_STUB(1) |
| MAKE_SUBCLASS_STUB(2) |
| MAKE_SUBCLASS_STUB(3) |
| |
| const static WNDPROC subclassStubs[NUM_SUBCLASSES] = { |
| subclass_stub0, |
| subclass_stub1, |
| subclass_stub2, |
| subclass_stub3 |
| }; |
| |
| /*********************************************************************** |
| * THEMING_Initialize |
| * |
| * Register classes for standard controls that will shadow the system |
| * classes. |
| */ |
| void THEMING_Initialize (void) |
| { |
| int i; |
| static const WCHAR subclassPropName[] = |
| { 'C','C','3','2','T','h','e','m','i','n','g','S','u','b','C','l',0 }; |
| static const WCHAR refDataPropName[] = |
| { 'C','C','3','2','T','h','e','m','i','n','g','D','a','t','a',0 }; |
| |
| atSubclassProp = GlobalAddAtomW (subclassPropName); |
| atRefDataProp = GlobalAddAtomW (refDataPropName); |
| |
| for (i = 0; i < NUM_SUBCLASSES; i++) |
| { |
| WNDCLASSEXW class; |
| |
| class.cbSize = sizeof(class); |
| class.style |= CS_GLOBALCLASS; |
| GetClassInfoExW (NULL, subclasses[i].className, &class); |
| originalProcs[i] = class.lpfnWndProc; |
| class.lpfnWndProc = subclassStubs[i]; |
| |
| if (!class.lpfnWndProc) |
| { |
| ERR("Missing stub for class %s\n", |
| debugstr_w (subclasses[i].className)); |
| continue; |
| } |
| |
| if (!RegisterClassExW (&class)) |
| { |
| ERR("Could not re-register class %s: %lx\n", |
| debugstr_w (subclasses[i].className), GetLastError ()); |
| } |
| else |
| { |
| TRACE("Re-registered class %s\n", |
| debugstr_w (subclasses[i].className)); |
| } |
| } |
| } |
| |
| /*********************************************************************** |
| * THEMING_CallOriginalClass |
| * |
| * Determines the original window proc and calls it. |
| */ |
| LRESULT THEMING_CallOriginalClass (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) |
| { |
| int subclass = (int)GetPropW (wnd, MAKEINTATOMW (atSubclassProp)); |
| WNDPROC oldProc = originalProcs[subclass]; |
| return CallWindowProcW (oldProc, wnd, msg, wParam, lParam); |
| } |
| |
| /*********************************************************************** |
| * THEMING_SetSubclassData |
| * |
| * Update the "refData" value of the subclassed window. |
| */ |
| void THEMING_SetSubclassData (HWND wnd, ULONG_PTR refData) |
| { |
| SetPropW (wnd, MAKEINTATOMW (atRefDataProp), (HANDLE)refData); |
| } |