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.
4
5 #include "ui/base/win/hwnd_subclass.h"
6
7 #include <algorithm>
8
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"
14
15 namespace {
16 const char kHWNDSubclassKey[] = "__UI_BASE_WIN_HWND_SUBCLASS_PROC__";
17
WndProc(HWND hwnd,UINT message,WPARAM w_param,LPARAM l_param)18 LRESULT CALLBACK WndProc(HWND hwnd,
19 UINT message,
20 WPARAM w_param,
21 LPARAM l_param) {
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,
26 message,
27 w_param,
28 l_param)
29 : DefWindowProc(hwnd, message, w_param, l_param);
30 }
31
GetCurrentWndProc(HWND target)32 WNDPROC GetCurrentWndProc(HWND target) {
33 return reinterpret_cast<WNDPROC>(GetWindowLongPtr(target, GWLP_WNDPROC));
34 }
35
36 // Not defined before Win7
GetTouchInputInfoWrapper(HTOUCHINPUT handle,UINT count,PTOUCHINPUT pointer,int size)37 BOOL GetTouchInputInfoWrapper(HTOUCHINPUT handle, UINT count,
38 PTOUCHINPUT pointer, int size) {
39 typedef BOOL(WINAPI *GetTouchInputInfoPtr)(HTOUCHINPUT, UINT,
40 PTOUCHINPUT, int);
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);
46 return FALSE;
47 }
48
49 } // namespace
50
51 namespace ui {
52
53 // Singleton factory that creates and manages the lifetime of all
54 // ui::HWNDSubclass objects.
55 class HWNDSubclass::HWNDSubclassFactory {
56 public:
GetInstance()57 static HWNDSubclassFactory* GetInstance() {
58 return Singleton<HWNDSubclassFactory,
59 LeakySingletonTraits<HWNDSubclassFactory> >::get();
60 }
61
62 // Returns a non-null HWNDSubclass corresponding to the HWND |target|. Creates
63 // one if none exists. Retains ownership of the returned pointer.
GetHwndSubclassForTarget(HWND target)64 HWNDSubclass* GetHwndSubclassForTarget(HWND target) {
65 DCHECK(target);
66 HWNDSubclass* subclass = reinterpret_cast<HWNDSubclass*>(
67 ui::ViewProp::GetValue(target, kHWNDSubclassKey));
68 if (!subclass) {
69 subclass = new ui::HWNDSubclass(target);
70 hwnd_subclasses_.push_back(subclass);
71 }
72 return subclass;
73 }
74
hwnd_subclasses()75 const ScopedVector<HWNDSubclass>& hwnd_subclasses() {
76 return hwnd_subclasses_;
77 }
78
79 private:
80 friend struct DefaultSingletonTraits<HWNDSubclassFactory>;
81
HWNDSubclassFactory()82 HWNDSubclassFactory() {}
83
84 ScopedVector<HWNDSubclass> hwnd_subclasses_;
85
86 DISALLOW_COPY_AND_ASSIGN(HWNDSubclassFactory);
87 };
88
89 // static
AddFilterToTarget(HWND target,HWNDMessageFilter * filter)90 void HWNDSubclass::AddFilterToTarget(HWND target, HWNDMessageFilter* filter) {
91 HWNDSubclassFactory::GetInstance()->GetHwndSubclassForTarget(
92 target)->AddFilter(filter);
93 }
94
95 // static
RemoveFilterFromAllTargets(HWNDMessageFilter * 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);
102 }
103
104 // static
GetHwndSubclassForTarget(HWND target)105 HWNDSubclass* HWNDSubclass::GetHwndSubclassForTarget(HWND target) {
106 return HWNDSubclassFactory::GetInstance()->GetHwndSubclassForTarget(target);
107 }
108
AddFilter(HWNDMessageFilter * filter)109 void HWNDSubclass::AddFilter(HWNDMessageFilter* filter) {
110 DCHECK(filter);
111 if (std::find(filters_.begin(), filters_.end(), filter) == filters_.end())
112 filters_.push_back(filter);
113 }
114
RemoveFilter(HWNDMessageFilter * 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())
119 filters_.erase(it);
120 }
121
HWNDSubclass(HWND target)122 HWNDSubclass::HWNDSubclass(HWND target)
123 : target_(target),
124 original_wnd_proc_(GetCurrentWndProc(target)),
125 prop_(target, kHWNDSubclassKey, this) {
126 gfx::SetWindowProc(target_, &WndProc);
127 }
128
~HWNDSubclass()129 HWNDSubclass::~HWNDSubclass() {
130 }
131
OnWndProc(HWND hwnd,UINT message,WPARAM w_param,LPARAM l_param)132 LRESULT HWNDSubclass::OnWndProc(HWND hwnd,
133 UINT message,
134 WPARAM w_param,
135 LPARAM l_param) {
136
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) {
141 TOUCHINPUT point;
142
143 if (GetTouchInputInfoWrapper(reinterpret_cast<HTOUCHINPUT>(l_param), 1,
144 &point, sizeof(TOUCHINPUT))) {
145 POINT touch_location = {TOUCH_COORD_TO_PIXEL(point.x),
146 TOUCH_COORD_TO_PIXEL(point.y)};
147 HWND actual_target = WindowFromPoint(touch_location);
148 if (actual_target != hwnd) {
149 return SendMessage(actual_target, message, w_param, l_param);
150 }
151 }
152 }
153
154 for (std::vector<HWNDMessageFilter*>::iterator it = filters_.begin();
155 it != filters_.end(); ++it) {
156 LRESULT l_result = 0;
157 if ((*it)->FilterMessage(hwnd, message, w_param, l_param, &l_result))
158 return l_result;
159 }
160
161 // In most cases, |original_wnd_proc_| will take care of calling
162 // DefWindowProc.
163 return CallWindowProc(original_wnd_proc_, hwnd, message, w_param, l_param);
164 }
165
~HWNDMessageFilter()166 HWNDMessageFilter::~HWNDMessageFilter() {
167 HWNDSubclass::RemoveFilterFromAllTargets(this);
168 }
169
170 } // namespace ui
171