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