Home | History | Annotate | Download | only in ui
      1 // Copyright (c) 2009 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 #import <Cocoa/Cocoa.h>
      6 #include "chrome/browser/ui/browser.h"
      7 #include "chrome/browser/ui/browser_list.h"
      8 #include "chrome/browser/ui/browser_window.h"
      9 #include "chrome/browser/ui/window_sizer.h"
     10 
     11 
     12 // How much horizontal and vertical offset there is between newly
     13 // opened windows.
     14 const int WindowSizer::kWindowTilePixels = 22;
     15 
     16 namespace {
     17 
     18 class DefaultMonitorInfoProvider : public WindowSizer::MonitorInfoProvider {
     19  public:
     20   DefaultMonitorInfoProvider() { }
     21 
     22   // Overridden from WindowSizer::MonitorInfoProvider:
     23   virtual gfx::Rect GetPrimaryMonitorWorkArea() const  {
     24     // Primary monitor is defined as the monitor with the menubar,
     25     // which is always at index 0.
     26     NSScreen* primary = [[NSScreen screens] objectAtIndex:0];
     27     NSRect frame = [primary frame];
     28     NSRect visible_frame = [primary visibleFrame];
     29 
     30     // Convert coordinate systems.
     31     gfx::Rect rect = gfx::Rect(NSRectToCGRect(visible_frame));
     32     rect.set_y(frame.size.height -
     33                visible_frame.origin.y - visible_frame.size.height);
     34     return rect;
     35   }
     36 
     37   virtual gfx::Rect GetPrimaryMonitorBounds() const  {
     38     // Primary monitor is defined as the monitor with the menubar,
     39     // which is always at index 0.
     40     NSScreen* primary = [[NSScreen screens] objectAtIndex:0];
     41     return gfx::Rect(NSRectToCGRect([primary frame]));
     42   }
     43 
     44   virtual gfx::Rect GetMonitorWorkAreaMatching(
     45       const gfx::Rect& match_rect) const {
     46     NSScreen* match_screen = GetMatchingScreen(match_rect);
     47     return ConvertCoordinateSystem([match_screen visibleFrame]);
     48   }
     49 
     50   virtual gfx::Point GetBoundsOffsetMatching(
     51       const gfx::Rect& match_rect) const {
     52     NSScreen* match_screen = GetMatchingScreen(match_rect);
     53     gfx::Rect bounds = ConvertCoordinateSystem([match_screen frame]);
     54     gfx::Rect work_area = ConvertCoordinateSystem([match_screen visibleFrame]);
     55     return gfx::Point(work_area.x() - bounds.x(), work_area.y() - bounds.y());
     56   }
     57 
     58   virtual void UpdateWorkAreas();
     59 
     60  private:
     61   // Returns a pointer to the screen that most closely matches the
     62   // given |match_rect|.  This function currently returns the screen
     63   // that contains the largest amount of |match_rect| by area.
     64   NSScreen* GetMatchingScreen(const gfx::Rect& match_rect) const {
     65     // Default to the monitor with the current keyboard focus, in case
     66     // |match_rect| is not on any screen at all.
     67     NSScreen* max_screen = [NSScreen mainScreen];
     68     int max_area = 0;
     69 
     70     for (NSScreen* screen in [NSScreen screens]) {
     71       gfx::Rect monitor_area = ConvertCoordinateSystem([screen frame]);
     72       gfx::Rect intersection = monitor_area.Intersect(match_rect);
     73       int area = intersection.width() * intersection.height();
     74       if (area > max_area) {
     75         max_area = area;
     76         max_screen = screen;
     77       }
     78     }
     79 
     80     return max_screen;
     81   }
     82 
     83   // The lower left corner of screen 0 is always at (0, 0).  The
     84   // cross-platform code expects the origin to be in the upper left,
     85   // so we have to translate |ns_rect| to the new coordinate
     86   // system.
     87   gfx::Rect ConvertCoordinateSystem(NSRect ns_rect) const;
     88 
     89   DISALLOW_COPY_AND_ASSIGN(DefaultMonitorInfoProvider);
     90 };
     91 
     92 void DefaultMonitorInfoProvider::UpdateWorkAreas() {
     93   work_areas_.clear();
     94 
     95   for (NSScreen* screen in [NSScreen screens]) {
     96     gfx::Rect rect = ConvertCoordinateSystem([screen visibleFrame]);
     97     work_areas_.push_back(rect);
     98   }
     99 }
    100 
    101 gfx::Rect DefaultMonitorInfoProvider::ConvertCoordinateSystem(
    102     NSRect ns_rect) const {
    103   // Primary monitor is defined as the monitor with the menubar,
    104   // which is always at index 0.
    105   NSScreen* primary_screen = [[NSScreen screens] objectAtIndex:0];
    106   float primary_screen_height = [primary_screen frame].size.height;
    107   gfx::Rect rect(NSRectToCGRect(ns_rect));
    108   rect.set_y(primary_screen_height - rect.y() - rect.height());
    109   return rect;
    110 }
    111 
    112 }  // namespace
    113 
    114 // static
    115 WindowSizer::MonitorInfoProvider*
    116 WindowSizer::CreateDefaultMonitorInfoProvider() {
    117   return new DefaultMonitorInfoProvider();
    118 }
    119 
    120 // static
    121 gfx::Point WindowSizer::GetDefaultPopupOrigin(const gfx::Size& size) {
    122   NSRect work_area = [[NSScreen mainScreen] visibleFrame];
    123   NSRect main_area = [[[NSScreen screens] objectAtIndex:0] frame];
    124   NSPoint corner = NSMakePoint(NSMinX(work_area), NSMaxY(work_area));
    125 
    126   if (Browser* b = BrowserList::GetLastActive()) {
    127     NSWindow* window = b->window()->GetNativeHandle();
    128     NSRect window_frame = [window frame];
    129 
    130     // Limit to not overflow the work area right and bottom edges.
    131     NSPoint limit = NSMakePoint(
    132         std::min(NSMinX(window_frame) + kWindowTilePixels,
    133                  NSMaxX(work_area) - size.width()),
    134         std::max(NSMaxY(window_frame) - kWindowTilePixels,
    135                  NSMinY(work_area) + size.height()));
    136 
    137     // Adjust corner to now overflow the work area left and top edges, so
    138     // that if a popup does not fit the title-bar is remains visible.
    139     corner = NSMakePoint(std::max(corner.x, limit.x),
    140                          std::min(corner.y, limit.y));
    141   }
    142 
    143   return gfx::Point(corner.x, NSHeight(main_area) - corner.y);
    144 }
    145