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: 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 33 virtual ~BaseWindowFinder() {} 34 35 protected: 36 // Returns true if |window| is in the ignore list. 37 bool ShouldIgnoreWindow(XID window) { 38 return (ignore_.find(window) != ignore_.end()); 39 } 40 41 // Returns true if iteration should stop, false otherwise. 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|. 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: 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: 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. 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: 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: 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 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 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 206 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 217 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