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