1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/base/win/hwnd_subclass.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_vector.h"
11 #include "base/memory/singleton.h"
12 #include "ui/gfx/win/dpi.h"
13 #include "ui/gfx/win/hwnd_util.h"
16 const char kHWNDSubclassKey
[] = "__UI_BASE_WIN_HWND_SUBCLASS_PROC__";
18 LRESULT CALLBACK
WndProc(HWND hwnd
,
22 ui::HWNDSubclass
* wrapped_wnd_proc
=
23 reinterpret_cast<ui::HWNDSubclass
*>(
24 ui::ViewProp::GetValue(hwnd
, kHWNDSubclassKey
));
25 return wrapped_wnd_proc
? wrapped_wnd_proc
->OnWndProc(hwnd
,
29 : DefWindowProc(hwnd
, message
, w_param
, l_param
);
32 WNDPROC
GetCurrentWndProc(HWND target
) {
33 return reinterpret_cast<WNDPROC
>(GetWindowLongPtr(target
, GWLP_WNDPROC
));
36 // Not defined before Win7
37 BOOL
GetTouchInputInfoWrapper(HTOUCHINPUT handle
, UINT count
,
38 PTOUCHINPUT pointer
, int size
) {
39 typedef BOOL(WINAPI
*GetTouchInputInfoPtr
)(HTOUCHINPUT
, UINT
,
41 GetTouchInputInfoPtr get_touch_input_info_func
=
42 reinterpret_cast<GetTouchInputInfoPtr
>(
43 GetProcAddress(GetModuleHandleA("user32.dll"), "GetTouchInputInfo"));
44 if (get_touch_input_info_func
)
45 return get_touch_input_info_func(handle
, count
, pointer
, size
);
53 // Singleton factory that creates and manages the lifetime of all
54 // ui::HWNDSubclass objects.
55 class HWNDSubclass::HWNDSubclassFactory
{
57 static HWNDSubclassFactory
* GetInstance() {
58 return Singleton
<HWNDSubclassFactory
,
59 LeakySingletonTraits
<HWNDSubclassFactory
> >::get();
62 // Returns a non-null HWNDSubclass corresponding to the HWND |target|. Creates
63 // one if none exists. Retains ownership of the returned pointer.
64 HWNDSubclass
* GetHwndSubclassForTarget(HWND target
) {
66 HWNDSubclass
* subclass
= reinterpret_cast<HWNDSubclass
*>(
67 ui::ViewProp::GetValue(target
, kHWNDSubclassKey
));
69 subclass
= new ui::HWNDSubclass(target
);
70 hwnd_subclasses_
.push_back(subclass
);
75 const ScopedVector
<HWNDSubclass
>& hwnd_subclasses() {
76 return hwnd_subclasses_
;
80 friend struct DefaultSingletonTraits
<HWNDSubclassFactory
>;
82 HWNDSubclassFactory() {}
84 ScopedVector
<HWNDSubclass
> hwnd_subclasses_
;
86 DISALLOW_COPY_AND_ASSIGN(HWNDSubclassFactory
);
90 void HWNDSubclass::AddFilterToTarget(HWND target
, HWNDMessageFilter
* filter
) {
91 HWNDSubclassFactory::GetInstance()->GetHwndSubclassForTarget(
92 target
)->AddFilter(filter
);
96 void HWNDSubclass::RemoveFilterFromAllTargets(HWNDMessageFilter
* filter
) {
97 HWNDSubclassFactory
* factory
= HWNDSubclassFactory::GetInstance();
98 ScopedVector
<ui::HWNDSubclass
>::const_iterator it
;
99 for (it
= factory
->hwnd_subclasses().begin();
100 it
!= factory
->hwnd_subclasses().end(); ++it
)
101 (*it
)->RemoveFilter(filter
);
105 HWNDSubclass
* HWNDSubclass::GetHwndSubclassForTarget(HWND target
) {
106 return HWNDSubclassFactory::GetInstance()->GetHwndSubclassForTarget(target
);
109 void HWNDSubclass::AddFilter(HWNDMessageFilter
* filter
) {
111 if (std::find(filters_
.begin(), filters_
.end(), filter
) == filters_
.end())
112 filters_
.push_back(filter
);
115 void HWNDSubclass::RemoveFilter(HWNDMessageFilter
* filter
) {
116 std::vector
<HWNDMessageFilter
*>::iterator it
=
117 std::find(filters_
.begin(), filters_
.end(), filter
);
118 if (it
!= filters_
.end())
122 HWNDSubclass::HWNDSubclass(HWND target
)
124 original_wnd_proc_(GetCurrentWndProc(target
)),
125 prop_(target
, kHWNDSubclassKey
, this) {
126 gfx::SetWindowProc(target_
, &WndProc
);
129 HWNDSubclass::~HWNDSubclass() {
132 LRESULT
HWNDSubclass::OnWndProc(HWND hwnd
,
137 // Touch messages are always passed in screen coordinates. If the OS is
138 // scaled, but the app is not DPI aware, then then WM_TOUCH might be
139 // intended for a different window.
140 if (message
== WM_TOUCH
) {
143 if (GetTouchInputInfoWrapper(reinterpret_cast<HTOUCHINPUT
>(l_param
), 1,
144 &point
, sizeof(TOUCHINPUT
))) {
145 POINT touch_location
= {
146 TOUCH_COORD_TO_PIXEL(point
.x
) /
147 gfx::win::GetUndocumentedDPITouchScale(),
148 TOUCH_COORD_TO_PIXEL(point
.y
) /
149 gfx::win::GetUndocumentedDPITouchScale()};
150 HWND actual_target
= WindowFromPoint(touch_location
);
151 if (actual_target
!= hwnd
) {
152 return SendMessage(actual_target
, message
, w_param
, l_param
);
157 for (std::vector
<HWNDMessageFilter
*>::iterator it
= filters_
.begin();
158 it
!= filters_
.end(); ++it
) {
159 LRESULT l_result
= 0;
160 if ((*it
)->FilterMessage(hwnd
, message
, w_param
, l_param
, &l_result
))
164 // In most cases, |original_wnd_proc_| will take care of calling
166 return CallWindowProc(original_wnd_proc_
, hwnd
, message
, w_param
, l_param
);
169 HWNDMessageFilter::~HWNDMessageFilter() {
170 HWNDSubclass::RemoveFilterFromAllTargets(this);