Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / tabs / window_finder_win.cc
1 // Copyright 2014 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 "chrome/browser/ui/views/tabs/window_finder.h"
6
7 #include "base/win/scoped_gdi_object.h"
8 #include "base/win/windows_version.h"
9 #include "ui/aura/window.h"
10 #include "ui/gfx/screen.h"
11 #include "ui/gfx/win/dpi.h"
12 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
13 #include "ui/views/win/hwnd_util.h"
14
15 #if defined(USE_ASH)
16 gfx::NativeWindow GetLocalProcessWindowAtPointAsh(
17     const gfx::Point& screen_point,
18     const std::set<gfx::NativeWindow>& ignore);
19 #endif
20
21 namespace {
22
23 // BaseWindowFinder -----------------------------------------------------------
24
25 // Base class used to locate a window. This is intended to be used with the
26 // various win32 functions that iterate over windows.
27 //
28 // A subclass need only override ShouldStopIterating to determine when
29 // iteration should stop.
30 class BaseWindowFinder {
31  public:
32   // Creates a BaseWindowFinder with the specified set of HWNDs to ignore.
33   explicit BaseWindowFinder(const std::set<HWND>& ignore) : ignore_(ignore) {}
34   virtual ~BaseWindowFinder() {}
35
36  protected:
37   static BOOL CALLBACK WindowCallbackProc(HWND hwnd, LPARAM lParam) {
38     // Cast must match that in as_lparam().
39     BaseWindowFinder* finder = reinterpret_cast<BaseWindowFinder*>(lParam);
40     if (finder->ignore_.find(hwnd) != finder->ignore_.end())
41       return TRUE;
42
43     return finder->ShouldStopIterating(hwnd) ? FALSE : TRUE;
44   }
45
46   LPARAM as_lparam() {
47     // Cast must match that in WindowCallbackProc().
48     return reinterpret_cast<LPARAM>(static_cast<BaseWindowFinder*>(this));
49   }
50
51   // Returns true if iteration should stop, false if iteration should continue.
52   virtual bool ShouldStopIterating(HWND window) = 0;
53
54  private:
55   const std::set<HWND>& ignore_;
56
57   DISALLOW_COPY_AND_ASSIGN(BaseWindowFinder);
58 };
59
60 // TopMostFinder --------------------------------------------------------------
61
62 // Helper class to determine if a particular point of a window is not obscured
63 // by another window.
64 class TopMostFinder : public BaseWindowFinder {
65  public:
66   // Returns true if |window| is the topmost window at the location
67   // |screen_loc|, not including the windows in |ignore|.
68   static bool IsTopMostWindowAtPoint(HWND window,
69                                      const gfx::Point& screen_loc,
70                                      const std::set<HWND>& ignore) {
71     TopMostFinder finder(window, screen_loc, ignore);
72     return finder.is_top_most_;
73   }
74
75   virtual bool ShouldStopIterating(HWND hwnd) {
76     if (hwnd == target_) {
77       // Window is topmost, stop iterating.
78       is_top_most_ = true;
79       return true;
80     }
81
82     if (!IsWindowVisible(hwnd)) {
83       // The window isn't visible, keep iterating.
84       return false;
85     }
86
87     RECT r;
88     if (!GetWindowRect(hwnd, &r) || !PtInRect(&r, screen_loc_.ToPOINT())) {
89       // The window doesn't contain the point, keep iterating.
90       return false;
91     }
92
93     LONG ex_styles = GetWindowLong(hwnd, GWL_EXSTYLE);
94     if (ex_styles & WS_EX_TRANSPARENT || ex_styles & WS_EX_LAYERED) {
95       // Mouse events fall through WS_EX_TRANSPARENT windows, so we ignore them.
96       //
97       // WS_EX_LAYERED is trickier. Apps like Switcher create a totally
98       // transparent WS_EX_LAYERED window that is always on top. If we don't
99       // ignore WS_EX_LAYERED windows and there are totally transparent
100       // WS_EX_LAYERED windows then there are effectively holes on the screen
101       // that the user can't reattach tabs to. So we ignore them. This is a bit
102       // problematic in so far as WS_EX_LAYERED windows need not be totally
103       // transparent in which case we treat chrome windows as not being obscured
104       // when they really are, but this is better than not being able to
105       // reattach tabs.
106       return false;
107     }
108
109     // hwnd is at the point. Make sure the point is within the windows region.
110     if (GetWindowRgn(hwnd, tmp_region_.Get()) == ERROR) {
111       // There's no region on the window and the window contains the point. Stop
112       // iterating.
113       return true;
114     }
115
116     // The region is relative to the window's rect.
117     BOOL is_point_in_region = PtInRegion(tmp_region_.Get(),
118         screen_loc_.x() - r.left, screen_loc_.y() - r.top);
119     tmp_region_ = CreateRectRgn(0, 0, 0, 0);
120     // Stop iterating if the region contains the point.
121     return !!is_point_in_region;
122   }
123
124  private:
125   TopMostFinder(HWND window,
126                 const gfx::Point& screen_loc,
127                 const std::set<HWND>& ignore)
128       : BaseWindowFinder(ignore),
129         target_(window),
130         is_top_most_(false),
131         tmp_region_(CreateRectRgn(0, 0, 0, 0)) {
132     screen_loc_ = gfx::win::DIPToScreenPoint(screen_loc);
133     EnumWindows(WindowCallbackProc, as_lparam());
134   }
135
136   // The window we're looking for.
137   HWND target_;
138
139   // Location of window to find in pixel coordinates.
140   gfx::Point screen_loc_;
141
142   // Is target_ the top most window? This is initially false but set to true
143   // in ShouldStopIterating if target_ is passed in.
144   bool is_top_most_;
145
146   base::win::ScopedRegion tmp_region_;
147
148   DISALLOW_COPY_AND_ASSIGN(TopMostFinder);
149 };
150
151 // WindowFinder ---------------------------------------------------------------
152
153 // Helper class to determine if a particular point contains a window from our
154 // process.
155 class LocalProcessWindowFinder : public BaseWindowFinder {
156  public:
157   // Returns the hwnd from our process at screen_loc that is not obscured by
158   // another window. Returns NULL otherwise.
159   static gfx::NativeWindow GetProcessWindowAtPoint(
160       const gfx::Point& screen_loc,
161       const std::set<HWND>& ignore) {
162     LocalProcessWindowFinder finder(screen_loc, ignore);
163     // Windows 8 has a window that appears first in the list of iterated
164     // windows, yet is not visually on top of everything.
165     // TODO(sky): figure out a better way to ignore this window.
166     if (finder.result_ &&
167         ((base::win::OSInfo::GetInstance()->version() >=
168           base::win::VERSION_WIN8) ||
169          TopMostFinder::IsTopMostWindowAtPoint(finder.result_,
170                                                screen_loc,
171                                                ignore))) {
172       return views::DesktopWindowTreeHostWin::GetContentWindowForHWND(
173           finder.result_);
174     }
175     return NULL;
176   }
177
178  protected:
179   virtual bool ShouldStopIterating(HWND hwnd) {
180     RECT r;
181     if (IsWindowVisible(hwnd) && GetWindowRect(hwnd, &r) &&
182         PtInRect(&r, screen_loc_.ToPOINT())) {
183       result_ = hwnd;
184       return true;
185     }
186     return false;
187   }
188
189  private:
190   LocalProcessWindowFinder(const gfx::Point& screen_loc,
191                            const std::set<HWND>& ignore)
192       : BaseWindowFinder(ignore),
193         result_(NULL) {
194     screen_loc_ = gfx::win::DIPToScreenPoint(screen_loc);
195     EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc, as_lparam());
196   }
197
198   // Position of the mouse in pixel coordinates.
199   gfx::Point screen_loc_;
200
201   // The resulting window. This is initially null but set to true in
202   // ShouldStopIterating if an appropriate window is found.
203   HWND result_;
204
205   DISALLOW_COPY_AND_ASSIGN(LocalProcessWindowFinder);
206 };
207
208 std::set<HWND> RemapIgnoreSet(const std::set<gfx::NativeView>& ignore) {
209   std::set<HWND> hwnd_set;
210   std::set<gfx::NativeView>::const_iterator it = ignore.begin();
211   for (; it != ignore.end(); ++it) {
212     HWND w = (*it)->GetHost()->GetAcceleratedWidget();
213     if (w)
214       hwnd_set.insert(w);
215   }
216   return hwnd_set;
217 }
218
219 }  // namespace
220
221 gfx::NativeWindow GetLocalProcessWindowAtPoint(
222     chrome::HostDesktopType host_desktop_type,
223     const gfx::Point& screen_point,
224     const std::set<gfx::NativeWindow>& ignore) {
225 #if defined(USE_ASH)
226   if (host_desktop_type == chrome::HOST_DESKTOP_TYPE_ASH)
227     return GetLocalProcessWindowAtPointAsh(screen_point, ignore);
228 #endif
229   return LocalProcessWindowFinder::GetProcessWindowAtPoint(
230           screen_point, RemapIgnoreSet(ignore));
231 }