window_state.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
1// Copyright 2013 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 "ash/wm/window_state.h"
6
7#include "ash/ash_switches.h"
8#include "ash/root_window_controller.h"
9#include "ash/screen_ash.h"
10#include "ash/shell_window_ids.h"
11#include "ash/wm/window_properties.h"
12#include "ash/wm/window_state_delegate.h"
13#include "ash/wm/window_state_observer.h"
14#include "ash/wm/window_util.h"
15#include "ash/wm/wm_types.h"
16#include "base/auto_reset.h"
17#include "base/command_line.h"
18#include "ui/aura/client/aura_constants.h"
19#include "ui/aura/window.h"
20#include "ui/aura/window_delegate.h"
21#include "ui/gfx/display.h"
22#include "ui/views/corewm/window_util.h"
23
24namespace ash {
25namespace wm {
26
27// static
28bool WindowState::IsMaximizedOrFullscreenState(ui::WindowShowState show_state) {
29  return show_state == ui::SHOW_STATE_FULLSCREEN ||
30      show_state == ui::SHOW_STATE_MAXIMIZED;
31}
32
33WindowState::WindowState(aura::Window* window)
34    : window_(window),
35      window_position_managed_(false),
36      bounds_changed_by_user_(false),
37      panel_attached_(true),
38      continue_drag_after_reparent_(false),
39      ignored_by_shelf_(false),
40      can_consume_system_keys_(false),
41      top_row_keys_are_function_keys_(false),
42      window_resizer_(NULL),
43      always_restores_to_restore_bounds_(false),
44      hide_shelf_when_fullscreen_(true),
45      animate_to_fullscreen_(true),
46      minimum_visibility_(false),
47      in_set_window_show_type_(false),
48      window_show_type_(ToWindowShowType(GetShowState())) {
49  window_->AddObserver(this);
50
51#if defined(OS_CHROMEOS)
52  // NOTE(pkotwicz): Animating to immersive fullscreen does not look good. When
53  // the kAshEnableImmersiveFullscreenForAllWindows flag is set most windows
54  // can be put into immersive fullscreen. It is not worth the added complexity
55  // to only animate to fullscreen if the window is put into immersive
56  // fullscreen.
57  animate_to_fullscreen_ = !CommandLine::ForCurrentProcess()->HasSwitch(
58      switches::kAshEnableImmersiveFullscreenForAllWindows);
59#endif
60}
61
62WindowState::~WindowState() {
63}
64
65bool WindowState::HasDelegate() const {
66  return delegate_;
67}
68
69void WindowState::SetDelegate(scoped_ptr<WindowStateDelegate> delegate) {
70  DCHECK(!delegate_.get());
71  delegate_ = delegate.Pass();
72}
73
74ui::WindowShowState WindowState::GetShowState() const {
75  return window_->GetProperty(aura::client::kShowStateKey);
76}
77
78bool WindowState::IsMinimized() const {
79  return GetShowState() == ui::SHOW_STATE_MINIMIZED;
80}
81
82bool WindowState::IsMaximized() const {
83  return GetShowState() == ui::SHOW_STATE_MAXIMIZED;
84}
85
86bool WindowState::IsFullscreen() const {
87  return GetShowState() == ui::SHOW_STATE_FULLSCREEN;
88}
89
90bool WindowState::IsMaximizedOrFullscreen() const {
91  return IsMaximizedOrFullscreenState(GetShowState());
92}
93
94bool WindowState::IsNormalShowState() const {
95  ui::WindowShowState state = window_->GetProperty(aura::client::kShowStateKey);
96  return state == ui::SHOW_STATE_NORMAL || state == ui::SHOW_STATE_DEFAULT;
97}
98
99bool WindowState::IsActive() const {
100  return IsActiveWindow(window_);
101}
102
103bool WindowState::IsDocked() const {
104  return window_->parent() &&
105      window_->parent()->id() == internal::kShellWindowId_DockedContainer;
106}
107
108bool WindowState::IsSnapped() const {
109  return window_show_type_ == SHOW_TYPE_LEFT_SNAPPED ||
110      window_show_type_ == SHOW_TYPE_RIGHT_SNAPPED;
111}
112
113bool WindowState::CanMaximize() const {
114  return window_->GetProperty(aura::client::kCanMaximizeKey);
115}
116
117bool WindowState::CanMinimize() const {
118  internal::RootWindowController* controller =
119      internal::RootWindowController::ForWindow(window_);
120  if (!controller)
121    return false;
122  aura::Window* lockscreen = controller->GetContainer(
123      internal::kShellWindowId_LockScreenContainersContainer);
124  if (lockscreen->Contains(window_))
125    return false;
126
127  return true;
128}
129
130bool WindowState::CanResize() const {
131  return window_->GetProperty(aura::client::kCanResizeKey);
132}
133
134bool WindowState::CanActivate() const {
135  return views::corewm::CanActivateWindow(window_);
136}
137
138bool WindowState::CanSnap() const {
139  if (!CanResize() ||
140      window_->type() == aura::client::WINDOW_TYPE_PANEL ||
141      window_->transient_parent())
142    return false;
143  // If a window has a maximum size defined, snapping may make it too big.
144  return window_->delegate() ? window_->delegate()->GetMaximumSize().IsEmpty() :
145                              true;
146}
147
148bool WindowState::HasRestoreBounds() const {
149  return window_->GetProperty(aura::client::kRestoreBoundsKey) != NULL;
150}
151
152void WindowState::Maximize() {
153  window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
154}
155
156void WindowState::SnapLeft(const gfx::Rect& bounds) {
157  SnapWindow(SHOW_TYPE_LEFT_SNAPPED, bounds);
158}
159
160void WindowState::SnapRight(const gfx::Rect& bounds) {
161  SnapWindow(SHOW_TYPE_RIGHT_SNAPPED, bounds);
162}
163
164void WindowState::Minimize() {
165  window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
166}
167
168void WindowState::Unminimize() {
169  window_->SetProperty(
170      aura::client::kShowStateKey,
171      window_->GetProperty(aura::client::kRestoreShowStateKey));
172  window_->ClearProperty(aura::client::kRestoreShowStateKey);
173}
174
175void WindowState::Activate() {
176  ActivateWindow(window_);
177}
178
179void WindowState::Deactivate() {
180  DeactivateWindow(window_);
181}
182
183void WindowState::Restore() {
184  window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
185}
186
187void WindowState::ToggleMaximized() {
188  if (IsMaximized())
189    Restore();
190  else if (CanMaximize())
191    Maximize();
192}
193
194void WindowState::ToggleFullscreen() {
195  // Window which cannot be maximized should not be fullscreened.
196  // It can, however, be restored if it was fullscreened.
197  bool is_fullscreen = IsFullscreen();
198  if (!is_fullscreen && !CanMaximize())
199    return;
200  if (delegate_ && delegate_->ToggleFullscreen(this))
201    return;
202  if (is_fullscreen) {
203    Restore();
204  } else {
205    window_->SetProperty(aura::client::kShowStateKey,
206                         ui::SHOW_STATE_FULLSCREEN);
207  }
208}
209
210void WindowState::SetBoundsInScreen(
211    const gfx::Rect& bounds_in_screen) {
212  gfx::Rect bounds_in_parent =
213      ScreenAsh::ConvertRectFromScreen(window_->parent(),
214                                       bounds_in_screen);
215  window_->SetBounds(bounds_in_parent);
216}
217
218void WindowState::SaveCurrentBoundsForRestore() {
219  gfx::Rect bounds_in_screen =
220      ScreenAsh::ConvertRectToScreen(window_->parent(),
221                                     window_->bounds());
222  SetRestoreBoundsInScreen(bounds_in_screen);
223}
224
225gfx::Rect WindowState::GetRestoreBoundsInScreen() const {
226  return *window_->GetProperty(aura::client::kRestoreBoundsKey);
227}
228
229gfx::Rect WindowState::GetRestoreBoundsInParent() const {
230  return ScreenAsh::ConvertRectFromScreen(window_->parent(),
231                                          GetRestoreBoundsInScreen());
232}
233
234void WindowState::SetRestoreBoundsInScreen(const gfx::Rect& bounds) {
235  window_->SetProperty(aura::client::kRestoreBoundsKey, new gfx::Rect(bounds));
236}
237
238void WindowState::SetRestoreBoundsInParent(const gfx::Rect& bounds) {
239  SetRestoreBoundsInScreen(
240      ScreenAsh::ConvertRectToScreen(window_->parent(), bounds));
241}
242
243void WindowState::ClearRestoreBounds() {
244  window_->ClearProperty(aura::client::kRestoreBoundsKey);
245}
246
247void WindowState::SetPreAutoManageWindowBounds(
248    const gfx::Rect& bounds) {
249  pre_auto_manage_window_bounds_.reset(new gfx::Rect(bounds));
250}
251
252void WindowState::AddObserver(WindowStateObserver* observer) {
253  observer_list_.AddObserver(observer);
254}
255
256void WindowState::RemoveObserver(WindowStateObserver* observer) {
257  observer_list_.RemoveObserver(observer);
258}
259
260void WindowState::OnWindowPropertyChanged(aura::Window* window,
261                                          const void* key,
262                                          intptr_t old) {
263  DCHECK_EQ(window, window_);
264  if (key == aura::client::kShowStateKey)
265    SetWindowShowType(ToWindowShowType(GetShowState()));
266}
267
268void WindowState::SnapWindow(WindowShowType left_or_right,
269                             const gfx::Rect& bounds) {
270  if (window_show_type_ == left_or_right) {
271    window_->SetBounds(bounds);
272    return;
273  }
274
275  // Compute the bounds that the window will restore to. If the window does not
276  // already have restore bounds, it will be restored (when un-snapped) to the
277  // last bounds that it had before getting snapped.
278  gfx::Rect restore_bounds_in_screen(HasRestoreBounds() ?
279      GetRestoreBoundsInScreen() : window_->GetBoundsInScreen());
280  // Set the window's restore bounds so that WorkspaceLayoutManager knows
281  // which width to use when the snapped window is moved to the edge.
282  SetRestoreBoundsInParent(bounds);
283
284  bool was_maximized = IsMaximizedOrFullscreen();
285  // Before we can set the bounds we need to restore the window.
286  // Restoring the window will set the window to its restored bounds set above.
287  // Restore will cause OnWindowPropertyChanged() so it needs to be done
288  // before notifying that the WindowShowType has changed to |left_or_right|.
289  if (was_maximized)
290    Restore();
291  DCHECK(left_or_right == SHOW_TYPE_LEFT_SNAPPED ||
292         left_or_right == SHOW_TYPE_RIGHT_SNAPPED);
293  SetWindowShowType(left_or_right);
294  // TODO(varkha): Ideally the bounds should be changed in a LayoutManager upon
295  // observing the WindowShowType change.
296  // If the window is a child of kShellWindowId_DockedContainer such as during
297  // a drag, the window's bounds are not set in
298  // WorkspaceLayoutManager::OnWindowShowTypeChanged(). Set them here. Skip
299  // setting the bounds otherwise to avoid stopping the slide animation which
300  // was started as a result of OnWindowShowTypeChanged().
301  if (IsDocked())
302    window_->SetBounds(bounds);
303  SetRestoreBoundsInScreen(restore_bounds_in_screen);
304}
305
306void WindowState::SetWindowShowType(WindowShowType new_window_show_type) {
307  if (in_set_window_show_type_)
308    return;
309  base::AutoReset<bool> resetter(&in_set_window_show_type_, true);
310
311  ui::WindowShowState new_window_state =
312      ToWindowShowState(new_window_show_type);
313  if (new_window_state != GetShowState())
314    window_->SetProperty(aura::client::kShowStateKey, new_window_state);
315  WindowShowType old_window_show_type = window_show_type_;
316  window_show_type_ = new_window_show_type;
317  if (old_window_show_type != window_show_type_) {
318    FOR_EACH_OBSERVER(WindowStateObserver, observer_list_,
319                      OnWindowShowTypeChanged(this, old_window_show_type));
320  }
321}
322
323WindowState* GetActiveWindowState() {
324  aura::Window* active = GetActiveWindow();
325  return active ? GetWindowState(active) : NULL;
326}
327
328WindowState* GetWindowState(aura::Window* window) {
329  if (!window)
330    return NULL;
331  WindowState* settings = window->GetProperty(internal::kWindowStateKey);
332  if(!settings) {
333    settings = new WindowState(window);
334    window->SetProperty(internal::kWindowStateKey, settings);
335  }
336  return settings;
337}
338
339const WindowState* GetWindowState(const aura::Window* window) {
340  return GetWindowState(const_cast<aura::Window*>(window));
341}
342
343}  // namespace wm
344}  // namespace ash
345