Home | History | Annotate | Download | only in tabs
      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