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"
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/compositor/layer.h"
24 #include "ui/gfx/display.h"
25 #include "ui/gfx/geometry/rect.h"
26 #include "ui/views/view_constants_aura.h"
27 #include "ui/views/widget/widget.h"
32 // Returns the biggest possible size for a window which is about to be
34 gfx::Size
GetMaximumSizeOfWindow(wm::WindowState
* window_state
) {
35 DCHECK(window_state
->CanMaximize() || window_state
->CanResize());
37 gfx::Size workspace_size
= ScreenUtil::GetMaximizedWindowBoundsInParent(
38 window_state
->window()).size();
40 aura::WindowDelegate
* delegate
= window_state
->window()->delegate();
42 return workspace_size
;
44 gfx::Size size
= delegate
->GetMaximumSize();
46 return workspace_size
;
48 size
.SetToMin(workspace_size
);
52 // Returns the centered bounds of the given bounds in the work area.
53 gfx::Rect
GetCenteredBounds(const gfx::Rect
& bounds_in_parent
,
54 wm::WindowState
* state_object
) {
55 gfx::Rect work_area_in_parent
=
56 ScreenUtil::GetDisplayWorkAreaBoundsInParent(state_object
->window());
57 work_area_in_parent
.ClampToCenteredSize(bounds_in_parent
.size());
58 return work_area_in_parent
;
61 // Returns the maximized/full screen and/or centered bounds of a window.
62 gfx::Rect
GetBoundsInMaximizedMode(wm::WindowState
* state_object
) {
63 if (state_object
->IsFullscreen())
64 return ScreenUtil::GetDisplayBoundsInParent(state_object
->window());
66 gfx::Rect bounds_in_parent
;
67 // Make the window as big as possible.
68 if (state_object
->CanMaximize() || state_object
->CanResize()) {
69 bounds_in_parent
.set_size(GetMaximumSizeOfWindow(state_object
));
71 // We prefer the user given window dimensions over the current windows
72 // dimensions since they are likely to be the result from some other state
74 if (state_object
->HasRestoreBounds())
75 bounds_in_parent
= state_object
->GetRestoreBoundsInParent();
77 bounds_in_parent
= state_object
->window()->bounds();
79 return GetCenteredBounds(bounds_in_parent
, state_object
);
85 void MaximizeModeWindowState::UpdateWindowPosition(
86 wm::WindowState
* window_state
) {
87 gfx::Rect bounds_in_parent
= GetBoundsInMaximizedMode(window_state
);
88 if (bounds_in_parent
== window_state
->window()->bounds())
90 window_state
->SetBoundsDirect(bounds_in_parent
);
93 MaximizeModeWindowState::MaximizeModeWindowState(
94 aura::Window
* window
, MaximizeModeWindowManager
* creator
)
97 current_state_type_(wm::GetWindowState(window
)->GetStateType()),
98 defer_bounds_updates_(false) {
100 wm::GetWindowState(window
)->SetStateObject(
101 scoped_ptr
<State
>(this).Pass()).release());
104 MaximizeModeWindowState::~MaximizeModeWindowState() {
105 creator_
->WindowStateDestroyed(window_
);
108 void MaximizeModeWindowState::LeaveMaximizeMode(wm::WindowState
* window_state
) {
109 // Note: When we return we will destroy ourselves with the |our_reference|.
110 scoped_ptr
<wm::WindowState::State
> our_reference
=
111 window_state
->SetStateObject(old_state_
.Pass());
114 void MaximizeModeWindowState::SetDeferBoundsUpdates(bool defer_bounds_updates
) {
115 if (defer_bounds_updates_
== defer_bounds_updates
)
118 defer_bounds_updates_
= defer_bounds_updates
;
119 if (!defer_bounds_updates_
)
120 UpdateBounds(wm::GetWindowState(window_
), true);
123 void MaximizeModeWindowState::OnWMEvent(wm::WindowState
* window_state
,
124 const wm::WMEvent
* event
) {
125 switch (event
->type()) {
126 case wm::WM_EVENT_TOGGLE_FULLSCREEN
:
127 ToggleFullScreen(window_state
, window_state
->delegate());
129 case wm::WM_EVENT_FULLSCREEN
:
130 UpdateWindow(window_state
, wm::WINDOW_STATE_TYPE_FULLSCREEN
, true);
132 case wm::WM_EVENT_TOGGLE_MAXIMIZE_CAPTION
:
133 case wm::WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE
:
134 case wm::WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE
:
135 case wm::WM_EVENT_TOGGLE_MAXIMIZE
:
136 case wm::WM_EVENT_CYCLE_SNAP_DOCK_LEFT
:
137 case wm::WM_EVENT_CYCLE_SNAP_DOCK_RIGHT
:
138 case wm::WM_EVENT_CENTER
:
139 case wm::WM_EVENT_SNAP_LEFT
:
140 case wm::WM_EVENT_SNAP_RIGHT
:
141 case wm::WM_EVENT_NORMAL
:
142 case wm::WM_EVENT_MAXIMIZE
:
143 case wm::WM_EVENT_DOCK
:
144 UpdateWindow(window_state
,
145 GetMaximizedOrCenteredWindowType(window_state
),
148 case wm::WM_EVENT_MINIMIZE
:
149 UpdateWindow(window_state
, wm::WINDOW_STATE_TYPE_MINIMIZED
, true);
151 case wm::WM_EVENT_SHOW_INACTIVE
:
153 case wm::WM_EVENT_SET_BOUNDS
:
154 if (current_state_type_
== wm::WINDOW_STATE_TYPE_MAXIMIZED
) {
155 // Having a maximized window, it could have been created with an empty
156 // size and the caller should get his size upon leaving the maximized
157 // mode. As such we set the restore bounds to the requested bounds.
158 gfx::Rect bounds_in_parent
=
159 (static_cast<const wm::SetBoundsEvent
*>(event
))->requested_bounds();
160 if (!bounds_in_parent
.IsEmpty())
161 window_state
->SetRestoreBoundsInParent(bounds_in_parent
);
162 } else if (current_state_type_
!= wm::WINDOW_STATE_TYPE_MINIMIZED
&&
163 current_state_type_
!= wm::WINDOW_STATE_TYPE_MAXIMIZED
&&
164 current_state_type_
!= wm::WINDOW_STATE_TYPE_FULLSCREEN
) {
165 // In all other cases (except for minimized windows) we respect the
166 // requested bounds and center it to a fully visible area on the screen.
167 gfx::Rect bounds_in_parent
=
168 (static_cast<const wm::SetBoundsEvent
*>(event
))->requested_bounds();
169 bounds_in_parent
= GetCenteredBounds(bounds_in_parent
, window_state
);
170 if (bounds_in_parent
!= window_state
->window()->bounds()) {
171 if (window_state
->window()->IsVisible())
172 window_state
->SetBoundsDirectAnimated(bounds_in_parent
);
174 window_state
->SetBoundsDirect(bounds_in_parent
);
178 case wm::WM_EVENT_ADDED_TO_WORKSPACE
:
179 if (current_state_type_
!= wm::WINDOW_STATE_TYPE_MAXIMIZED
&&
180 current_state_type_
!= wm::WINDOW_STATE_TYPE_FULLSCREEN
&&
181 current_state_type_
!= wm::WINDOW_STATE_TYPE_MINIMIZED
) {
182 wm::WindowStateType new_state
=
183 GetMaximizedOrCenteredWindowType(window_state
);
184 UpdateWindow(window_state
, new_state
, true);
187 case wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED
:
188 if (current_state_type_
!= wm::WINDOW_STATE_TYPE_MINIMIZED
)
189 UpdateBounds(window_state
, true);
191 case wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED
:
192 // Don't animate on a screen rotation - just snap to new size.
193 if (current_state_type_
!= wm::WINDOW_STATE_TYPE_MINIMIZED
)
194 UpdateBounds(window_state
, false);
199 wm::WindowStateType
MaximizeModeWindowState::GetType() const {
200 return current_state_type_
;
203 void MaximizeModeWindowState::AttachState(
204 wm::WindowState
* window_state
,
205 wm::WindowState::State
* previous_state
) {
206 current_state_type_
= previous_state
->GetType();
208 views::Widget
* widget
=
209 views::Widget::GetWidgetForNativeWindow(window_state
->window());
211 gfx::Rect bounds
= widget
->GetRestoredBounds();
212 if (!bounds
.IsEmpty()) {
213 // We do not want to do a session restore to our window states. Therefore
214 // we tell the window to use the current default states instead.
215 window_state
->window()->SetProperty(ash::kRestoreShowStateOverrideKey
,
216 window_state
->GetShowState());
217 window_state
->window()->SetProperty(ash::kRestoreBoundsOverrideKey
,
218 new gfx::Rect(widget
->GetRestoredBounds()));
222 // Initialize the state to a good preset.
223 if (current_state_type_
!= wm::WINDOW_STATE_TYPE_MAXIMIZED
&&
224 current_state_type_
!= wm::WINDOW_STATE_TYPE_MINIMIZED
&&
225 current_state_type_
!= wm::WINDOW_STATE_TYPE_FULLSCREEN
) {
226 UpdateWindow(window_state
,
227 GetMaximizedOrCenteredWindowType(window_state
),
231 window_state
->set_can_be_dragged(false);
234 void MaximizeModeWindowState::DetachState(wm::WindowState
* window_state
) {
235 // From now on, we can use the default session restore mechanism again.
236 window_state
->window()->ClearProperty(ash::kRestoreBoundsOverrideKey
);
237 window_state
->set_can_be_dragged(true);
240 void MaximizeModeWindowState::UpdateWindow(wm::WindowState
* window_state
,
241 wm::WindowStateType target_state
,
243 DCHECK(target_state
== wm::WINDOW_STATE_TYPE_MINIMIZED
||
244 target_state
== wm::WINDOW_STATE_TYPE_MAXIMIZED
||
245 (target_state
== wm::WINDOW_STATE_TYPE_NORMAL
&&
246 !window_state
->CanMaximize()) ||
247 target_state
== wm::WINDOW_STATE_TYPE_FULLSCREEN
);
249 if (target_state
== wm::WINDOW_STATE_TYPE_MINIMIZED
) {
250 if (current_state_type_
== wm::WINDOW_STATE_TYPE_MINIMIZED
)
253 current_state_type_
= target_state
;
254 ::wm::SetWindowVisibilityAnimationType(
255 window_state
->window(), WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE
);
256 window_state
->window()->Hide();
257 if (window_state
->IsActive())
258 window_state
->Deactivate();
262 if (current_state_type_
== target_state
) {
263 // If the state type did not change, update it accordingly.
264 UpdateBounds(window_state
, animated
);
268 const wm::WindowStateType old_state_type
= current_state_type_
;
269 current_state_type_
= target_state
;
270 window_state
->UpdateWindowShowStateFromStateType();
271 window_state
->NotifyPreStateTypeChange(old_state_type
);
272 UpdateBounds(window_state
, animated
);
273 window_state
->NotifyPostStateTypeChange(old_state_type
);
275 if ((window_state
->window()->TargetVisibility() ||
276 old_state_type
== wm::WINDOW_STATE_TYPE_MINIMIZED
) &&
277 !window_state
->window()->layer()->visible()) {
278 // The layer may be hidden if the window was previously minimized. Make
279 // sure it's visible.
280 window_state
->window()->Show();
284 wm::WindowStateType
MaximizeModeWindowState::GetMaximizedOrCenteredWindowType(
285 wm::WindowState
* window_state
) {
286 return window_state
->CanMaximize() ? wm::WINDOW_STATE_TYPE_MAXIMIZED
:
287 wm::WINDOW_STATE_TYPE_NORMAL
;
290 void MaximizeModeWindowState::UpdateBounds(wm::WindowState
* window_state
,
292 if (defer_bounds_updates_
)
294 gfx::Rect bounds_in_parent
= GetBoundsInMaximizedMode(window_state
);
295 // If we have a target bounds rectangle, we center it and set it
297 if (!bounds_in_parent
.IsEmpty() &&
298 bounds_in_parent
!= window_state
->window()->bounds()) {
299 if (current_state_type_
== wm::WINDOW_STATE_TYPE_MINIMIZED
||
300 !window_state
->window()->IsVisible() ||
302 window_state
->SetBoundsDirect(bounds_in_parent
);
304 // If we animate (to) maximized mode, we want to use the cross fade to
306 if (window_state
->IsMaximized())
307 window_state
->SetBoundsDirectCrossFade(bounds_in_parent
);
309 window_state
->SetBoundsDirectAnimated(bounds_in_parent
);