Fixing build: GetViewContainer changed name from under me. :)
[chromium-blink-merge.git] / chrome / browser / window_sizer.cc
blob8535277a9dd31a7970da9d0e04574eeca8437aef
1 // Copyright (c) 2006-2008 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.
5 #include "chrome/browser/window_sizer.h"
7 #include "chrome/browser/browser.h"
8 #include "chrome/browser/browser_list.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/browser_type.h"
11 #include "chrome/browser/browser_window.h"
12 #include "chrome/common/pref_names.h"
13 #include "chrome/common/pref_service.h"
15 // How much horizontal and vertical offset there is between newly opened
16 // windows.
17 static const int kWindowTilePixels = 10;
19 ///////////////////////////////////////////////////////////////////////////////
20 // An implementation of WindowSizer::MonitorInfoProvider that gets the actual
21 // monitor information from Windows.
22 class DefaultMonitorInfoProvider : public WindowSizer::MonitorInfoProvider {
23 public:
24 DefaultMonitorInfoProvider() {
25 EnumDisplayMonitors(NULL, NULL,
26 &DefaultMonitorInfoProvider::MonitorEnumProc,
27 reinterpret_cast<LPARAM>(&working_rects_));
30 // Overridden from WindowSizer::MonitorInfoProvider:
31 virtual gfx::Rect GetPrimaryMonitorWorkingRect() const {
32 HMONITOR monitor = MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY);
33 MONITORINFO monitor_info;
34 monitor_info.cbSize = sizeof(monitor_info);
35 GetMonitorInfo(monitor, &monitor_info);
36 return gfx::Rect(monitor_info.rcWork);
39 virtual gfx::Rect GetPrimaryMonitorBounds() const {
40 HMONITOR monitor = MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY);
41 MONITORINFO monitor_info;
42 monitor_info.cbSize = sizeof(monitor_info);
43 GetMonitorInfo(monitor, &monitor_info);
44 return gfx::Rect(monitor_info.rcMonitor);
47 virtual gfx::Rect GetMonitorBoundsMatching(
48 const gfx::Rect& match_rect) const {
49 CRect other_bounds_crect = match_rect.ToRECT();
50 HMONITOR monitor =
51 MonitorFromRect(&other_bounds_crect, MONITOR_DEFAULTTOPRIMARY);
52 MONITORINFO monitor_info;
53 monitor_info.cbSize = sizeof(monitor_info);
54 GetMonitorInfo(monitor, &monitor_info);
55 return gfx::Rect(monitor_info.rcWork);
58 virtual gfx::Point GetBoundsOffsetMatching(
59 const gfx::Rect& match_rect) const {
60 CRect other_bounds_crect = match_rect.ToRECT();
61 HMONITOR monitor =
62 MonitorFromRect(&other_bounds_crect, MONITOR_DEFAULTTOPRIMARY);
63 MONITORINFO monitor_info;
64 monitor_info.cbSize = sizeof(monitor_info);
65 GetMonitorInfo(monitor, &monitor_info);
66 return gfx::Point(monitor_info.rcWork.left - monitor_info.rcMonitor.left,
67 monitor_info.rcWork.top - monitor_info.rcMonitor.top);
70 virtual int GetMonitorCount() const {
71 return static_cast<int>(working_rects_.size());
74 virtual gfx::Rect GetWorkingRectAt(int index) const {
75 DCHECK(index >= 0 && index < GetMonitorCount());
76 return working_rects_.at(index);
79 private:
80 // A callback for EnumDisplayMonitors that records the work area of the
81 // current monitor in the enumeration.
82 static BOOL CALLBACK MonitorEnumProc(HMONITOR monitor,
83 HDC monitor_dc,
84 LPRECT monitor_rect,
85 LPARAM data) {
86 std::vector<gfx::Rect>* working_rects =
87 reinterpret_cast<std::vector<gfx::Rect>*>(data);
88 MONITORINFO info;
89 info.cbSize = sizeof(info);
90 GetMonitorInfo(monitor, &info);
91 working_rects->push_back(gfx::Rect(info.rcWork));
92 return TRUE;
95 std::vector<gfx::Rect> working_rects_;
97 DISALLOW_EVIL_CONSTRUCTORS(DefaultMonitorInfoProvider);
100 ///////////////////////////////////////////////////////////////////////////////
101 // An implementation of WindowSizer::StateProvider that gets the last active
102 // and persistent state from the browser window and the user's profile.
103 class DefaultStateProvider : public WindowSizer::StateProvider {
104 public:
105 explicit DefaultStateProvider(const std::wstring& app_name)
106 : app_name_(app_name) {
109 // Overridden from WindowSizer::StateProvider:
110 virtual bool GetPersistentState(gfx::Rect* bounds, bool* maximized) const {
111 DCHECK(bounds && maximized);
113 std::wstring key(prefs::kBrowserWindowPlacement);
114 if (!app_name_.empty()) {
115 key.append(L"_");
116 key.append(app_name_);
119 const DictionaryValue* wp_pref =
120 g_browser_process->local_state()->GetDictionary(key.c_str());
121 int top = 0, left = 0, bottom = 0, right = 0;
122 bool has_prefs =
123 wp_pref &&
124 wp_pref->GetInteger(L"top", &top) &&
125 wp_pref->GetInteger(L"left", &left) &&
126 wp_pref->GetInteger(L"bottom", &bottom) &&
127 wp_pref->GetInteger(L"right", &right) &&
128 wp_pref->GetBoolean(L"maximized", maximized);
129 bounds->SetRect(left, top, std::max(0, right - left),
130 std::max(0, bottom - top));
131 return has_prefs;
134 virtual bool GetLastActiveWindowState(gfx::Rect* bounds) const {
135 // Applications are always restored with the same position.
136 if (!app_name_.empty())
137 return false;
139 BrowserList::const_reverse_iterator it = BrowserList::begin_last_active();
140 BrowserList::const_reverse_iterator end = BrowserList::end_last_active();
141 for (; it != end; ++it) {
142 Browser* last_active = *it;
143 if (last_active &&
144 last_active->GetType() == BrowserType::TABBED_BROWSER) {
145 BrowserWindow* frame = last_active->window();
146 DCHECK(frame);
147 *bounds = frame->GetNormalBounds();
148 return true;
152 return false;
155 private:
156 std::wstring app_name_;
158 DISALLOW_EVIL_CONSTRUCTORS(DefaultStateProvider);
161 ///////////////////////////////////////////////////////////////////////////////
162 // WindowSizer, public:
164 WindowSizer::WindowSizer(
165 StateProvider* state_provider,
166 MonitorInfoProvider* monitor_info_provider) {
167 Init(state_provider, monitor_info_provider);
170 WindowSizer::~WindowSizer() {
171 if (state_provider_)
172 delete state_provider_;
173 if (monitor_info_provider_)
174 delete monitor_info_provider_;
177 // static
178 void WindowSizer::GetBrowserWindowBounds(const std::wstring& app_name,
179 const gfx::Rect& specified_bounds,
180 gfx::Rect* window_bounds,
181 bool* maximized) {
182 const WindowSizer sizer(new DefaultStateProvider(app_name),
183 new DefaultMonitorInfoProvider);
184 sizer.DetermineWindowBounds(specified_bounds, window_bounds, maximized);
188 ///////////////////////////////////////////////////////////////////////////////
189 // WindowSizer, private:
191 WindowSizer::WindowSizer(const std::wstring& app_name) {
192 Init(new DefaultStateProvider(app_name),
193 new DefaultMonitorInfoProvider);
196 void WindowSizer::Init(StateProvider* state_provider,
197 MonitorInfoProvider* monitor_info_provider) {
198 state_provider_ = state_provider;
199 monitor_info_provider_ = monitor_info_provider;
202 void WindowSizer::DetermineWindowBounds(const gfx::Rect& specified_bounds,
203 gfx::Rect* bounds,
204 bool* maximized) const {
205 *bounds = specified_bounds;
206 if (bounds->IsEmpty()) {
207 // See if there's saved placement information.
208 *maximized = false; // Default off; GetSavedWindowBounds() may set this.
209 if (!GetLastWindowBounds(bounds)) {
210 if (!GetSavedWindowBounds(bounds, maximized)) {
211 // No saved placement, figure out some sensible default size based on
212 // the user's screen size.
213 GetDefaultWindowBounds(bounds);
219 bool WindowSizer::GetLastWindowBounds(gfx::Rect* bounds) const {
220 DCHECK(bounds);
221 if (!state_provider_ || !state_provider_->GetLastActiveWindowState(bounds))
222 return false;
223 gfx::Rect last_window_bounds = *bounds;
224 bounds->Offset(kWindowTilePixels, kWindowTilePixels);
225 AdjustBoundsToBeVisibleOnMonitorContaining(last_window_bounds, bounds);
226 return true;
229 bool WindowSizer::GetSavedWindowBounds(gfx::Rect* bounds,
230 bool* maximized) const {
231 DCHECK(bounds && maximized);
232 if (!state_provider_ ||
233 !state_provider_->GetPersistentState(bounds, maximized))
234 return false;
235 const gfx::Point& taskbar_offset =
236 monitor_info_provider_->GetBoundsOffsetMatching(*bounds);
237 bounds->Offset(taskbar_offset.x(), taskbar_offset.y());
238 AdjustBoundsToBeVisibleOnMonitorContaining(*bounds, bounds);
239 return true;
242 void WindowSizer::GetDefaultWindowBounds(gfx::Rect* default_bounds) const {
243 DCHECK(default_bounds);
244 DCHECK(monitor_info_provider_);
246 gfx::Rect work_rect = monitor_info_provider_->GetPrimaryMonitorWorkingRect();
248 // The default size is either some reasonably wide width, or if the work
249 // area is narrower, then the work area width less some aesthetic padding.
250 int default_width = std::min(work_rect.width() - 2 * kWindowTilePixels, 1050);
251 int default_height = work_rect.height() - 2 * kWindowTilePixels;
253 // For wider aspect ratio displays at higher resolutions, we might size the
254 // window narrower to allow two windows to easily be placed side-by-side.
255 gfx::Rect screen_size = monitor_info_provider_->GetPrimaryMonitorBounds();
256 double width_to_height =
257 static_cast<double>(screen_size.width()) / screen_size.height();
259 // The least wide a screen can be to qualify for the halving described above.
260 static const int kMinScreenWidthForWindowHalving = 1600;
261 // We assume 16:9/10 is a fairly standard indicator of a wide aspect ratio
262 // computer display.
263 if (((width_to_height * 10) >= 16) &&
264 work_rect.width() > kMinScreenWidthForWindowHalving) {
265 // Halve the work area, subtracting aesthetic padding on either side, plus
266 // some more aesthetic padding for spacing between windows.
267 default_width = (work_rect.width() / 2) - 3 * kWindowTilePixels;
269 default_bounds->SetRect(kWindowTilePixels + work_rect.x(),
270 kWindowTilePixels + work_rect.y(),
271 default_width, default_height);
274 bool WindowSizer::PositionIsOffscreen(int position, Edge edge) const {
275 DCHECK(monitor_info_provider_);
277 int monitor_count = monitor_info_provider_->GetMonitorCount();
278 for (int i = 0; i < monitor_count; ++i) {
279 gfx::Rect working_rect = monitor_info_provider_->GetWorkingRectAt(i);
280 switch (edge) {
281 case TOP:
282 if (position >= working_rect.y())
283 return true;
284 break;
285 case LEFT:
286 if (position >= working_rect.x())
287 return true;
288 break;
289 case BOTTOM:
290 if (position <= working_rect.height())
291 return true;
292 break;
293 case RIGHT:
294 if (position <= working_rect.width())
295 return true;
296 break;
299 return false;
302 void WindowSizer::AdjustBoundsToBeVisibleOnMonitorContaining(
303 const gfx::Rect& other_bounds, gfx::Rect* bounds) const {
304 DCHECK(bounds);
305 DCHECK(monitor_info_provider_);
307 // Find the size of the work area of the monitor that intersects the bounds
308 // of the anchor window.
309 gfx::Rect work_area =
310 monitor_info_provider_->GetMonitorBoundsMatching(other_bounds);
312 // If height or width are 0, reset to the default size.
313 gfx::Rect default_bounds;
314 GetDefaultWindowBounds(&default_bounds);
315 if (bounds->height() <= 0)
316 bounds->set_height(default_bounds.height());
317 if (bounds->width() <= 0)
318 bounds->set_width(default_bounds.width());
320 // First determine which screen edge(s) the window is offscreen on.
321 bool top_offscreen = !PositionIsOffscreen(bounds->y(), TOP);
322 bool left_offscreen = !PositionIsOffscreen(bounds->x(), LEFT);
323 bool bottom_offscreen = !PositionIsOffscreen(bounds->bottom(), BOTTOM);
324 bool right_offscreen = !PositionIsOffscreen(bounds->right(), RIGHT);
326 // Bump the window back onto the screen in the direction that it's offscreen.
327 if (bottom_offscreen) {
328 int y = work_area.bottom() - kWindowTilePixels - bounds->height();
329 bounds->set_y(std::max(kWindowTilePixels, y));
331 if (right_offscreen) {
332 int x = work_area.right() - kWindowTilePixels - bounds->width();
333 bounds->set_x(std::max(kWindowTilePixels, x));
335 if (top_offscreen)
336 bounds->set_y(kWindowTilePixels + work_area.y());
337 if (left_offscreen)
338 bounds->set_x(kWindowTilePixels + work_area.x());
340 // Now that we've tried to correct the x/y position to something reasonable,
341 // see if the window is still too tall or wide to fit, and resize it if need
342 // be.
343 if ((bottom_offscreen || top_offscreen) &&
344 bounds->bottom() > work_area.bottom()) {
345 bounds->set_height(work_area.height() - 2 * kWindowTilePixels);
347 if ((left_offscreen || right_offscreen) &&
348 bounds->right() > work_area.right()) {
349 bounds->set_width(work_area.width() - 2 * kWindowTilePixels);