Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / ui / views / tabs / window_finder_win.cc
blob2596c1888f35fef411b22f461b05a9ef1c421ef9
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.
5 #include "chrome/browser/ui/views/tabs/window_finder.h"
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"
15 #if defined(USE_ASH)
16 gfx::NativeWindow GetLocalProcessWindowAtPointAsh(
17 const gfx::Point& screen_point,
18 const std::set<gfx::NativeWindow>& ignore);
19 #endif
21 namespace {
23 // BaseWindowFinder -----------------------------------------------------------
25 // Base class used to locate a window. This is intended to be used with the
26 // various win32 functions that iterate over windows.
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() {}
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;
43 return finder->ShouldStopIterating(hwnd) ? FALSE : TRUE;
46 LPARAM as_lparam() {
47 // Cast must match that in WindowCallbackProc().
48 return reinterpret_cast<LPARAM>(static_cast<BaseWindowFinder*>(this));
51 // Returns true if iteration should stop, false if iteration should continue.
52 virtual bool ShouldStopIterating(HWND window) = 0;
54 private:
55 const std::set<HWND>& ignore_;
57 DISALLOW_COPY_AND_ASSIGN(BaseWindowFinder);
60 // TopMostFinder --------------------------------------------------------------
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_;
75 bool ShouldStopIterating(HWND hwnd) override {
76 if (hwnd == target_) {
77 // Window is topmost, stop iterating.
78 is_top_most_ = true;
79 return true;
82 if (!IsWindowVisible(hwnd)) {
83 // The window isn't visible, keep iterating.
84 return false;
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;
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.
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;
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;
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;
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());
136 // The window we're looking for.
137 HWND target_;
139 // Location of window to find in pixel coordinates.
140 gfx::Point screen_loc_;
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_;
146 base::win::ScopedRegion tmp_region_;
148 DISALLOW_COPY_AND_ASSIGN(TopMostFinder);
151 // LocalProcessWindowFinder ---------------------------------------------------
153 // Copied from ShObjIdl.h in 10.0.10240.0 SDK. This can be removed once we
154 // update to the newer SDK.
155 #if NTDDI_VERSION < 0x0A000000
156 class DECLSPEC_UUID("aa509086-5ca9-4c25-8f95-589d3c07b48a")
157 VirtualDesktopManager;
159 MIDL_INTERFACE("a5cd92ff-29be-454c-8d04-d82879fb3f1b")
160 IVirtualDesktopManager : public IUnknown {
161 public:
162 virtual HRESULT STDMETHODCALLTYPE IsWindowOnCurrentVirtualDesktop(
163 /* [in] */ __RPC__in HWND topLevelWindow,
164 /* [out] */ __RPC__out BOOL * onCurrentDesktop) = 0;
166 virtual HRESULT STDMETHODCALLTYPE GetWindowDesktopId(
167 /* [in] */ __RPC__in HWND topLevelWindow,
168 /* [out] */ __RPC__out GUID * desktopId) = 0;
170 virtual HRESULT STDMETHODCALLTYPE MoveWindowToDesktop(
171 /* [in] */ __RPC__in HWND topLevelWindow,
172 /* [in] */ __RPC__in REFGUID desktopId) = 0;
174 #endif // NTDDI_VERSION < 0x0A000000
176 // Helper class to determine if a particular point contains a window from our
177 // process.
178 class LocalProcessWindowFinder : public BaseWindowFinder {
179 public:
180 // Returns the hwnd from our process at screen_loc that is not obscured by
181 // another window. Returns NULL otherwise.
182 static gfx::NativeWindow GetProcessWindowAtPoint(
183 const gfx::Point& screen_loc,
184 const std::set<HWND>& ignore) {
185 LocalProcessWindowFinder finder(screen_loc, ignore);
186 // Windows 8 has a window that appears first in the list of iterated
187 // windows, yet is not visually on top of everything.
188 // TODO(sky): figure out a better way to ignore this window.
189 if (finder.result_ &&
190 ((base::win::OSInfo::GetInstance()->version() >=
191 base::win::VERSION_WIN8) ||
192 TopMostFinder::IsTopMostWindowAtPoint(finder.result_,
193 screen_loc,
194 ignore))) {
195 return views::DesktopWindowTreeHostWin::GetContentWindowForHWND(
196 finder.result_);
198 return NULL;
201 protected:
202 bool ShouldStopIterating(HWND hwnd) override {
203 RECT r;
205 // Make sure the window is on the same virtual desktop.
206 if (base::win::GetVersion() >= base::win::VERSION_WIN10) {
207 BOOL on_current_desktop;
208 if (SUCCEEDED(virtual_desktop_manager_->IsWindowOnCurrentVirtualDesktop(
209 hwnd, &on_current_desktop)) &&
210 !on_current_desktop) {
211 return false;
215 if (IsWindowVisible(hwnd) && GetWindowRect(hwnd, &r) &&
216 PtInRect(&r, screen_loc_.ToPOINT())) {
217 result_ = hwnd;
218 return true;
220 return false;
223 private:
224 LocalProcessWindowFinder(const gfx::Point& screen_loc,
225 const std::set<HWND>& ignore)
226 : BaseWindowFinder(ignore),
227 result_(NULL) {
228 if (base::win::GetVersion() >= base::win::VERSION_WIN10) {
229 CHECK(SUCCEEDED(virtual_desktop_manager_.CreateInstance(
230 __uuidof(VirtualDesktopManager))));
232 screen_loc_ = gfx::win::DIPToScreenPoint(screen_loc);
233 EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc, as_lparam());
236 // Position of the mouse in pixel coordinates.
237 gfx::Point screen_loc_;
239 // The resulting window. This is initially null but set to true in
240 // ShouldStopIterating if an appropriate window is found.
241 HWND result_;
243 // Only used on Win10+.
244 base::win::ScopedComPtr<IVirtualDesktopManager> virtual_desktop_manager_;
246 DISALLOW_COPY_AND_ASSIGN(LocalProcessWindowFinder);
249 std::set<HWND> RemapIgnoreSet(const std::set<gfx::NativeView>& ignore) {
250 std::set<HWND> hwnd_set;
251 std::set<gfx::NativeView>::const_iterator it = ignore.begin();
252 for (; it != ignore.end(); ++it) {
253 HWND w = (*it)->GetHost()->GetAcceleratedWidget();
254 if (w)
255 hwnd_set.insert(w);
257 return hwnd_set;
260 } // namespace
262 gfx::NativeWindow GetLocalProcessWindowAtPoint(
263 chrome::HostDesktopType host_desktop_type,
264 const gfx::Point& screen_point,
265 const std::set<gfx::NativeWindow>& ignore) {
266 #if defined(USE_ASH)
267 if (host_desktop_type == chrome::HOST_DESKTOP_TYPE_ASH)
268 return GetLocalProcessWindowAtPointAsh(screen_point, ignore);
269 #endif
270 return LocalProcessWindowFinder::GetProcessWindowAtPoint(
271 screen_point, RemapIgnoreSet(ignore));