• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/tabs/dock_info.h"
6 
7 #include <gtk/gtk.h>
8 
9 #include "base/logging.h"
10 #include "base/task.h"
11 #include "chrome/browser/ui/browser_list.h"
12 #include "chrome/browser/ui/browser_window.h"
13 #include "chrome/browser/ui/gtk/browser_window_gtk.h"
14 #include "chrome/browser/ui/gtk/gtk_util.h"
15 #include "ui/base/x/x11_util.h"
16 #include "ui/gfx/native_widget_types.h"
17 
18 ////////////////////////////////////////////////////////////////////////////////
19 // BaseWindowFinder
20 //
21 // Base class used to locate a window. A subclass need only override
22 // ShouldStopIterating to determine when iteration should stop.
23 class BaseWindowFinder : public ui::EnumerateWindowsDelegate {
24  public:
BaseWindowFinder(const std::set<GtkWidget * > & ignore)25   explicit BaseWindowFinder(const std::set<GtkWidget*>& ignore) {
26     std::set<GtkWidget*>::iterator iter;
27     for (iter = ignore.begin(); iter != ignore.end(); iter++) {
28       XID xid = ui::GetX11WindowFromGtkWidget(*iter);
29       ignore_.insert(xid);
30     }
31   }
32 
~BaseWindowFinder()33   virtual ~BaseWindowFinder() {}
34 
35  protected:
36   // Returns true if |window| is in the ignore list.
ShouldIgnoreWindow(XID window)37   bool ShouldIgnoreWindow(XID window) {
38     return (ignore_.find(window) != ignore_.end());
39   }
40 
41   // Returns true if iteration should stop, false otherwise.
ShouldStopIterating(XID window)42   virtual bool ShouldStopIterating(XID window) {
43     return false;
44   }
45 
46  private:
47   std::set<XID> ignore_;
48 
49   DISALLOW_COPY_AND_ASSIGN(BaseWindowFinder);
50 };
51 
52 ////////////////////////////////////////////////////////////////////////////////
53 // TopMostFinder
54 //
55 // Helper class to determine if a particular point of a window is not obscured
56 // by another window.
57 class TopMostFinder : public BaseWindowFinder {
58  public:
59   // Returns true if |window| is not obscured by another window at the
60   // location |screen_loc|, not including the windows in |ignore|.
IsTopMostWindowAtPoint(XID window,const gfx::Point & screen_loc,const std::set<GtkWidget * > & ignore)61   static bool IsTopMostWindowAtPoint(XID window,
62                                      const gfx::Point& screen_loc,
63                                      const std::set<GtkWidget*>& ignore) {
64     TopMostFinder finder(window, screen_loc, ignore);
65     return finder.is_top_most_;
66   }
67 
68  protected:
ShouldStopIterating(XID window)69   virtual bool ShouldStopIterating(XID window) {
70     if (BaseWindowFinder::ShouldIgnoreWindow(window))
71       return false;
72 
73     if (window == target_) {
74       // Window is topmost, stop iterating.
75       is_top_most_ = true;
76       return true;
77     }
78 
79     if (!ui::IsWindowVisible(window)) {
80       // The window isn't visible, keep iterating.
81       return false;
82     }
83 
84     gfx::Rect rect;
85     if (ui::GetWindowRect(window, &rect) && rect.Contains(screen_loc_)) {
86       // At this point we haven't found our target window, so this window is
87       // higher in the z-order than the target window.  If this window contains
88       // the point, then we can stop the search now because this window is
89       // obscuring the target window at this point.
90       return true;
91     }
92 
93     return false;
94   }
95 
96  private:
TopMostFinder(XID window,const gfx::Point & screen_loc,const std::set<GtkWidget * > & ignore)97   TopMostFinder(XID window,
98                 const gfx::Point& screen_loc,
99                 const std::set<GtkWidget*>& ignore)
100     : BaseWindowFinder(ignore),
101       target_(window),
102       screen_loc_(screen_loc),
103       is_top_most_(false) {
104     gtk_util::EnumerateTopLevelWindows(this);
105   }
106 
107   // The window we're looking for.
108   XID target_;
109 
110   // Location of window to find.
111   gfx::Point screen_loc_;
112 
113   // Is target_ the top most window? This is initially false but set to true
114   // in ShouldStopIterating if target_ is passed in.
115   bool is_top_most_;
116 
117   DISALLOW_COPY_AND_ASSIGN(TopMostFinder);
118 };
119 
120 ////////////////////////////////////////////////////////////////////////////////
121 // LocalProcessWindowFinder
122 //
123 // Helper class to determine if a particular point of a window from our process
124 // is not obscured by another window.
125 class LocalProcessWindowFinder : public BaseWindowFinder {
126  public:
127   // Returns the XID from our process at screen_loc that is not obscured by
128   // another window. Returns 0 otherwise.
GetProcessWindowAtPoint(const gfx::Point & screen_loc,const std::set<GtkWidget * > & ignore)129   static XID GetProcessWindowAtPoint(const gfx::Point& screen_loc,
130                                      const std::set<GtkWidget*>& ignore) {
131     LocalProcessWindowFinder finder(screen_loc, ignore);
132     if (finder.result_ &&
133         TopMostFinder::IsTopMostWindowAtPoint(finder.result_, screen_loc,
134                                               ignore)) {
135       return finder.result_;
136     }
137     return 0;
138   }
139 
140  protected:
ShouldStopIterating(XID window)141   virtual bool ShouldStopIterating(XID window) {
142     if (BaseWindowFinder::ShouldIgnoreWindow(window))
143       return false;
144 
145     // Check if this window is in our process.
146     if (!BrowserWindowGtk::GetBrowserWindowForXID(window))
147       return false;
148 
149     if (!ui::IsWindowVisible(window))
150       return false;
151 
152     gfx::Rect rect;
153     if (ui::GetWindowRect(window, &rect) && rect.Contains(screen_loc_)) {
154       result_ = window;
155       return true;
156     }
157 
158     return false;
159   }
160 
161  private:
LocalProcessWindowFinder(const gfx::Point & screen_loc,const std::set<GtkWidget * > & ignore)162   LocalProcessWindowFinder(const gfx::Point& screen_loc,
163                            const std::set<GtkWidget*>& ignore)
164     : BaseWindowFinder(ignore),
165       screen_loc_(screen_loc),
166       result_(0) {
167     gtk_util::EnumerateTopLevelWindows(this);
168   }
169 
170   // Position of the mouse.
171   gfx::Point screen_loc_;
172 
173   // The resulting window. This is initially null but set to true in
174   // ShouldStopIterating if an appropriate window is found.
175   XID result_;
176 
177   DISALLOW_COPY_AND_ASSIGN(LocalProcessWindowFinder);
178 };
179 
180 // static
GetDockInfoAtPoint(const gfx::Point & screen_point,const std::set<GtkWidget * > & ignore)181 DockInfo DockInfo::GetDockInfoAtPoint(const gfx::Point& screen_point,
182                                       const std::set<GtkWidget*>& ignore) {
183   if (factory_)
184     return factory_->GetDockInfoAtPoint(screen_point, ignore);
185 
186   NOTIMPLEMENTED();
187   return DockInfo();
188 }
189 
190 // static
GetLocalProcessWindowAtPoint(const gfx::Point & screen_point,const std::set<GtkWidget * > & ignore)191 GtkWindow* DockInfo::GetLocalProcessWindowAtPoint(
192     const gfx::Point& screen_point,
193     const std::set<GtkWidget*>& ignore) {
194   if (factory_)
195     return factory_->GetLocalProcessWindowAtPoint(screen_point, ignore);
196 
197 #if defined(OS_CHROMEOS) || defined(TOOLKIT_VIEWS)
198   return NULL;
199 #else
200   XID xid =
201       LocalProcessWindowFinder::GetProcessWindowAtPoint(screen_point, ignore);
202   return BrowserWindowGtk::GetBrowserWindowForXID(xid);
203 #endif
204 }
205 
GetWindowBounds(gfx::Rect * bounds) const206 bool DockInfo::GetWindowBounds(gfx::Rect* bounds) const {
207   if (!window())
208     return false;
209 
210   int x, y, w, h;
211   gtk_window_get_position(window(), &x, &y);
212   gtk_window_get_size(window(), &w, &h);
213   bounds->SetRect(x, y, w, h);
214   return true;
215 }
216 
SizeOtherWindowTo(const gfx::Rect & bounds) const217 void DockInfo::SizeOtherWindowTo(const gfx::Rect& bounds) const {
218   gtk_window_move(window(), bounds.x(), bounds.y());
219   gtk_window_resize(window(), bounds.width(), bounds.height());
220 }
221