15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/win/hwnd_subclass.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_vector.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/singleton.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/win/dpi.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/win/hwnd_util.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kHWNDSubclassKey[] = "__UI_BASE_WIN_HWND_SUBCLASS_PROC__";
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LRESULT CALLBACK WndProc(HWND hwnd,
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         UINT message,
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         WPARAM w_param,
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         LPARAM l_param) {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::HWNDSubclass* wrapped_wnd_proc =
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<ui::HWNDSubclass*>(
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ui::ViewProp::GetValue(hwnd, kHWNDSubclassKey));
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return wrapped_wnd_proc ? wrapped_wnd_proc->OnWndProc(hwnd,
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                        message,
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                        w_param,
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                        l_param)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          : DefWindowProc(hwnd, message, w_param, l_param);
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WNDPROC GetCurrentWndProc(HWND target) {
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return reinterpret_cast<WNDPROC>(GetWindowLongPtr(target, GWLP_WNDPROC));
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Not defined before Win7
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)BOOL GetTouchInputInfoWrapper(HTOUCHINPUT handle, UINT count,
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              PTOUCHINPUT pointer, int size) {
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  typedef BOOL(WINAPI *GetTouchInputInfoPtr)(HTOUCHINPUT, UINT,
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             PTOUCHINPUT, int);
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetTouchInputInfoPtr get_touch_input_info_func =
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      reinterpret_cast<GetTouchInputInfoPtr>(
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          GetProcAddress(GetModuleHandleA("user32.dll"), "GetTouchInputInfo"));
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (get_touch_input_info_func)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return get_touch_input_info_func(handle, count, pointer, size);
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return FALSE;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ui {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Singleton factory that creates and manages the lifetime of all
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ui::HWNDSubclass objects.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class HWNDSubclass::HWNDSubclassFactory {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static HWNDSubclassFactory* GetInstance() {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return Singleton<HWNDSubclassFactory,
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LeakySingletonTraits<HWNDSubclassFactory> >::get();
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns a non-null HWNDSubclass corresponding to the HWND |target|. Creates
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // one if none exists. Retains ownership of the returned pointer.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HWNDSubclass* GetHwndSubclassForTarget(HWND target) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(target);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HWNDSubclass* subclass = reinterpret_cast<HWNDSubclass*>(
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ui::ViewProp::GetValue(target, kHWNDSubclassKey));
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!subclass) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      subclass = new ui::HWNDSubclass(target);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hwnd_subclasses_.push_back(subclass);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return subclass;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ScopedVector<HWNDSubclass>& hwnd_subclasses() {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hwnd_subclasses_;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend struct DefaultSingletonTraits<HWNDSubclassFactory>;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HWNDSubclassFactory() {}
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<HWNDSubclass> hwnd_subclasses_;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(HWNDSubclassFactory);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HWNDSubclass::AddFilterToTarget(HWND target, HWNDMessageFilter* filter) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HWNDSubclassFactory::GetInstance()->GetHwndSubclassForTarget(
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      target)->AddFilter(filter);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HWNDSubclass::RemoveFilterFromAllTargets(HWNDMessageFilter* filter) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HWNDSubclassFactory* factory = HWNDSubclassFactory::GetInstance();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<ui::HWNDSubclass>::const_iterator it;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (it = factory->hwnd_subclasses().begin();
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      it != factory->hwnd_subclasses().end(); ++it)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*it)->RemoveFilter(filter);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HWNDSubclass* HWNDSubclass::GetHwndSubclassForTarget(HWND target) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return HWNDSubclassFactory::GetInstance()->GetHwndSubclassForTarget(target);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HWNDSubclass::AddFilter(HWNDMessageFilter* filter) {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(filter);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (std::find(filters_.begin(), filters_.end(), filter) == filters_.end())
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    filters_.push_back(filter);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HWNDSubclass::RemoveFilter(HWNDMessageFilter* filter) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<HWNDMessageFilter*>::iterator it =
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::find(filters_.begin(), filters_.end(), filter);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it != filters_.end())
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    filters_.erase(it);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HWNDSubclass::HWNDSubclass(HWND target)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : target_(target),
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      original_wnd_proc_(GetCurrentWndProc(target)),
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      prop_(target, kHWNDSubclassKey, this) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::SetWindowProc(target_, &WndProc);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HWNDSubclass::~HWNDSubclass() {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LRESULT HWNDSubclass::OnWndProc(HWND hwnd,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                UINT message,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                WPARAM w_param,
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                LPARAM l_param) {
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Touch messages are always passed in screen coordinates. If the OS is
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // scaled, but the app is not DPI aware, then then WM_TOUCH might be
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // intended for a different window.
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (message == WM_TOUCH) {
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    TOUCHINPUT point;
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (GetTouchInputInfoWrapper(reinterpret_cast<HTOUCHINPUT>(l_param), 1,
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 &point, sizeof(TOUCHINPUT))) {
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      POINT touch_location = {
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        TOUCH_COORD_TO_PIXEL(point.x) / ui::win::GetUndocumentedDPIScale(),
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        TOUCH_COORD_TO_PIXEL(point.y) / ui::win::GetUndocumentedDPIScale()};
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      HWND actual_target = WindowFromPoint(touch_location);
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (actual_target != hwnd) {
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return SendMessage(actual_target, message, w_param, l_param);
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<HWNDMessageFilter*>::iterator it = filters_.begin();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      it != filters_.end(); ++it) {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LRESULT l_result = 0;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((*it)->FilterMessage(hwnd, message, w_param, l_param, &l_result))
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return l_result;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In most cases, |original_wnd_proc_| will take care of calling
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // DefWindowProc.
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CallWindowProc(original_wnd_proc_, hwnd, message, w_param, l_param);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HWNDMessageFilter::~HWNDMessageFilter() {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HWNDSubclass::RemoveFilterFromAllTargets(this);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace ui
172