window_finder_x11.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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/debug/trace_event.h"
8#include "chrome/browser/ui/host_desktop.h"
9#include "ui/aura/window.h"
10#include "ui/aura/window_tree_host.h"
11#include "ui/base/x/x11_util.h"
12#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
13
14#if defined(USE_ASH)
15aura::Window* GetLocalProcessWindowAtPointAsh(
16    const gfx::Point& screen_point,
17    const std::set<aura::Window*>& ignore);
18#endif
19
20namespace {
21
22////////////////////////////////////////////////////////////////////////////////
23// BaseWindowFinder
24//
25// Base class used to locate a window. A subclass need only override
26// ShouldStopIterating to determine when iteration should stop.
27class BaseWindowFinder : public ui::EnumerateWindowsDelegate {
28 public:
29  explicit BaseWindowFinder(const std::set<aura::Window*>& ignore) {
30    std::set<aura::Window*>::iterator iter;
31    for (iter = ignore.begin(); iter != ignore.end(); iter++) {
32      XID xid = (*iter)->GetHost()->GetAcceleratedWidget();
33      ignore_.insert(xid);
34    }
35  }
36
37  virtual ~BaseWindowFinder() {}
38
39 protected:
40  // Returns true if |window| is in the ignore list.
41  bool ShouldIgnoreWindow(XID window) {
42    return (ignore_.find(window) != ignore_.end());
43  }
44
45  // Returns true if iteration should stop, false otherwise.
46  virtual bool ShouldStopIterating(XID window) OVERRIDE {
47    return false;
48  }
49
50 private:
51  std::set<XID> ignore_;
52
53  DISALLOW_COPY_AND_ASSIGN(BaseWindowFinder);
54};
55
56////////////////////////////////////////////////////////////////////////////////
57// TopMostFinder
58//
59// Helper class to determine if a particular point of a window is not obscured
60// by another window.
61class TopMostFinder : public BaseWindowFinder {
62 public:
63  // Returns true if |window| is not obscured by another window at the
64  // location |screen_loc|, not including the windows in |ignore|.
65  static bool IsTopMostWindowAtPoint(XID window,
66                                     const gfx::Point& screen_loc,
67                                     const std::set<aura::Window*>& ignore) {
68    TopMostFinder finder(window, screen_loc, ignore);
69    return finder.is_top_most_;
70  }
71
72 protected:
73  virtual bool ShouldStopIterating(XID window) OVERRIDE {
74    if (BaseWindowFinder::ShouldIgnoreWindow(window))
75      return false;
76
77    if (window == target_) {
78      // Window is topmost, stop iterating.
79      is_top_most_ = true;
80      return true;
81    }
82
83    if (!ui::IsWindowVisible(window)) {
84      // The window isn't visible, keep iterating.
85      return false;
86    }
87
88    // At this point we haven't found our target window, so this window is
89    // higher in the z-order than the target window.  If this window contains
90    // the point, then we can stop the search now because this window is
91    // obscuring the target window at this point.
92    return ui::WindowContainsPoint(window, screen_loc_);
93  }
94
95 private:
96  TopMostFinder(XID window,
97                const gfx::Point& screen_loc,
98                const std::set<aura::Window*>& ignore)
99    : BaseWindowFinder(ignore),
100      target_(window),
101      screen_loc_(screen_loc),
102      is_top_most_(false) {
103    ui::EnumerateTopLevelWindows(this);
104  }
105
106  // The window we're looking for.
107  XID target_;
108
109  // Location of window to find.
110  gfx::Point screen_loc_;
111
112  // Is target_ the top most window? This is initially false but set to true
113  // in ShouldStopIterating if target_ is passed in.
114  bool is_top_most_;
115
116  DISALLOW_COPY_AND_ASSIGN(TopMostFinder);
117};
118
119////////////////////////////////////////////////////////////////////////////////
120// LocalProcessWindowFinder
121//
122// Helper class to determine if a particular point of a window from our process
123// is not obscured by another window.
124class LocalProcessWindowFinder : public BaseWindowFinder {
125 public:
126  // Returns the XID from our process at screen_loc that is not obscured by
127  // another window. Returns 0 otherwise.
128  static XID GetProcessWindowAtPoint(const gfx::Point& screen_loc,
129                                     const std::set<aura::Window*>& ignore) {
130    LocalProcessWindowFinder finder(screen_loc, ignore);
131    if (finder.result_ &&
132        TopMostFinder::IsTopMostWindowAtPoint(finder.result_, screen_loc,
133                                              ignore)) {
134      return finder.result_;
135    }
136    return 0;
137  }
138
139 protected:
140  virtual bool ShouldStopIterating(XID window) OVERRIDE {
141    if (BaseWindowFinder::ShouldIgnoreWindow(window))
142      return false;
143
144    // Check if this window is in our process.
145    if (!aura::WindowTreeHost::GetForAcceleratedWidget(window))
146      return false;
147
148    if (!ui::IsWindowVisible(window))
149      return false;
150
151    if (ui::WindowContainsPoint(window, screen_loc_)) {
152      result_ = window;
153      return true;
154    }
155
156    return false;
157  }
158
159 private:
160  LocalProcessWindowFinder(const gfx::Point& screen_loc,
161                           const std::set<aura::Window*>& ignore)
162    : BaseWindowFinder(ignore),
163      screen_loc_(screen_loc),
164      result_(0) {
165    ui::EnumerateTopLevelWindows(this);
166  }
167
168  // Position of the mouse.
169  gfx::Point screen_loc_;
170
171  // The resulting window. This is initially null but set to true in
172  // ShouldStopIterating if an appropriate window is found.
173  XID result_;
174
175  DISALLOW_COPY_AND_ASSIGN(LocalProcessWindowFinder);
176};
177
178}  // namespace
179
180aura::Window* GetLocalProcessWindowAtPoint(
181    chrome::HostDesktopType host_desktop_type,
182    const gfx::Point& screen_point,
183    const std::set<aura::Window*>& ignore) {
184#if defined(USE_ASH)
185  if (host_desktop_type == chrome::HOST_DESKTOP_TYPE_ASH)
186    return GetLocalProcessWindowAtPointAsh(screen_point, ignore);
187#endif
188  // The X11 server is the canonical state of what the window stacking order
189  // is.
190  XID xid =
191      LocalProcessWindowFinder::GetProcessWindowAtPoint(screen_point, ignore);
192  return views::DesktopWindowTreeHostX11::GetContentWindowForXID(xid);
193}
194