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