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
15namespace {
16const char kHWNDSubclassKey[] = "__UI_BASE_WIN_HWND_SUBCLASS_PROC__";
17
18LRESULT 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
32WNDPROC GetCurrentWndProc(HWND target) {
33  return reinterpret_cast<WNDPROC>(GetWindowLongPtr(target, GWLP_WNDPROC));
34}
35
36// Not defined before Win7
37BOOL 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
51namespace ui {
52
53// Singleton factory that creates and manages the lifetime of all
54// ui::HWNDSubclass objects.
55class HWNDSubclass::HWNDSubclassFactory {
56 public:
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.
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
75  const ScopedVector<HWNDSubclass>& hwnd_subclasses() {
76    return hwnd_subclasses_;
77  }
78
79 private:
80  friend struct DefaultSingletonTraits<HWNDSubclassFactory>;
81
82  HWNDSubclassFactory() {}
83
84  ScopedVector<HWNDSubclass> hwnd_subclasses_;
85
86  DISALLOW_COPY_AND_ASSIGN(HWNDSubclassFactory);
87};
88
89// static
90void HWNDSubclass::AddFilterToTarget(HWND target, HWNDMessageFilter* filter) {
91  HWNDSubclassFactory::GetInstance()->GetHwndSubclassForTarget(
92      target)->AddFilter(filter);
93}
94
95// static
96void 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
105HWNDSubclass* HWNDSubclass::GetHwndSubclassForTarget(HWND target) {
106  return HWNDSubclassFactory::GetInstance()->GetHwndSubclassForTarget(target);
107}
108
109void 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
115void 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
122HWNDSubclass::HWNDSubclass(HWND target)
123    : target_(target),
124      original_wnd_proc_(GetCurrentWndProc(target)),
125      prop_(target, kHWNDSubclassKey, this) {
126  gfx::SetWindowProc(target_, &WndProc);
127}
128
129HWNDSubclass::~HWNDSubclass() {
130}
131
132LRESULT 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
166HWNDMessageFilter::~HWNDMessageFilter() {
167  HWNDSubclass::RemoveFilterFromAllTargets(this);
168}
169
170}  // namespace ui
171