diff options
author | rohitrao@chromium.org <rohitrao@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-14 15:24:31 +0000 |
---|---|---|
committer | rohitrao@chromium.org <rohitrao@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-14 15:24:31 +0000 |
commit | 96649a0f3cafe764eb191532f635d99c234ea005 (patch) | |
tree | 4450b4a03d498df44850ef549814a458cbc77be9 /chrome/browser | |
parent | 3313359d46d2a4f0e0dc8c4dc476462dec8c988a (diff) | |
download | chromium_src-96649a0f3cafe764eb191532f635d99c234ea005.zip chromium_src-96649a0f3cafe764eb191532f635d99c234ea005.tar.gz chromium_src-96649a0f3cafe764eb191532f635d99c234ea005.tar.bz2 |
Enable basic saving/restoring window placements on Mac.
Refactors the existing WindowSizer code to move platform-specific code
into separate files. Future CLs will add Mac support for muliple
monitors.
TEST=Browser windows should remember their position on Mac. The
corresponding behavior on Windows should not have changed.
Review URL: http://codereview.chromium.org/113286
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16056 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/browser.cc | 5 | ||||
-rw-r--r-- | chrome/browser/browser.vcproj | 4 | ||||
-rw-r--r-- | chrome/browser/cocoa/browser_window_controller.mm | 51 | ||||
-rw-r--r-- | chrome/browser/cocoa/browser_window_controller_unittest.mm | 53 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_tabs_module.cc | 2 | ||||
-rw-r--r-- | chrome/browser/window_sizer.cc | 106 | ||||
-rw-r--r-- | chrome/browser/window_sizer.h | 45 | ||||
-rw-r--r-- | chrome/browser/window_sizer_mac.mm | 70 | ||||
-rw-r--r-- | chrome/browser/window_sizer_win.cc | 112 |
9 files changed, 327 insertions, 121 deletions
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index dc35140..c59f21e 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -74,10 +74,13 @@ #include "chrome/browser/user_data_manager.h" #include "chrome/browser/view_ids.h" #include "chrome/browser/views/location_bar_view.h" -#include "chrome/browser/window_sizer.h" #include "chrome/common/child_process_host.h" #endif // OS_WIN +#if defined(OS_WIN) || defined(OS_MACOSX) +#include "chrome/browser/window_sizer.h" +#endif + using base::TimeDelta; // How long we wait before updating the browser chrome while loading a page. diff --git a/chrome/browser/browser.vcproj b/chrome/browser/browser.vcproj index 9c7094a..6653ca2 100644 --- a/chrome/browser/browser.vcproj +++ b/chrome/browser/browser.vcproj @@ -825,6 +825,10 @@ RelativePath=".\window_sizer.h" > </File> + <File + RelativePath=".\window_sizer_win.cc" + > + </File> </Filter> <Filter Name="Automation" diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm index 6d87b9d..283eb1e 100644 --- a/chrome/browser/cocoa/browser_window_controller.mm +++ b/chrome/browser/cocoa/browser_window_controller.mm @@ -7,6 +7,7 @@ #include "chrome/app/chrome_dll_resource.h" // IDC_* #include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_contents_view.h" #include "chrome/browser/tabs/tab_strip_model.h" @@ -21,6 +22,7 @@ #import "chrome/browser/cocoa/tab_strip_controller.h" #import "chrome/browser/cocoa/tab_view.h" #import "chrome/browser/cocoa/toolbar_controller.h" +#include "chrome/common/pref_service.h" namespace { @@ -44,6 +46,12 @@ const int kWindowGradientHeight = 24; // frame changes. Re-positions the bookmark bar and the find bar. - (void)tabContentAreaFrameChanged:(id)sender; +// Saves the window's position in the local state preferences. +- (void)saveWindowPositionIfNeeded; + +// Saves the window's position to the given pref service. +- (void)saveWindowPositionToPrefs:(PrefService*)prefs; + // We need to adjust where sheets come out of the window, as by default they // erupt from the omnibox, which is rather weird. - (NSRect)window:(NSWindow *)window @@ -166,7 +174,7 @@ willPositionSheet:(NSWindow *)sheet - (void)windowWillClose:(NSNotification *)notification { DCHECK(!browser_->tabstrip_model()->count()); - // We can't acutally use |-autorelease| here because there's an embedded + // We can't actually use |-autorelease| here because there's an embedded // run loop in the |-performClose:| which contains its own autorelease pool. // Instead we use call it after a zero-length delay, which gets us back // to the main event loop. @@ -187,6 +195,11 @@ willPositionSheet:(NSWindow *)sheet if (!browser_->ShouldCloseWindow()) return NO; + // saveWindowPositionIfNeeded: only works if we are the last active + // window, but orderOut: ends up activating another window, so we + // have to save the window position before we call orderOut:. + [self saveWindowPositionIfNeeded]; + if (!browser_->tabstrip_model()->empty()) { // Tab strip isn't empty. Hide the frame (so it appears to have closed // immediately) and close all the tabs, allowing the renderers to shut @@ -203,6 +216,7 @@ willPositionSheet:(NSWindow *)sheet // Called right after our window became the main window. - (void)windowDidBecomeMain:(NSNotification *)notification { BrowserList::SetLastActive(browser_.get()); + [self saveWindowPositionIfNeeded]; } // Called when the user clicks the zoom button (or selects it from the Window @@ -580,6 +594,41 @@ willPositionSheet:(NSWindow *)sheet } } +- (void)saveWindowPositionIfNeeded { + if (browser_ != BrowserList::GetLastActive()) + return; + + if (!g_browser_process || !g_browser_process->local_state() || + !browser_->ShouldSaveWindowPlacement()) + return; + + [self saveWindowPositionToPrefs:g_browser_process->local_state()]; +} + +- (void)saveWindowPositionToPrefs:(PrefService*)prefs { + // Window placements are stored relative to the work area bounds, + // not the monitor bounds. + NSRect workFrame = [[[self window] screen] visibleFrame]; + + // Start with the window's frame, which is in virtual coordinates. + // Subtract the origin of the visibleFrame to get the window frame + // relative to the work area. + gfx::Rect bounds(NSRectToCGRect([[self window] frame])); + bounds.Offset(-workFrame.origin.x, -workFrame.origin.y); + + // Do some y twiddling to flip the coordinate system. + bounds.set_y(workFrame.size.height - bounds.y() - bounds.height()); + + DictionaryValue* windowPreferences = prefs->GetMutableDictionary( + browser_->GetWindowPlacementKey().c_str()); + windowPreferences->SetInteger(L"left", bounds.x()); + windowPreferences->SetInteger(L"top", bounds.y()); + windowPreferences->SetInteger(L"right", bounds.right()); + windowPreferences->SetInteger(L"bottom", bounds.bottom()); + windowPreferences->SetBoolean(L"maximized", false); + windowPreferences->SetBoolean(L"always_on_top", false); +} + - (NSRect)window:(NSWindow *)window willPositionSheet:(NSWindow *)sheet usingRect:(NSRect)defaultSheetRect { diff --git a/chrome/browser/cocoa/browser_window_controller_unittest.mm b/chrome/browser/cocoa/browser_window_controller_unittest.mm new file mode 100644 index 0000000..0dff06d --- /dev/null +++ b/chrome/browser/cocoa/browser_window_controller_unittest.mm @@ -0,0 +1,53 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/scoped_nsobject.h" +#include "base/scoped_nsautorelease_pool.h" +#include "base/scoped_ptr.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/cocoa/browser_test_helper.h" +#include "chrome/browser/cocoa/browser_window_controller.h" +#include "chrome/browser/cocoa/cocoa_test_helper.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/pref_service.h" +#include "chrome/test/testing_browser_process.h" +#include "testing/gtest/include/gtest/gtest.h" + +@interface BrowserWindowController (ExposedForTesting) +- (void)saveWindowPositionToPrefs:(PrefService*)prefs; +@end + +class BrowserWindowControllerTest : public testing::Test { + virtual void SetUp() { + controller_.reset([[BrowserWindowController alloc] + initWithBrowser:browser_helper_.browser() + takeOwnership:NO]); + } + + public: + // Order is very important here. We want the controller deleted + // before the pool, and want the pool deleted before + // BrowserTestHelper. + CocoaTestHelper cocoa_helper_; + BrowserTestHelper browser_helper_; + base::ScopedNSAutoreleasePool pool_; + scoped_nsobject<BrowserWindowController> controller_; +}; + +TEST_F(BrowserWindowControllerTest, TestSaveWindowPosition) { + PrefService* prefs = browser_helper_.profile()->GetPrefs(); + ASSERT_TRUE(prefs != NULL); + + // Check to make sure there is no existing pref for window placement. + ASSERT_TRUE(prefs->GetDictionary(prefs::kBrowserWindowPlacement) == NULL); + + // Ask the window to save its position, then check that a preference + // exists. We're technically passing in a pointer to the user prefs + // and not the local state prefs, but a PrefService* is a + // PrefService*, and this is a unittest. + [controller_ saveWindowPositionToPrefs:prefs]; + EXPECT_TRUE(prefs->GetDictionary(prefs::kBrowserWindowPlacement) != NULL); +} + +/* TODO(???): test other methods of BrowserWindowController */ diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc index 09415f4..782bfe8 100644 --- a/chrome/browser/extensions/extension_tabs_module.cc +++ b/chrome/browser/extensions/extension_tabs_module.cc @@ -13,7 +13,7 @@ #include "chrome/browser/tab_contents/navigation_entry.h" // TODO(port): Port these files. -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_MACOSX) #include "chrome/browser/window_sizer.h" #else #include "chrome/common/temp_scaffolding_stubs.h" diff --git a/chrome/browser/window_sizer.cc b/chrome/browser/window_sizer.cc index ce34b71..300e5c5 100644 --- a/chrome/browser/window_sizer.cc +++ b/chrome/browser/window_sizer.cc @@ -1,13 +1,9 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/window_sizer.h" -#include <atlbase.h> -#include <atlapp.h> -#include <atlmisc.h> - #include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_process.h" @@ -15,73 +11,10 @@ #include "chrome/common/pref_names.h" #include "chrome/common/pref_service.h" -// How much horizontal and vertical offset there is between newly opened -// windows. -static const int kWindowTilePixels = 10; - -/////////////////////////////////////////////////////////////////////////////// -// An implementation of WindowSizer::MonitorInfoProvider that gets the actual -// monitor information from Windows. -class DefaultMonitorInfoProvider : public WindowSizer::MonitorInfoProvider { - public: - DefaultMonitorInfoProvider() { } - - // Overridden from WindowSizer::MonitorInfoProvider: - virtual gfx::Rect GetPrimaryMonitorWorkArea() const { - return gfx::Rect(GetMonitorInfoForMonitor(MonitorFromWindow(NULL, - MONITOR_DEFAULTTOPRIMARY)).rcWork); - } - - virtual gfx::Rect GetPrimaryMonitorBounds() const { - return gfx::Rect(GetMonitorInfoForMonitor(MonitorFromWindow(NULL, - MONITOR_DEFAULTTOPRIMARY)).rcMonitor); - } - - virtual gfx::Rect GetMonitorWorkAreaMatching( - const gfx::Rect& match_rect) const { - CRect other_bounds_crect = match_rect.ToRECT(); - MONITORINFO monitor_info = GetMonitorInfoForMonitor(MonitorFromRect( - &other_bounds_crect, MONITOR_DEFAULTTONEAREST)); - return gfx::Rect(monitor_info.rcWork); - } - - virtual gfx::Point GetBoundsOffsetMatching( - const gfx::Rect& match_rect) const { - CRect other_bounds_crect = match_rect.ToRECT(); - MONITORINFO monitor_info = GetMonitorInfoForMonitor(MonitorFromRect( - &other_bounds_crect, MONITOR_DEFAULTTONEAREST)); - return gfx::Point(monitor_info.rcWork.left - monitor_info.rcMonitor.left, - monitor_info.rcWork.top - monitor_info.rcMonitor.top); - } - - void UpdateWorkAreas() { - work_areas_.clear(); - EnumDisplayMonitors(NULL, NULL, - &DefaultMonitorInfoProvider::MonitorEnumProc, - reinterpret_cast<LPARAM>(&work_areas_)); - } - - private: - // A callback for EnumDisplayMonitors that records the work area of the - // current monitor in the enumeration. - static BOOL CALLBACK MonitorEnumProc(HMONITOR monitor, - HDC monitor_dc, - LPRECT monitor_rect, - LPARAM data) { - reinterpret_cast<std::vector<gfx::Rect>*>(data)->push_back( - gfx::Rect(GetMonitorInfoForMonitor(monitor).rcWork)); - return TRUE; - } - - static MONITORINFO GetMonitorInfoForMonitor(HMONITOR monitor) { - MONITORINFO monitor_info = { 0 }; - monitor_info.cbSize = sizeof(monitor_info); - GetMonitorInfo(monitor, &monitor_info); - return monitor_info; - } - - DISALLOW_COPY_AND_ASSIGN(DefaultMonitorInfoProvider); -}; +// TODO(port): Port this to Linux. +// This requires creating window_sizer_linux.cc, creating a subclass +// of WindowSizer::MonitorInfoProvider, and providing implementations +// of GetDefaultMonitorInfoProvider() and GetDefaultPopupOrigin(). /////////////////////////////////////////////////////////////////////////////// // An implementation of WindowSizer::StateProvider that gets the last active @@ -184,41 +117,16 @@ void WindowSizer::GetBrowserWindowBounds(const std::wstring& app_name, gfx::Rect* window_bounds, bool* maximized) { const WindowSizer sizer(new DefaultStateProvider(app_name, browser), - new DefaultMonitorInfoProvider); + CreateDefaultMonitorInfoProvider()); sizer.DetermineWindowBounds(specified_bounds, window_bounds, maximized); } -gfx::Point WindowSizer::GetDefaultPopupOrigin(const gfx::Size& size) { - RECT area; - SystemParametersInfo(SPI_GETWORKAREA, 0, &area, 0); - gfx::Point corner(area.left, area.top); - - if (Browser* b = BrowserList::GetLastActive()) { - RECT browser; - HWND window = reinterpret_cast<HWND>(b->window()->GetNativeHandle()); - if (GetWindowRect(window, &browser)) { - // Limit to not overflow the work area right and bottom edges. - gfx::Point limit( - std::min(browser.left + kWindowTilePixels, area.right-size.width()), - std::min(browser.top + kWindowTilePixels, area.bottom-size.height()) - ); - // Adjust corner to now overflow the work area left and top edges, so - // that if a popup does not fit the title-bar is remains visible. - corner = gfx::Point( - std::max(corner.x(), limit.x()), - std::max(corner.y(), limit.y()) - ); - } - } - return corner; -} - /////////////////////////////////////////////////////////////////////////////// // WindowSizer, private: WindowSizer::WindowSizer(const std::wstring& app_name) { Init(new DefaultStateProvider(app_name, NULL), - new DefaultMonitorInfoProvider); + CreateDefaultMonitorInfoProvider()); } void WindowSizer::Init(StateProvider* state_provider, diff --git a/chrome/browser/window_sizer.h b/chrome/browser/window_sizer.h index 5153f6d..d1db1db 100644 --- a/chrome/browser/window_sizer.h +++ b/chrome/browser/window_sizer.h @@ -1,9 +1,9 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_WINDOW_SIZER_H__ -#define CHROME_BROWSER_WINDOW_SIZER_H__ +#ifndef CHROME_BROWSER_WINDOW_SIZER_H_ +#define CHROME_BROWSER_WINDOW_SIZER_H_ #include <vector> @@ -33,6 +33,10 @@ class WindowSizer { MonitorInfoProvider* monitor_info_provider); virtual ~WindowSizer(); + // Static factory methods to create default MonitorInfoProvider + // instances. The returned object is owned by the caller. + static MonitorInfoProvider* CreateDefaultMonitorInfoProvider(); + // An interface implemented by an object that can retrieve information about // the monitors on the system. class MonitorInfoProvider { @@ -92,20 +96,6 @@ class WindowSizer { virtual bool GetLastActiveWindowState(gfx::Rect* bounds) const = 0; }; - // Determines the size, position and maximized state for the browser window. - // See documentation for DetermineWindowBounds below. Normally, - // |window_bounds| is calculated by calling GetLastActiveWindowState(). To - // explicitly specify a particular window to base the bounds on, pass in a - // non-NULL value for |browser|. - static void GetBrowserWindowBounds(const std::wstring& app_name, - const gfx::Rect& specified_bounds, - Browser* browser, - gfx::Rect* window_bounds, - bool* maximized); - - // Returns the default origin for popups of the given size. - static gfx::Point GetDefaultPopupOrigin(const gfx::Size& size); - // Determines the position, size and maximized state for a window as it is // created. This function uses several strategies to figure out optimal size // and placement, first looking for an existing active window, then falling @@ -121,6 +111,24 @@ class WindowSizer { gfx::Rect* bounds, bool* maximized) const; + // Determines the size, position and maximized state for the browser window. + // See documentation for DetermineWindowBounds below. Normally, + // |window_bounds| is calculated by calling GetLastActiveWindowState(). To + // explicitly specify a particular window to base the bounds on, pass in a + // non-NULL value for |browser|. + static void GetBrowserWindowBounds(const std::wstring& app_name, + const gfx::Rect& specified_bounds, + Browser* browser, + gfx::Rect* window_bounds, + bool* maximized); + + // Returns the default origin for popups of the given size. + static gfx::Point GetDefaultPopupOrigin(const gfx::Size& size); + + // How much horizontal and vertical offset there is between newly + // opened windows. This value may be different on each platform. + static const int kWindowTilePixels; + private: // The edge of the screen to check for out-of-bounds. enum Edge { TOP, LEFT, BOTTOM, RIGHT }; @@ -165,5 +173,4 @@ class WindowSizer { DISALLOW_EVIL_CONSTRUCTORS(WindowSizer); }; - -#endif // #ifndef CHROME_BROWSER_WINDOW_SIZER_H__ +#endif // #ifndef CHROME_BROWSER_WINDOW_SIZER_H_ diff --git a/chrome/browser/window_sizer_mac.mm b/chrome/browser/window_sizer_mac.mm new file mode 100644 index 0000000..8ff0223 --- /dev/null +++ b/chrome/browser/window_sizer_mac.mm @@ -0,0 +1,70 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <Cocoa/Cocoa.h> + +#include "chrome/browser/window_sizer.h" + +// How much horizontal and vertical offset there is between newly +// opened windows. +const int WindowSizer::kWindowTilePixels = 22; + +class DefaultMonitorInfoProvider : public WindowSizer::MonitorInfoProvider { + public: + DefaultMonitorInfoProvider() { } + + // Overridden from WindowSizer::MonitorInfoProvider: + virtual gfx::Rect GetPrimaryMonitorWorkArea() const { + // Primary monitor is defined as the monitor with the menubar, + // which is always at index 0. + NSScreen* primary = [[NSScreen screens] objectAtIndex:0]; + NSRect frame = [primary frame]; + NSRect visible_frame = [primary visibleFrame]; + + // Convert coordinate systems. + gfx::Rect rect = gfx::Rect(NSRectToCGRect(visible_frame)); + rect.set_y(frame.size.height - + visible_frame.origin.y - visible_frame.size.height); + return rect; + } + + virtual gfx::Rect GetPrimaryMonitorBounds() const { + // Primary monitor is defined as the monitor with the menubar, + // which is always at index 0. + NSScreen* primary = [[NSScreen screens] objectAtIndex:0]; + return gfx::Rect(NSRectToCGRect([primary frame])); + } + + virtual gfx::Rect GetMonitorWorkAreaMatching( + const gfx::Rect& match_rect) const { + // TODO(rohitrao): Support multiple monitors. + return GetPrimaryMonitorWorkArea(); + } + + virtual gfx::Point GetBoundsOffsetMatching( + const gfx::Rect& match_rect) const { + // TODO(rohitrao): Support multiple monitors. + return GetPrimaryMonitorWorkArea().origin(); + } + + void UpdateWorkAreas() { + // TODO(rohitrao): Support multiple monitors. + work_areas_.clear(); + work_areas_.push_back(GetPrimaryMonitorWorkArea()); + } + + private: + DISALLOW_COPY_AND_ASSIGN(DefaultMonitorInfoProvider); +}; + +// static +WindowSizer::MonitorInfoProvider* +WindowSizer::CreateDefaultMonitorInfoProvider() { + return new DefaultMonitorInfoProvider(); +} + +// static +gfx::Point WindowSizer::GetDefaultPopupOrigin(const gfx::Size& size) { + return gfx::Point(0, 0); +} diff --git a/chrome/browser/window_sizer_win.cc b/chrome/browser/window_sizer_win.cc new file mode 100644 index 0000000..249af74 --- /dev/null +++ b/chrome/browser/window_sizer_win.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/window_sizer.h" + +#include <atlbase.h> +#include <atlapp.h> +#include <atlmisc.h> + +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/browser_window.h" + +// How much horizontal and vertical offset there is between newly +// opened windows. +const int WindowSizer::kWindowTilePixels = 10; + +// An implementation of WindowSizer::MonitorInfoProvider that gets the actual +// monitor information from Windows. +class DefaultMonitorInfoProvider : public WindowSizer::MonitorInfoProvider { + public: + DefaultMonitorInfoProvider() { } + + // Overridden from WindowSizer::MonitorInfoProvider: + virtual gfx::Rect GetPrimaryMonitorWorkArea() const { + return gfx::Rect(GetMonitorInfoForMonitor(MonitorFromWindow(NULL, + MONITOR_DEFAULTTOPRIMARY)).rcWork); + } + + virtual gfx::Rect GetPrimaryMonitorBounds() const { + return gfx::Rect(GetMonitorInfoForMonitor(MonitorFromWindow(NULL, + MONITOR_DEFAULTTOPRIMARY)).rcMonitor); + } + + virtual gfx::Rect GetMonitorWorkAreaMatching( + const gfx::Rect& match_rect) const { + CRect other_bounds_crect = match_rect.ToRECT(); + MONITORINFO monitor_info = GetMonitorInfoForMonitor(MonitorFromRect( + &other_bounds_crect, MONITOR_DEFAULTTONEAREST)); + return gfx::Rect(monitor_info.rcWork); + } + + virtual gfx::Point GetBoundsOffsetMatching( + const gfx::Rect& match_rect) const { + CRect other_bounds_crect = match_rect.ToRECT(); + MONITORINFO monitor_info = GetMonitorInfoForMonitor(MonitorFromRect( + &other_bounds_crect, MONITOR_DEFAULTTONEAREST)); + return gfx::Point(monitor_info.rcWork.left - monitor_info.rcMonitor.left, + monitor_info.rcWork.top - monitor_info.rcMonitor.top); + } + + void UpdateWorkAreas() { + work_areas_.clear(); + EnumDisplayMonitors(NULL, NULL, + &DefaultMonitorInfoProvider::MonitorEnumProc, + reinterpret_cast<LPARAM>(&work_areas_)); + } + + private: + // A callback for EnumDisplayMonitors that records the work area of the + // current monitor in the enumeration. + static BOOL CALLBACK MonitorEnumProc(HMONITOR monitor, + HDC monitor_dc, + LPRECT monitor_rect, + LPARAM data) { + reinterpret_cast<std::vector<gfx::Rect>*>(data)->push_back( + gfx::Rect(GetMonitorInfoForMonitor(monitor).rcWork)); + return TRUE; + } + + static MONITORINFO GetMonitorInfoForMonitor(HMONITOR monitor) { + MONITORINFO monitor_info = { 0 }; + monitor_info.cbSize = sizeof(monitor_info); + GetMonitorInfo(monitor, &monitor_info); + return monitor_info; + } + + DISALLOW_COPY_AND_ASSIGN(DefaultMonitorInfoProvider); +}; + +// static +WindowSizer::MonitorInfoProvider* +WindowSizer::CreateDefaultMonitorInfoProvider() { + return new DefaultMonitorInfoProvider(); +} + +// static +gfx::Point WindowSizer::GetDefaultPopupOrigin(const gfx::Size& size) { + RECT area; + SystemParametersInfo(SPI_GETWORKAREA, 0, &area, 0); + gfx::Point corner(area.left, area.top); + + if (Browser* b = BrowserList::GetLastActive()) { + RECT browser; + HWND window = reinterpret_cast<HWND>(b->window()->GetNativeHandle()); + if (GetWindowRect(window, &browser)) { + // Limit to not overflow the work area right and bottom edges. + gfx::Point limit( + std::min(browser.left + kWindowTilePixels, area.right-size.width()), + std::min(browser.top + kWindowTilePixels, area.bottom-size.height()) + ); + // Adjust corner to now overflow the work area left and top edges, so + // that if a popup does not fit the title-bar is remains visible. + corner = gfx::Point( + std::max(corner.x(), limit.x()), + std::max(corner.y(), limit.y()) + ); + } + } + return corner; +} |