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