• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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