hwnd_subclass.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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/base/win/dpi.h" 13#include "ui/base/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 ALLOW_THIS_IN_INITIALIZER_LIST(prop_(target, kHWNDSubclassKey, this)) { 126 ui::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 = { 146 TOUCH_COORD_TO_PIXEL(point.x) / ui::win::GetUndocumentedDPIScale(), 147 TOUCH_COORD_TO_PIXEL(point.y) / ui::win::GetUndocumentedDPIScale()}; 148 HWND actual_target = WindowFromPoint(touch_location); 149 if (actual_target != hwnd) { 150 return SendMessage(actual_target, message, w_param, l_param); 151 } 152 } 153 } 154 155 for (std::vector<HWNDMessageFilter*>::iterator it = filters_.begin(); 156 it != filters_.end(); ++it) { 157 LRESULT l_result = 0; 158 if ((*it)->FilterMessage(hwnd, message, w_param, l_param, &l_result)) 159 return l_result; 160 } 161 162 // In most cases, |original_wnd_proc_| will take care of calling 163 // DefWindowProc. 164 return CallWindowProc(original_wnd_proc_, hwnd, message, w_param, l_param); 165} 166 167HWNDMessageFilter::~HWNDMessageFilter() { 168 HWNDSubclass::RemoveFilterFromAllTargets(this); 169} 170 171} // namespace ui 172