window_sizer_ash.cc revision 58537e28ecd584eab876aee8be7156509866d23a
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/window_sizer/window_sizer.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ash/ash_switches.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell.h" 9a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ash/wm/mru_window_tracker.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/wm/window_util.h" 11424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ash/wm/workspace/auto_window_management.h" 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/command_line.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_window.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/root_window.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/aura/window_delegate.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/screen.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// When a window gets opened in default mode and the screen is less than or 25ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// equal to this width, the window will get opened in maximized mode. This value 26ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// can be reduced to a "tame" number if the feature is disabled. 27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kForceMaximizeWidthLimit = 1366; 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kForceMaximizeWidthLimitDisabled = 640; 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Check if the given browser is 'valid': It is a tabbed, non minimized 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// window, which intersects with the |bounds_in_screen| area of a given screen. 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsValidBrowser(Browser* browser, const gfx::Rect& bounds_in_screen) { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (browser && browser->window() && 34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) !browser->is_type_popup() && 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !browser->window()->IsMinimized() && 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) browser->window()->GetNativeWindow() && 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_in_screen.Intersects( 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) browser->window()->GetNativeWindow()->GetBoundsInScreen())); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return the number of valid top level windows on the screen defined by 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the |bounds_in_screen| rectangle. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int GetNumberOfValidTopLevelBrowserWindows(const gfx::Rect& bounds_in_screen) { 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int count = 0; 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const BrowserList* ash_browser_list = 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (BrowserList::const_iterator iter = ash_browser_list->begin(); 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) iter != ash_browser_list->end(); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++iter) { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsValidBrowser(*iter, bounds_in_screen)) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) count++; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return count; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Move the given |bounds_in_screen| on the available |work_area| to the 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// direction. If |move_right| is true, the rectangle gets moved to the right 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// corner. Otherwise to the left side. 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MoveRect(const gfx::Rect& work_area, 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect& bounds_in_screen, 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool move_right) { 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (move_right) { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (work_area.right() > bounds_in_screen.right()) { 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_in_screen.set_x(work_area.right() - bounds_in_screen.width()); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (work_area.x() < bounds_in_screen.x()) { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bounds_in_screen.set_x(work_area.x()); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int WindowSizer::GetForceMaximizedWidthLimit() { 80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) static int maximum_limit = 0; 81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!maximum_limit) { 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) maximum_limit = CommandLine::ForCurrentProcess()->HasSwitch( 83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ash::switches::kAshDisableAutoMaximizing) ? 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) kForceMaximizeWidthLimitDisabled : kForceMaximizeWidthLimit; 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return maximum_limit; 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void WindowSizer::GetTabbedBrowserBoundsAsh( 9058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) gfx::Rect* bounds_in_screen, 9158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ui::WindowShowState* show_state) const { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(show_state); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(bounds_in_screen); 9458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(!browser_ || browser_->is_type_tabbed()); 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bounds_in_screen->SetRect(0, 0, 0, 0); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Experiment: Force the maximize mode for all tabbed windows 9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (ash::Shell::IsForcedMaximizeMode()) 10058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *show_state = ui::SHOW_STATE_MAXIMIZED; 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::WindowShowState passed_show_state = *show_state; 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool has_saved_bounds = true; 104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!GetSavedWindowBounds(bounds_in_screen, show_state)) { 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) has_saved_bounds = false; 10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) GetDefaultWindowBoundsAsh(bounds_in_screen); 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) aura::RootWindow* active = ash::Shell::GetActiveRootWindow(); 11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Always open new window in the active display. 11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) gfx::Rect work_area = 11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) screen_->GetDisplayMatching(active->GetBoundsInScreen()).work_area(); 11358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 11458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // This is a window / app. See if there is no window and try to place it. 11558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) int count = GetNumberOfValidTopLevelBrowserWindows(work_area); 11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) aura::Window* top_window = ash::GetTopWindowForNewWindow(active); 11758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Our window should not have any impact if we are already on top. 11858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (browser_->window() && 11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) top_window == browser_->window()->GetNativeWindow()) 12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) top_window = NULL; 12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // If there is no valid other window we take the coordinates as is. 12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if ((!count || !top_window)) { 12458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (has_saved_bounds) { 12558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Restore to previous state - if there is one. 12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) bounds_in_screen->AdjustToFit(work_area); 12758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // When using "small screens" we want to always open in full screen mode. 13158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (passed_show_state == ui::SHOW_STATE_DEFAULT && 13258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) !browser_->is_session_restore() && 13358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) work_area.width() <= GetForceMaximizedWidthLimit() && 13458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) (!browser_->window() || !browser_->window()->IsFullscreen())) 13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *show_state = ui::SHOW_STATE_MAXIMIZED; 13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 13858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) bool maximized = ash::wm::IsWindowMaximized(top_window); 13958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // We ignore the saved show state, but look instead for the top level 14058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // window's show state. 14158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (passed_show_state == ui::SHOW_STATE_DEFAULT) { 14258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *show_state = maximized ? ui::SHOW_STATE_MAXIMIZED : 14358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ui::SHOW_STATE_DEFAULT; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Use the size of the other window. The window's bound will be rearranged 14758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // in ash::WorkspaceLayoutManager using this location. 14858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *bounds_in_screen = top_window->GetBoundsInScreen(); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WindowSizer::GetDefaultWindowBoundsAsh(gfx::Rect* default_bounds) const { 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(default_bounds); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 154424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) gfx::Rect work_area = screen_->GetPrimaryDisplay().work_area(); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There should be a 'desktop' border around the window at the left and right 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // side. 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int default_width = work_area.width() - 2 * kDesktopBorderSize; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There should also be a 'desktop' border around the window at the top. 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since the workspace excludes the tray area we only need one border size. 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int default_height = work_area.height() - kDesktopBorderSize; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We align the size to the grid size to avoid any surprise when the 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // monitor height isn't divide-able by our alignment factor. 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_width -= default_width % kDesktopBorderSize; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_height -= default_height % kDesktopBorderSize; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int offset_x = kDesktopBorderSize; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (default_width > kMaximumWindowWidth) { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The window should get centered on the screen and not follow the grid. 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) offset_x = (work_area.width() - kMaximumWindowWidth) / 2; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_width = kMaximumWindowWidth; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_bounds->SetRect(work_area.x() + offset_x, 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) work_area.y() + kDesktopBorderSize, 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_width, 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_height); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 177