Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ash / wm / maximize_mode / maximize_mode_window_state.cc
blobe30c4b1878a05804808da4e901fbfcb4a0913d9e
1 // Copyright 2014 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.
5 #include "ash/wm/maximize_mode/maximize_mode_window_state.h"
7 #include "ash/display/display_controller.h"
8 #include "ash/screen_util.h"
9 #include "ash/shell.h"
10 #include "ash/shell_window_ids.h"
11 #include "ash/wm/coordinate_conversion.h"
12 #include "ash/wm/maximize_mode/maximize_mode_window_manager.h"
13 #include "ash/wm/window_animations.h"
14 #include "ash/wm/window_properties.h"
15 #include "ash/wm/window_state_delegate.h"
16 #include "ash/wm/window_state_util.h"
17 #include "ash/wm/window_util.h"
18 #include "ash/wm/wm_event.h"
19 #include "ash/wm/workspace/workspace_window_resizer.h"
20 #include "ui/aura/client/aura_constants.h"
21 #include "ui/aura/window.h"
22 #include "ui/aura/window_delegate.h"
23 #include "ui/gfx/display.h"
24 #include "ui/gfx/rect.h"
25 #include "ui/views/view_constants_aura.h"
26 #include "ui/views/widget/widget.h"
28 namespace ash {
29 namespace {
31 // Returns the biggest possible size for a window which is about to be
32 // maximized.
33 gfx::Size GetMaximumSizeOfWindow(wm::WindowState* window_state) {
34 DCHECK(window_state->CanMaximize() || window_state->CanResize());
36 gfx::Size workspace_size = ScreenUtil::GetMaximizedWindowBoundsInParent(
37 window_state->window()).size();
39 aura::WindowDelegate* delegate = window_state->window()->delegate();
40 if (!delegate)
41 return workspace_size;
43 gfx::Size size = delegate->GetMaximumSize();
44 if (size.IsEmpty())
45 return workspace_size;
47 size.SetToMin(workspace_size);
48 return size;
51 // Returns the centered bounds of the given bounds in the work area.
52 gfx::Rect GetCenteredBounds(const gfx::Rect& bounds_in_parent,
53 wm::WindowState* state_object) {
54 gfx::Rect work_area_in_parent =
55 ScreenUtil::GetDisplayWorkAreaBoundsInParent(state_object->window());
56 work_area_in_parent.ClampToCenteredSize(bounds_in_parent.size());
57 return work_area_in_parent;
60 // Returns the maximized/full screen and/or centered bounds of a window.
61 gfx::Rect GetBoundsInMaximizedMode(wm::WindowState* state_object) {
62 if (state_object->IsFullscreen())
63 return ScreenUtil::GetDisplayBoundsInParent(state_object->window());
65 gfx::Rect bounds_in_parent;
66 // Make the window as big as possible.
67 if (state_object->CanMaximize() || state_object->CanResize()) {
68 bounds_in_parent.set_size(GetMaximumSizeOfWindow(state_object));
69 } else {
70 // We prefer the user given window dimensions over the current windows
71 // dimensions since they are likely to be the result from some other state
72 // object logic.
73 if (state_object->HasRestoreBounds())
74 bounds_in_parent = state_object->GetRestoreBoundsInParent();
75 else
76 bounds_in_parent = state_object->window()->bounds();
78 return GetCenteredBounds(bounds_in_parent, state_object);
81 } // namespace
83 // static
84 void MaximizeModeWindowState::UpdateWindowPosition(
85 wm::WindowState* window_state, bool animated) {
86 gfx::Rect bounds_in_parent = GetBoundsInMaximizedMode(window_state);
88 if (bounds_in_parent == window_state->window()->bounds())
89 return;
91 if (animated)
92 window_state->SetBoundsDirect(bounds_in_parent);
93 else
94 window_state->SetBoundsDirectAnimated(bounds_in_parent);
97 MaximizeModeWindowState::MaximizeModeWindowState(
98 aura::Window* window, MaximizeModeWindowManager* creator)
99 : window_(window),
100 creator_(creator),
101 current_state_type_(wm::GetWindowState(window)->GetStateType()) {
102 old_state_.reset(
103 wm::GetWindowState(window)->SetStateObject(
104 scoped_ptr<State>(this).Pass()).release());
107 MaximizeModeWindowState::~MaximizeModeWindowState() {
108 creator_->WindowStateDestroyed(window_);
111 void MaximizeModeWindowState::LeaveMaximizeMode(wm::WindowState* window_state) {
112 // Note: When we return we will destroy ourselves with the |our_reference|.
113 scoped_ptr<wm::WindowState::State> our_reference =
114 window_state->SetStateObject(old_state_.Pass());
117 void MaximizeModeWindowState::OnWMEvent(wm::WindowState* window_state,
118 const wm::WMEvent* event) {
119 switch (event->type()) {
120 case wm::WM_EVENT_TOGGLE_FULLSCREEN:
121 ToggleFullScreen(window_state, window_state->delegate());
122 break;
123 case wm::WM_EVENT_FULLSCREEN:
124 UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_FULLSCREEN, true);
125 break;
126 case wm::WM_EVENT_TOGGLE_MAXIMIZE_CAPTION:
127 case wm::WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE:
128 case wm::WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE:
129 case wm::WM_EVENT_TOGGLE_MAXIMIZE:
130 case wm::WM_EVENT_CENTER:
131 case wm::WM_EVENT_SNAP_LEFT:
132 case wm::WM_EVENT_SNAP_RIGHT:
133 case wm::WM_EVENT_NORMAL:
134 case wm::WM_EVENT_MAXIMIZE:
135 UpdateWindow(window_state,
136 GetMaximizedOrCenteredWindowType(window_state),
137 true);
138 return;
139 case wm::WM_EVENT_MINIMIZE:
140 UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_MINIMIZED, true);
141 return;
142 case wm::WM_EVENT_SHOW_INACTIVE:
143 return;
144 case wm::WM_EVENT_SET_BOUNDS:
145 if (current_state_type_ == wm::WINDOW_STATE_TYPE_MAXIMIZED) {
146 // Having a maximized window, it could have been created with an empty
147 // size and the caller should get his size upon leaving the maximized
148 // mode. As such we set the restore bounds to the requested bounds.
149 gfx::Rect bounds_in_parent =
150 (static_cast<const wm::SetBoundsEvent*>(event))->requested_bounds();
151 if (!bounds_in_parent.IsEmpty())
152 window_state->SetRestoreBoundsInParent(bounds_in_parent);
153 } else if (current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED &&
154 current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED &&
155 current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN) {
156 // In all other cases (except for minimized windows) we respect the
157 // requested bounds and center it to a fully visible area on the screen.
158 gfx::Rect bounds_in_parent =
159 (static_cast<const wm::SetBoundsEvent*>(event))->requested_bounds();
160 bounds_in_parent = GetCenteredBounds(bounds_in_parent, window_state);
161 if (bounds_in_parent != window_state->window()->bounds()) {
162 if (window_state->window()->IsVisible())
163 window_state->SetBoundsDirectAnimated(bounds_in_parent);
164 else
165 window_state->SetBoundsDirect(bounds_in_parent);
168 break;
169 case wm::WM_EVENT_ADDED_TO_WORKSPACE:
170 if (current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED &&
171 current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN &&
172 current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED) {
173 wm::WindowStateType new_state =
174 GetMaximizedOrCenteredWindowType(window_state);
175 UpdateWindow(window_state, new_state, true);
177 break;
178 case wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED:
179 if (current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED)
180 UpdateBounds(window_state, true);
181 break;
182 case wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED:
183 // Don't animate on a screen rotation - just snap to new size.
184 if (current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED)
185 UpdateBounds(window_state, false);
186 break;
190 wm::WindowStateType MaximizeModeWindowState::GetType() const {
191 return current_state_type_;
194 void MaximizeModeWindowState::AttachState(
195 wm::WindowState* window_state,
196 wm::WindowState::State* previous_state) {
197 current_state_type_ = previous_state->GetType();
199 views::Widget* widget =
200 views::Widget::GetWidgetForNativeWindow(window_state->window());
201 if (widget) {
202 gfx::Rect bounds = widget->GetRestoredBounds();
203 if (!bounds.IsEmpty()) {
204 // We do not want to do a session restore to our window states. Therefore
205 // we tell the window to use the current default states instead.
206 window_state->window()->SetProperty(ash::kRestoreShowStateOverrideKey,
207 window_state->GetShowState());
208 window_state->window()->SetProperty(ash::kRestoreBoundsOverrideKey,
209 new gfx::Rect(widget->GetRestoredBounds()));
213 // Initialize the state to a good preset.
214 if (current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED &&
215 current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED &&
216 current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN) {
217 UpdateWindow(window_state,
218 GetMaximizedOrCenteredWindowType(window_state),
219 true);
222 window_state->set_can_be_dragged(false);
225 void MaximizeModeWindowState::DetachState(wm::WindowState* window_state) {
226 // From now on, we can use the default session restore mechanism again.
227 window_state->window()->ClearProperty(ash::kRestoreBoundsOverrideKey);
228 window_state->set_can_be_dragged(true);
231 void MaximizeModeWindowState::UpdateWindow(wm::WindowState* window_state,
232 wm::WindowStateType target_state,
233 bool animated) {
234 DCHECK(target_state == wm::WINDOW_STATE_TYPE_MINIMIZED ||
235 target_state == wm::WINDOW_STATE_TYPE_MAXIMIZED ||
236 (target_state == wm::WINDOW_STATE_TYPE_NORMAL &&
237 !window_state->CanMaximize()) ||
238 target_state == wm::WINDOW_STATE_TYPE_FULLSCREEN);
240 if (target_state == wm::WINDOW_STATE_TYPE_MINIMIZED) {
241 if (current_state_type_ == wm::WINDOW_STATE_TYPE_MINIMIZED)
242 return;
244 current_state_type_ = target_state;
245 ::wm::SetWindowVisibilityAnimationType(
246 window_state->window(), WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE);
247 window_state->window()->Hide();
248 if (window_state->IsActive())
249 window_state->Deactivate();
250 return;
253 if (current_state_type_ == target_state) {
254 // If the state type did not change, update it accordingly.
255 UpdateBounds(window_state, animated);
256 return;
259 const wm::WindowStateType old_state_type = current_state_type_;
260 current_state_type_ = target_state;
261 window_state->UpdateWindowShowStateFromStateType();
262 window_state->NotifyPreStateTypeChange(old_state_type);
263 UpdateBounds(window_state, animated);
264 window_state->NotifyPostStateTypeChange(old_state_type);
266 if ((window_state->window()->TargetVisibility() ||
267 old_state_type == wm::WINDOW_STATE_TYPE_MINIMIZED) &&
268 !window_state->window()->layer()->visible()) {
269 // The layer may be hidden if the window was previously minimized. Make
270 // sure it's visible.
271 window_state->window()->Show();
275 wm::WindowStateType MaximizeModeWindowState::GetMaximizedOrCenteredWindowType(
276 wm::WindowState* window_state) {
277 return window_state->CanMaximize() ? wm::WINDOW_STATE_TYPE_MAXIMIZED :
278 wm::WINDOW_STATE_TYPE_NORMAL;
281 void MaximizeModeWindowState::UpdateBounds(wm::WindowState* window_state,
282 bool animated) {
283 gfx::Rect bounds_in_parent = GetBoundsInMaximizedMode(window_state);
284 // If we have a target bounds rectangle, we center it and set it
285 // accordingly.
286 if (!bounds_in_parent.IsEmpty() &&
287 bounds_in_parent != window_state->window()->bounds()) {
288 if (current_state_type_ == wm::WINDOW_STATE_TYPE_MINIMIZED ||
289 !window_state->window()->IsVisible() ||
290 !animated) {
291 window_state->SetBoundsDirect(bounds_in_parent);
292 } else {
293 // If we animate (to) maximized mode, we want to use the cross fade to
294 // avoid flashing.
295 if (window_state->IsMaximized())
296 window_state->SetBoundsDirectCrossFade(bounds_in_parent);
297 else
298 window_state->SetBoundsDirectAnimated(bounds_in_parent);
303 } // namespace ash