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 "chrome/browser/ui/tabs/dock_info.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_gdi_object.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/ash/tabs/dock_info_ash.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_window.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/frame/browser_view.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/tabs/tab.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/root_window.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/screen.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/win/hwnd_util.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(USE_AURA)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/views/widget/desktop_aura/desktop_root_window_host_win.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BaseWindowFinder -----------------------------------------------------------
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Base class used to locate a window. This is intended to be used with the
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// various win32 functions that iterate over windows.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A subclass need only override ShouldStopIterating to determine when
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// iteration should stop.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BaseWindowFinder {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates a BaseWindowFinder with the specified set of HWNDs to ignore.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit BaseWindowFinder(const std::set<HWND>& ignore) : ignore_(ignore) {}
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~BaseWindowFinder() {}
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static BOOL CALLBACK WindowCallbackProc(HWND hwnd, LPARAM lParam) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Cast must match that in as_lparam().
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BaseWindowFinder* finder = reinterpret_cast<BaseWindowFinder*>(lParam);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (finder->ignore_.find(hwnd) != finder->ignore_.end())
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return TRUE;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return finder->ShouldStopIterating(hwnd) ? FALSE : TRUE;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LPARAM as_lparam() {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Cast must match that in WindowCallbackProc().
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return reinterpret_cast<LPARAM>(static_cast<BaseWindowFinder*>(this));
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true if iteration should stop, false if iteration should continue.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool ShouldStopIterating(HWND window) = 0;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::set<HWND>& ignore_;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(BaseWindowFinder);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TopMostFinder --------------------------------------------------------------
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper class to determine if a particular point of a window is not obscured
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// by another window.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TopMostFinder : public BaseWindowFinder {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true if |window| is the topmost window at the location
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |screen_loc|, not including the windows in |ignore|.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool IsTopMostWindowAtPoint(HWND window,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const gfx::Point& screen_loc,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const std::set<HWND>& ignore) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TopMostFinder finder(window, screen_loc, ignore);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return finder.is_top_most_;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool ShouldStopIterating(HWND hwnd) {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (hwnd == target_) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Window is topmost, stop iterating.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_top_most_ = true;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!IsWindowVisible(hwnd)) {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The window isn't visible, keep iterating.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RECT r;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!GetWindowRect(hwnd, &r) || !PtInRect(&r, screen_loc_.ToPOINT())) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The window doesn't contain the point, keep iterating.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LONG ex_styles = GetWindowLong(hwnd, GWL_EXSTYLE);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ex_styles & WS_EX_TRANSPARENT || ex_styles & WS_EX_LAYERED) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Mouse events fall through WS_EX_TRANSPARENT windows, so we ignore them.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // WS_EX_LAYERED is trickier. Apps like Switcher create a totally
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // transparent WS_EX_LAYERED window that is always on top. If we don't
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // ignore WS_EX_LAYERED windows and there are totally transparent
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // WS_EX_LAYERED windows then there are effectively holes on the screen
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // that the user can't reattach tabs to. So we ignore them. This is a bit
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // problematic in so far as WS_EX_LAYERED windows need not be totally
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // transparent in which case we treat chrome windows as not being obscured
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // when they really are, but this is better than not being able to
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // reattach tabs.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // hwnd is at the point. Make sure the point is within the windows region.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (GetWindowRgn(hwnd, tmp_region_.Get()) == ERROR) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // There's no region on the window and the window contains the point. Stop
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // iterating.
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The region is relative to the window's rect.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BOOL is_point_in_region = PtInRegion(tmp_region_.Get(),
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        screen_loc_.x() - r.left, screen_loc_.y() - r.top);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tmp_region_ = CreateRectRgn(0, 0, 0, 0);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Stop iterating if the region contains the point.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return !!is_point_in_region;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TopMostFinder(HWND window,
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                const gfx::Point& screen_loc,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                const std::set<HWND>& ignore)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : BaseWindowFinder(ignore),
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        target_(window),
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        screen_loc_(screen_loc),
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        is_top_most_(false),
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tmp_region_(CreateRectRgn(0, 0, 0, 0)) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EnumWindows(WindowCallbackProc, as_lparam());
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The window we're looking for.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HWND target_;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Location of window to find.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point screen_loc_;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Is target_ the top most window? This is initially false but set to true
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in ShouldStopIterating if target_ is passed in.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_top_most_;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedRegion tmp_region_;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TopMostFinder);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// WindowFinder ---------------------------------------------------------------
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper class to determine if a particular point contains a window from our
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// process.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class LocalProcessWindowFinder : public BaseWindowFinder {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the hwnd from our process at screen_loc that is not obscured by
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // another window. Returns NULL otherwise.
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static gfx::NativeWindow GetProcessWindowAtPoint(
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const gfx::Point& screen_loc,
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::set<HWND>& ignore) {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LocalProcessWindowFinder finder(screen_loc, ignore);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Windows 8 has a window that appears first in the list of iterated
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // windows, yet is not visually on top of everything.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(sky): figure out a better way to ignore this window.
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (finder.result_ &&
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ((base::win::OSInfo::GetInstance()->version() >=
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::win::VERSION_WIN8) ||
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         TopMostFinder::IsTopMostWindowAtPoint(finder.result_, screen_loc,
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               ignore))) {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return views::DesktopRootWindowHostWin::GetContentWindowForHWND(
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          finder.result_);
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return finder.result_;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool ShouldStopIterating(HWND hwnd) {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RECT r;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsWindowVisible(hwnd) && GetWindowRect(hwnd, &r) &&
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PtInRect(&r, screen_loc_.ToPOINT())) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result_ = hwnd;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LocalProcessWindowFinder(const gfx::Point& screen_loc,
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           const std::set<HWND>& ignore)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : BaseWindowFinder(ignore),
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        screen_loc_(screen_loc),
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result_(NULL) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc, as_lparam());
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Position of the mouse.
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point screen_loc_;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The resulting window. This is initially null but set to true in
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ShouldStopIterating if an appropriate window is found.
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HWND result_;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(LocalProcessWindowFinder);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DockToWindowFinder ---------------------------------------------------------
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper class for creating a DockInfo from a specified point.
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DockToWindowFinder : public BaseWindowFinder {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the DockInfo for the specified point. If there is no docking
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // position for the specified point the returned DockInfo has a type of NONE.
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static DockInfo GetDockInfoAtPoint(const gfx::Point& screen_loc,
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const std::set<HWND>& ignore) {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DockToWindowFinder finder(screen_loc, ignore);
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    HWND hwnd = views::HWNDForNativeWindow(finder.result_.window());
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!finder.result_.window() ||
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !TopMostFinder::IsTopMostWindowAtPoint(hwnd,
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               finder.result_.hot_spot(),
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               ignore)) {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      finder.result_.set_type(DockInfo::NONE);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return finder.result_;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool ShouldStopIterating(HWND hwnd) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserView* window = BrowserView::GetBrowserViewForNativeWindow(
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        views::DesktopRootWindowHostWin::GetContentWindowForHWND(hwnd));
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserView* window = BrowserView::GetBrowserViewForNativeWindow(hwnd);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RECT bounds;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!window || !IsWindowVisible(hwnd) ||
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !GetWindowRect(hwnd, &bounds)) {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check the three corners we allow docking to. We don't currently allow
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // docking to top of window as it conflicts with docking to the tab strip.
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (CheckPoint(hwnd, bounds.left, (bounds.top + bounds.bottom) / 2,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   DockInfo::LEFT_OF_WINDOW) ||
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CheckPoint(hwnd, bounds.right - 1, (bounds.top + bounds.bottom) / 2,
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   DockInfo::RIGHT_OF_WINDOW) ||
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CheckPoint(hwnd, (bounds.left + bounds.right) / 2, bounds.bottom - 1,
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   DockInfo::BOTTOM_OF_WINDOW)) {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DockToWindowFinder(const gfx::Point& screen_loc,
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const std::set<HWND>& ignore)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : BaseWindowFinder(ignore),
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        screen_loc_(screen_loc) {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Rect work_area = gfx::Screen::GetNativeScreen()->
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetDisplayNearestPoint(screen_loc).bounds();
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!work_area.IsEmpty()) {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result_.set_monitor_bounds(work_area);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc, as_lparam());
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool CheckPoint(HWND hwnd, int x, int y, DockInfo::Type type) {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool in_enable_area;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (DockInfo::IsCloseToPoint(screen_loc_, x, y, &in_enable_area)) {
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result_.set_in_enable_area(in_enable_area);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result_.set_window(
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          views::DesktopRootWindowHostWin::GetContentWindowForHWND(hwnd));
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result_.set_window(hwnd);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result_.set_type(type);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result_.set_hot_spot(gfx::Point(x, y));
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Only show the hotspot if the monitor contains the bounds of the popup
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // window. Otherwise we end with a weird situation where the popup window
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // isn't completely visible.
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return result_.monitor_bounds().Contains(result_.GetPopupRect());
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The location to look for.
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point screen_loc_;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The resulting DockInfo.
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DockInfo result_;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(DockToWindowFinder);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::set<HWND> RemapIgnoreSet(const std::set<gfx::NativeView>& ignore) {
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA)
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::set<HWND> hwnd_set;
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::set<gfx::NativeView>::const_iterator it = ignore.begin();
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (; it != ignore.end(); ++it) {
307f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    HWND w = (*it)->GetDispatcher()->host()->GetAcceleratedWidget();
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (w)
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      hwnd_set.insert(w);
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return hwnd_set;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NativeViews are already HWNDs on non-Aura Windows.
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ignore;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DockInfo -------------------------------------------------------------------
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DockInfo DockInfo::GetDockInfoAtPoint(chrome::HostDesktopType host_desktop_type,
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const gfx::Point& screen_point,
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const std::set<gfx::NativeView>& ignore) {
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (host_desktop_type == chrome::HOST_DESKTOP_TYPE_ASH)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return chrome::ash::GetDockInfoAtPointAsh(screen_point, ignore);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try docking to a window first.
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DockInfo info = DockToWindowFinder::GetDockInfoAtPoint(
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      screen_point, RemapIgnoreSet(ignore));
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (info.type() != DockInfo::NONE)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return info;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No window relative positions. Try monitor relative positions.
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::Rect& m_bounds = info.monitor_bounds();
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int mid_x = m_bounds.x() + m_bounds.width() / 2;
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int mid_y = m_bounds.y() + m_bounds.height() / 2;
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool result =
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info.CheckMonitorPoint(screen_point, mid_x, m_bounds.y(),
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             DockInfo::MAXIMIZE) ||
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info.CheckMonitorPoint(screen_point, mid_x, m_bounds.bottom(),
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             DockInfo::BOTTOM_HALF) ||
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info.CheckMonitorPoint(screen_point, m_bounds.x(), mid_y,
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             DockInfo::LEFT_HALF) ||
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info.CheckMonitorPoint(screen_point, m_bounds.right(), mid_y,
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             DockInfo::RIGHT_HALF);
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return info;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::NativeView DockInfo::GetLocalProcessWindowAtPoint(
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chrome::HostDesktopType host_desktop_type,
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Point& screen_point,
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::set<gfx::NativeView>& ignore) {
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (host_desktop_type == chrome::HOST_DESKTOP_TYPE_ASH)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return chrome::ash::GetLocalProcessWindowAtPointAsh(screen_point, ignore);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LocalProcessWindowFinder::GetProcessWindowAtPoint(
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          screen_point, RemapIgnoreSet(ignore));
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DockInfo::GetWindowBounds(gfx::Rect* bounds) const {
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!window())
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *bounds = window_->bounds();
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DockInfo::SizeOtherWindowTo(const gfx::Rect& bounds) const {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window_->SetBounds(bounds);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else  // USE_AURA
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DockInfo::GetWindowBounds(gfx::Rect* bounds) const {
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RECT window_rect;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!window() || !GetWindowRect(window(), &window_rect))
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *bounds = gfx::Rect(window_rect);
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DockInfo::SizeOtherWindowTo(const gfx::Rect& bounds) const {
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsZoomed(window())) {
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We're docking relative to another window, we need to make sure the
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // window we're docking to isn't maximized.
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ShowWindow(window(), SW_RESTORE | SW_SHOWNA);
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetWindowPos(window(), HWND_TOP, bounds.x(), bounds.y(), bounds.width(),
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               bounds.height(), SWP_NOACTIVATE | SWP_NOOWNERZORDER);
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int DockInfo::GetHotSpotDeltaY() {
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Tab::GetMinimumUnselectedSize().height() - 1;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // !USE_AURA
406