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