window_sizer_ash.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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/window_sizer/window_sizer.h" 6 7#include "ash/ash_switches.h" 8#include "ash/shell.h" 9#include "ash/wm/mru_window_tracker.h" 10#include "ash/wm/window_state.h" 11#include "ash/wm/window_util.h" 12#include "ash/wm/workspace/auto_window_management.h" 13#include "base/command_line.h" 14#include "base/compiler_specific.h" 15#include "chrome/browser/ui/browser.h" 16#include "chrome/browser/ui/browser_list.h" 17#include "chrome/browser/ui/browser_window.h" 18#include "ui/aura/root_window.h" 19#include "ui/aura/window.h" 20#include "ui/aura/window_delegate.h" 21#include "ui/gfx/screen.h" 22 23namespace { 24 25// When a window gets opened in default mode and the screen is less than or 26// equal to this width, the window will get opened in maximized mode. This value 27// can be reduced to a "tame" number if the feature is disabled. 28const int kForceMaximizeWidthLimit = 1366; 29const int kForceMaximizeWidthLimitDisabled = 640; 30 31// Check if the given browser is 'valid': It is a tabbed, non minimized 32// window, which intersects with the |bounds_in_screen| area of a given screen. 33bool IsValidBrowser(Browser* browser, const gfx::Rect& bounds_in_screen) { 34 return (browser && browser->window() && 35 !browser->is_type_popup() && 36 !browser->window()->IsMinimized() && 37 browser->window()->GetNativeWindow() && 38 bounds_in_screen.Intersects( 39 browser->window()->GetNativeWindow()->GetBoundsInScreen())); 40} 41 42// Return the number of valid top level windows on the screen defined by 43// the |bounds_in_screen| rectangle. 44int GetNumberOfValidTopLevelBrowserWindows(const gfx::Rect& bounds_in_screen) { 45 int count = 0; 46 const BrowserList* ash_browser_list = 47 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); 48 for (BrowserList::const_iterator iter = ash_browser_list->begin(); 49 iter != ash_browser_list->end(); 50 ++iter) { 51 if (IsValidBrowser(*iter, bounds_in_screen)) 52 count++; 53 } 54 return count; 55} 56 57// Move the given |bounds_in_screen| on the available |work_area| to the 58// direction. If |move_right| is true, the rectangle gets moved to the right 59// corner. Otherwise to the left side. 60bool MoveRect(const gfx::Rect& work_area, 61 gfx::Rect& bounds_in_screen, 62 bool move_right) { 63 if (move_right) { 64 if (work_area.right() > bounds_in_screen.right()) { 65 bounds_in_screen.set_x(work_area.right() - bounds_in_screen.width()); 66 return true; 67 } 68 } else { 69 if (work_area.x() < bounds_in_screen.x()) { 70 bounds_in_screen.set_x(work_area.x()); 71 return true; 72 } 73 } 74 return false; 75} 76 77} // namespace 78 79// static 80int WindowSizer::GetForceMaximizedWidthLimit() { 81 static int maximum_limit = 0; 82 if (!maximum_limit) { 83 maximum_limit = CommandLine::ForCurrentProcess()->HasSwitch( 84 ash::switches::kAshDisableAutoMaximizing) ? 85 kForceMaximizeWidthLimitDisabled : kForceMaximizeWidthLimit; 86 } 87 return maximum_limit; 88} 89 90void WindowSizer::GetTabbedBrowserBoundsAsh( 91 gfx::Rect* bounds_in_screen, 92 ui::WindowShowState* show_state) const { 93 DCHECK(show_state); 94 DCHECK(bounds_in_screen); 95 DCHECK(!browser_ || browser_->is_type_tabbed()); 96 97 bounds_in_screen->SetRect(0, 0, 0, 0); 98 99 // Experiment: Force the maximize mode for all tabbed windows 100 if (ash::Shell::IsForcedMaximizeMode()) 101 *show_state = ui::SHOW_STATE_MAXIMIZED; 102 103 ui::WindowShowState passed_show_state = *show_state; 104 bool has_saved_bounds = true; 105 if (!GetSavedWindowBounds(bounds_in_screen, show_state)) { 106 has_saved_bounds = false; 107 GetDefaultWindowBoundsAsh(bounds_in_screen); 108 } 109 110 aura::RootWindow* target = ash::Shell::GetTargetRootWindow(); 111 // Always open new window in the active display. 112 gfx::Rect work_area = 113 screen_->GetDisplayMatching(target->GetBoundsInScreen()).work_area(); 114 115 // This is a window / app. See if there is no window and try to place it. 116 int count = GetNumberOfValidTopLevelBrowserWindows(work_area); 117 aura::Window* top_window = ash::GetTopWindowForNewWindow(target); 118 // Our window should not have any impact if we are already on top. 119 if (browser_->window() && 120 top_window == browser_->window()->GetNativeWindow()) 121 top_window = NULL; 122 123 // If there is no valid other window we take the coordinates as is. 124 if ((!count || !top_window)) { 125 if (has_saved_bounds) { 126 // Restore to previous state - if there is one. 127 bounds_in_screen->AdjustToFit(work_area); 128 return; 129 } 130 131 // When using "small screens" we want to always open in full screen mode. 132 if (passed_show_state == ui::SHOW_STATE_DEFAULT && 133 !browser_->is_session_restore() && 134 work_area.width() <= GetForceMaximizedWidthLimit() && 135 (!browser_->window() || !browser_->window()->IsFullscreen())) 136 *show_state = ui::SHOW_STATE_MAXIMIZED; 137 return; 138 } 139 bool maximized = ash::wm::GetWindowState(top_window)->IsMaximized(); 140 // We ignore the saved show state, but look instead for the top level 141 // window's show state. 142 if (passed_show_state == ui::SHOW_STATE_DEFAULT) { 143 *show_state = maximized ? ui::SHOW_STATE_MAXIMIZED : 144 ui::SHOW_STATE_DEFAULT; 145 } 146 147 // Use the size of the other window. The window's bound will be rearranged 148 // in ash::WorkspaceLayoutManager using this location. 149 *bounds_in_screen = top_window->GetBoundsInScreen(); 150} 151 152void WindowSizer::GetDefaultWindowBoundsAsh(gfx::Rect* default_bounds) const { 153 DCHECK(default_bounds); 154 155 gfx::Rect work_area = screen_->GetPrimaryDisplay().work_area(); 156 157 // There should be a 'desktop' border around the window at the left and right 158 // side. 159 int default_width = work_area.width() - 2 * kDesktopBorderSize; 160 // There should also be a 'desktop' border around the window at the top. 161 // Since the workspace excludes the tray area we only need one border size. 162 int default_height = work_area.height() - kDesktopBorderSize; 163 // We align the size to the grid size to avoid any surprise when the 164 // monitor height isn't divide-able by our alignment factor. 165 default_width -= default_width % kDesktopBorderSize; 166 default_height -= default_height % kDesktopBorderSize; 167 int offset_x = kDesktopBorderSize; 168 if (default_width > kMaximumWindowWidth) { 169 // The window should get centered on the screen and not follow the grid. 170 offset_x = (work_area.width() - kMaximumWindowWidth) / 2; 171 default_width = kMaximumWindowWidth; 172 } 173 default_bounds->SetRect(work_area.x() + offset_x, 174 work_area.y() + kDesktopBorderSize, 175 default_width, 176 default_height); 177} 178