window_state.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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/root_window_controller.h"
8#include "ash/screen_ash.h"
9#include "ash/shell_window_ids.h"
10#include "ash/wm/window_properties.h"
11#include "ash/wm/window_state_delegate.h"
12#include "ash/wm/window_state_observer.h"
13#include "ash/wm/window_util.h"
14#include "ash/wm/wm_types.h"
15#include "ui/aura/client/aura_constants.h"
16#include "ui/aura/window.h"
17#include "ui/aura/window_delegate.h"
18#include "ui/gfx/display.h"
19#include "ui/views/corewm/window_util.h"
20
21namespace ash {
22namespace wm {
23
24// static
25bool WindowState::IsMaximizedOrFullscreenState(ui::WindowShowState show_state) {
26  return show_state == ui::SHOW_STATE_FULLSCREEN ||
27      show_state == ui::SHOW_STATE_MAXIMIZED;
28}
29
30WindowState::WindowState(aura::Window* window)
31    : window_(window),
32      tracked_by_workspace_(true),
33      window_position_managed_(false),
34      bounds_changed_by_user_(false),
35      panel_attached_(true),
36      continue_drag_after_reparent_(false),
37      ignored_by_shelf_(false),
38      can_consume_system_keys_(false),
39      top_row_keys_are_function_keys_(false),
40      window_resizer_(NULL),
41      always_restores_to_restore_bounds_(false),
42      hide_shelf_when_fullscreen_(true),
43      animate_to_fullscreen_(true),
44      window_show_type_(ToWindowShowType(GetShowState())) {
45  window_->AddObserver(this);
46}
47
48WindowState::~WindowState() {
49}
50
51void WindowState::SetDelegate(scoped_ptr<WindowStateDelegate> delegate) {
52  DCHECK(!delegate_.get());
53  delegate_ = delegate.Pass();
54}
55
56ui::WindowShowState WindowState::GetShowState() const {
57  return window_->GetProperty(aura::client::kShowStateKey);
58}
59
60bool WindowState::IsMinimized() const {
61  return GetShowState() == ui::SHOW_STATE_MINIMIZED;
62}
63
64bool WindowState::IsMaximized() const {
65  return GetShowState() == ui::SHOW_STATE_MAXIMIZED;
66}
67
68bool WindowState::IsFullscreen() const {
69  return GetShowState() == ui::SHOW_STATE_FULLSCREEN;
70}
71
72bool WindowState::IsMaximizedOrFullscreen() const {
73  return IsMaximizedOrFullscreenState(GetShowState());
74}
75
76bool WindowState::IsNormalShowState() const {
77  ui::WindowShowState state = window_->GetProperty(aura::client::kShowStateKey);
78  return state == ui::SHOW_STATE_NORMAL || state == ui::SHOW_STATE_DEFAULT;
79}
80
81bool WindowState::IsActive() const {
82  return IsActiveWindow(window_);
83}
84
85bool WindowState::IsDocked() const {
86  return window_->parent() &&
87      window_->parent()->id() == internal::kShellWindowId_DockedContainer;
88}
89
90bool WindowState::CanMaximize() const {
91  return window_->GetProperty(aura::client::kCanMaximizeKey);
92}
93
94bool WindowState::CanMinimize() const {
95  internal::RootWindowController* controller =
96      internal::RootWindowController::ForWindow(window_);
97  if (!controller)
98    return false;
99  aura::Window* lockscreen = controller->GetContainer(
100      internal::kShellWindowId_LockScreenContainersContainer);
101  if (lockscreen->Contains(window_))
102    return false;
103
104  return true;
105}
106
107bool WindowState::CanResize() const {
108  return window_->GetProperty(aura::client::kCanResizeKey);
109}
110
111bool WindowState::CanActivate() const {
112  return views::corewm::CanActivateWindow(window_);
113}
114
115bool WindowState::CanSnap() const {
116  if (!CanResize() ||
117      window_->type() == aura::client::WINDOW_TYPE_PANEL ||
118      window_->transient_parent())
119    return false;
120  // If a window has a maximum size defined, snapping may make it too big.
121  return window_->delegate() ? window_->delegate()->GetMaximumSize().IsEmpty() :
122                              true;
123}
124
125bool WindowState::HasRestoreBounds() const {
126  return window_->GetProperty(aura::client::kRestoreBoundsKey) != NULL;
127}
128
129void WindowState::Maximize() {
130  window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
131}
132
133void WindowState::SnapLeft(const gfx::Rect& bounds) {
134  SnapWindow(SHOW_TYPE_LEFT_SNAPPED, bounds);
135}
136
137void WindowState::SnapRight(const gfx::Rect& bounds) {
138  SnapWindow(SHOW_TYPE_LEFT_SNAPPED, bounds);
139}
140
141void WindowState::Minimize() {
142  window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
143}
144
145void WindowState::Unminimize() {
146  window_->SetProperty(
147      aura::client::kShowStateKey,
148      window_->GetProperty(aura::client::kRestoreShowStateKey));
149  window_->ClearProperty(aura::client::kRestoreShowStateKey);
150}
151
152void WindowState::Activate() {
153  ActivateWindow(window_);
154}
155
156void WindowState::Deactivate() {
157  DeactivateWindow(window_);
158}
159
160void WindowState::Restore() {
161  window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
162}
163
164void WindowState::ToggleMaximized() {
165  if (IsMaximized())
166    Restore();
167  else if (CanMaximize())
168    Maximize();
169}
170
171void WindowState::ToggleFullscreen() {
172  // Window which cannot be maximized should not be fullscreened.
173  // It can, however, be restored if it was fullscreened.
174  bool is_fullscreen = IsFullscreen();
175  if (!is_fullscreen && !CanMaximize())
176    return;
177  if (delegate_ && delegate_->ToggleFullscreen(this))
178    return;
179  if (is_fullscreen) {
180    Restore();
181  } else {
182    window_->SetProperty(aura::client::kShowStateKey,
183                         ui::SHOW_STATE_FULLSCREEN);
184  }
185}
186
187void WindowState::SetBoundsInScreen(
188    const gfx::Rect& bounds_in_screen) {
189  gfx::Rect bounds_in_parent =
190      ScreenAsh::ConvertRectFromScreen(window_->parent(),
191                                       bounds_in_screen);
192  window_->SetBounds(bounds_in_parent);
193}
194
195void WindowState::SaveCurrentBoundsForRestore() {
196  gfx::Rect bounds_in_screen =
197      ScreenAsh::ConvertRectToScreen(window_->parent(),
198                                     window_->bounds());
199  SetRestoreBoundsInScreen(bounds_in_screen);
200}
201
202gfx::Rect WindowState::GetRestoreBoundsInScreen() const {
203  return *window_->GetProperty(aura::client::kRestoreBoundsKey);
204}
205
206gfx::Rect WindowState::GetRestoreBoundsInParent() const {
207  return ScreenAsh::ConvertRectFromScreen(window_->parent(),
208                                          GetRestoreBoundsInScreen());
209}
210
211void WindowState::SetRestoreBoundsInScreen(const gfx::Rect& bounds) {
212  window_->SetProperty(aura::client::kRestoreBoundsKey, new gfx::Rect(bounds));
213}
214
215void WindowState::SetRestoreBoundsInParent(const gfx::Rect& bounds) {
216  SetRestoreBoundsInScreen(
217      ScreenAsh::ConvertRectToScreen(window_->parent(), bounds));
218}
219
220void WindowState::ClearRestoreBounds() {
221  window_->ClearProperty(aura::client::kRestoreBoundsKey);
222}
223
224void WindowState::SetPreAutoManageWindowBounds(
225    const gfx::Rect& bounds) {
226  pre_auto_manage_window_bounds_.reset(new gfx::Rect(bounds));
227}
228
229void WindowState::AddObserver(WindowStateObserver* observer) {
230  observer_list_.AddObserver(observer);
231}
232
233void WindowState::RemoveObserver(WindowStateObserver* observer) {
234  observer_list_.RemoveObserver(observer);
235}
236
237void WindowState::SetTrackedByWorkspace(bool tracked_by_workspace) {
238  if (tracked_by_workspace_ == tracked_by_workspace)
239    return;
240  bool old = tracked_by_workspace_;
241  tracked_by_workspace_ = tracked_by_workspace;
242  FOR_EACH_OBSERVER(WindowStateObserver, observer_list_,
243                    OnTrackedByWorkspaceChanged(this, old));
244}
245
246void WindowState::OnWindowPropertyChanged(aura::Window* window,
247                                          const void* key,
248                                          intptr_t old) {
249  DCHECK_EQ(window, window_);
250  if (key == aura::client::kShowStateKey) {
251    window_show_type_ = ToWindowShowType(GetShowState());
252    ui::WindowShowState old_state = static_cast<ui::WindowShowState>(old);
253    // TODO(oshima): Notify only when the state has changed.
254    // Doing so break a few tests now.
255    FOR_EACH_OBSERVER(
256        WindowStateObserver, observer_list_,
257        OnWindowShowTypeChanged(this, ToWindowShowType(old_state)));
258  }
259}
260
261void WindowState::OnWindowDestroying(aura::Window* window) {
262  window_->RemoveObserver(this);
263}
264
265void WindowState::SnapWindow(WindowShowType left_or_right,
266                             const gfx::Rect& bounds) {
267  if (IsMaximizedOrFullscreen()) {
268    // Before we can set the bounds we need to restore the window.
269    // Restoring the window will set the window to its restored bounds.
270    // To avoid an unnecessary bounds changes (which may have side effects)
271    // we set the restore bounds to the bounds we want, restore the window,
272    // then reset the restore bounds. This way no unnecessary bounds
273    // changes occurs and the original restore bounds is remembered.
274    gfx::Rect restore_bounds_in_screen =
275        GetRestoreBoundsInScreen();
276    SetRestoreBoundsInParent(bounds);
277    Restore();
278    SetRestoreBoundsInScreen(restore_bounds_in_screen);
279  } else {
280    window_->SetBounds(bounds);
281  }
282  DCHECK(left_or_right == SHOW_TYPE_LEFT_SNAPPED ||
283         left_or_right == SHOW_TYPE_RIGHT_SNAPPED);
284  window_show_type_ = left_or_right;
285}
286
287WindowState* GetActiveWindowState() {
288  aura::Window* active = GetActiveWindow();
289  return active ? GetWindowState(active) : NULL;
290}
291
292WindowState* GetWindowState(aura::Window* window) {
293  if (!window)
294    return NULL;
295  WindowState* settings = window->GetProperty(internal::kWindowStateKey);
296  if(!settings) {
297    settings = new WindowState(window);
298    window->SetProperty(internal::kWindowStateKey, settings);
299  }
300  return settings;
301}
302
303const WindowState* GetWindowState(const aura::Window* window) {
304  return GetWindowState(const_cast<aura::Window*>(window));
305}
306
307}  // namespace wm
308}  // namespace ash
309