OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "ash/wm/maximize_mode/maximize_mode_window_state.h" | |
6 | |
7 #include <utility> | |
8 | |
9 #include "ash/public/cpp/shell_window_ids.h" | |
10 #include "ash/screen_util.h" | |
11 #include "ash/shell.h" | |
12 #include "ash/wm/maximize_mode/maximize_mode_window_manager.h" | |
13 #include "ash/wm/screen_pinning_controller.h" | |
14 #include "ash/wm/window_animation_types.h" | |
15 #include "ash/wm/window_properties.h" | |
16 #include "ash/wm/window_state_util.h" | |
17 #include "ash/wm/wm_event.h" | |
18 #include "ash/wm_window.h" | |
19 #include "ui/aura/window.h" | |
20 #include "ui/aura/window_delegate.h" | |
21 #include "ui/compositor/layer.h" | |
22 #include "ui/gfx/geometry/rect.h" | |
23 | |
24 namespace ash { | |
25 namespace { | |
26 | |
27 // Sets the restore bounds and show state overrides. These values take | |
28 // precedence over the restore bounds and restore show state (if set). | |
29 // If |bounds_override| is empty the values are cleared. | |
30 void SetWindowRestoreOverrides(aura::Window* window, | |
31 const gfx::Rect& bounds_override, | |
32 ui::WindowShowState window_state_override) { | |
33 if (bounds_override.IsEmpty()) { | |
34 window->ClearProperty(kRestoreShowStateOverrideKey); | |
35 window->ClearProperty(kRestoreBoundsOverrideKey); | |
36 return; | |
37 } | |
38 window->SetProperty(kRestoreShowStateOverrideKey, window_state_override); | |
39 window->SetProperty(kRestoreBoundsOverrideKey, | |
40 new gfx::Rect(bounds_override)); | |
41 } | |
42 | |
43 // Returns the biggest possible size for a window which is about to be | |
44 // maximized. | |
45 gfx::Size GetMaximumSizeOfWindow(wm::WindowState* window_state) { | |
46 DCHECK(window_state->CanMaximize() || window_state->CanResize()); | |
47 | |
48 gfx::Size workspace_size = | |
49 ScreenUtil::GetMaximizedWindowBoundsInParent(window_state->window()) | |
50 .size(); | |
51 | |
52 gfx::Size size = window_state->window()->delegate() | |
53 ? window_state->window()->delegate()->GetMaximumSize() | |
54 : gfx::Size(); | |
55 if (size.IsEmpty()) | |
56 return workspace_size; | |
57 | |
58 size.SetToMin(workspace_size); | |
59 return size; | |
60 } | |
61 | |
62 // Returns the centered bounds of the given bounds in the work area. | |
63 gfx::Rect GetCenteredBounds(const gfx::Rect& bounds_in_parent, | |
64 wm::WindowState* state_object) { | |
65 gfx::Rect work_area_in_parent = | |
66 ScreenUtil::GetDisplayWorkAreaBoundsInParent(state_object->window()); | |
67 work_area_in_parent.ClampToCenteredSize(bounds_in_parent.size()); | |
68 return work_area_in_parent; | |
69 } | |
70 | |
71 // Returns the maximized/full screen and/or centered bounds of a window. | |
72 gfx::Rect GetBoundsInMaximizedMode(wm::WindowState* state_object) { | |
73 if (state_object->IsFullscreen() || state_object->IsPinned()) | |
74 return ScreenUtil::GetDisplayBoundsInParent(state_object->window()); | |
75 | |
76 gfx::Rect bounds_in_parent; | |
77 // Make the window as big as possible. | |
78 if (state_object->CanMaximize() || state_object->CanResize()) { | |
79 bounds_in_parent.set_size(GetMaximumSizeOfWindow(state_object)); | |
80 } else { | |
81 // We prefer the user given window dimensions over the current windows | |
82 // dimensions since they are likely to be the result from some other state | |
83 // object logic. | |
84 if (state_object->HasRestoreBounds()) | |
85 bounds_in_parent = state_object->GetRestoreBoundsInParent(); | |
86 else | |
87 bounds_in_parent = state_object->window()->bounds(); | |
88 } | |
89 return GetCenteredBounds(bounds_in_parent, state_object); | |
90 } | |
91 | |
92 gfx::Rect GetRestoreBounds(wm::WindowState* window_state) { | |
93 if (window_state->IsMinimized() || window_state->IsMaximized() || | |
94 window_state->IsFullscreen()) { | |
95 gfx::Rect restore_bounds = window_state->GetRestoreBoundsInScreen(); | |
96 if (!restore_bounds.IsEmpty()) | |
97 return restore_bounds; | |
98 } | |
99 return window_state->window()->GetBoundsInScreen(); | |
100 } | |
101 | |
102 } // namespace | |
103 | |
104 // static | |
105 void MaximizeModeWindowState::UpdateWindowPosition( | |
106 wm::WindowState* window_state) { | |
107 gfx::Rect bounds_in_parent = GetBoundsInMaximizedMode(window_state); | |
108 if (bounds_in_parent == window_state->window()->bounds()) | |
109 return; | |
110 window_state->SetBoundsDirect(bounds_in_parent); | |
111 } | |
112 | |
113 MaximizeModeWindowState::MaximizeModeWindowState( | |
114 aura::Window* window, | |
115 MaximizeModeWindowManager* creator) | |
116 : window_(window), | |
117 creator_(creator), | |
118 current_state_type_(wm::GetWindowState(window)->GetStateType()), | |
119 defer_bounds_updates_(false) { | |
120 old_state_.reset(wm::GetWindowState(window) | |
121 ->SetStateObject(std::unique_ptr<State>(this)) | |
122 .release()); | |
123 } | |
124 | |
125 MaximizeModeWindowState::~MaximizeModeWindowState() { | |
126 creator_->WindowStateDestroyed(window_); | |
127 } | |
128 | |
129 void MaximizeModeWindowState::LeaveMaximizeMode(wm::WindowState* window_state) { | |
130 // Note: When we return we will destroy ourselves with the |our_reference|. | |
131 std::unique_ptr<wm::WindowState::State> our_reference = | |
132 window_state->SetStateObject(std::move(old_state_)); | |
133 } | |
134 | |
135 void MaximizeModeWindowState::SetDeferBoundsUpdates(bool defer_bounds_updates) { | |
136 if (defer_bounds_updates_ == defer_bounds_updates) | |
137 return; | |
138 | |
139 defer_bounds_updates_ = defer_bounds_updates; | |
140 if (!defer_bounds_updates_) | |
141 UpdateBounds(wm::GetWindowState(window_), true); | |
142 } | |
143 | |
144 void MaximizeModeWindowState::OnWMEvent(wm::WindowState* window_state, | |
145 const wm::WMEvent* event) { | |
146 // Ignore events that are sent during the exit transition. | |
147 if (ignore_wm_events_) { | |
148 return; | |
149 } | |
150 | |
151 switch (event->type()) { | |
152 case wm::WM_EVENT_TOGGLE_FULLSCREEN: | |
153 ToggleFullScreen(window_state, window_state->delegate()); | |
154 break; | |
155 case wm::WM_EVENT_FULLSCREEN: | |
156 UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_FULLSCREEN, true); | |
157 break; | |
158 case wm::WM_EVENT_PIN: | |
159 if (!Shell::Get()->screen_pinning_controller()->IsPinned()) | |
160 UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_PINNED, true); | |
161 break; | |
162 case wm::WM_EVENT_TRUSTED_PIN: | |
163 if (!Shell::Get()->screen_pinning_controller()->IsPinned()) | |
164 UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_TRUSTED_PINNED, true); | |
165 break; | |
166 case wm::WM_EVENT_TOGGLE_MAXIMIZE_CAPTION: | |
167 case wm::WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: | |
168 case wm::WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE: | |
169 case wm::WM_EVENT_TOGGLE_MAXIMIZE: | |
170 case wm::WM_EVENT_CYCLE_SNAP_LEFT: | |
171 case wm::WM_EVENT_CYCLE_SNAP_RIGHT: | |
172 case wm::WM_EVENT_CENTER: | |
173 case wm::WM_EVENT_SNAP_LEFT: | |
174 case wm::WM_EVENT_SNAP_RIGHT: | |
175 case wm::WM_EVENT_NORMAL: | |
176 case wm::WM_EVENT_MAXIMIZE: | |
177 UpdateWindow(window_state, GetMaximizedOrCenteredWindowType(window_state), | |
178 true); | |
179 return; | |
180 case wm::WM_EVENT_MINIMIZE: | |
181 UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_MINIMIZED, true); | |
182 return; | |
183 case wm::WM_EVENT_SHOW_INACTIVE: | |
184 return; | |
185 case wm::WM_EVENT_SET_BOUNDS: | |
186 if (current_state_type_ == wm::WINDOW_STATE_TYPE_MAXIMIZED) { | |
187 // Having a maximized window, it could have been created with an empty | |
188 // size and the caller should get his size upon leaving the maximized | |
189 // mode. As such we set the restore bounds to the requested bounds. | |
190 gfx::Rect bounds_in_parent = | |
191 (static_cast<const wm::SetBoundsEvent*>(event))->requested_bounds(); | |
192 if (!bounds_in_parent.IsEmpty()) | |
193 window_state->SetRestoreBoundsInParent(bounds_in_parent); | |
194 } else if (current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED && | |
195 current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN && | |
196 current_state_type_ != wm::WINDOW_STATE_TYPE_PINNED && | |
197 current_state_type_ != wm::WINDOW_STATE_TYPE_TRUSTED_PINNED) { | |
198 // In all other cases (except for minimized windows) we respect the | |
199 // requested bounds and center it to a fully visible area on the screen. | |
200 gfx::Rect bounds_in_parent = | |
201 (static_cast<const wm::SetBoundsEvent*>(event))->requested_bounds(); | |
202 bounds_in_parent = GetCenteredBounds(bounds_in_parent, window_state); | |
203 if (bounds_in_parent != window_state->window()->bounds()) { | |
204 if (window_state->window()->IsVisible()) | |
205 window_state->SetBoundsDirectAnimated(bounds_in_parent); | |
206 else | |
207 window_state->SetBoundsDirect(bounds_in_parent); | |
208 } | |
209 } | |
210 break; | |
211 case wm::WM_EVENT_ADDED_TO_WORKSPACE: | |
212 if (current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED && | |
213 current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN && | |
214 current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED) { | |
215 wm::WindowStateType new_state = | |
216 GetMaximizedOrCenteredWindowType(window_state); | |
217 UpdateWindow(window_state, new_state, true); | |
218 } | |
219 break; | |
220 case wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED: | |
221 if (current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED) | |
222 UpdateBounds(window_state, true); | |
223 break; | |
224 case wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED: | |
225 // Don't animate on a screen rotation - just snap to new size. | |
226 if (current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED) | |
227 UpdateBounds(window_state, false); | |
228 break; | |
229 } | |
230 } | |
231 | |
232 wm::WindowStateType MaximizeModeWindowState::GetType() const { | |
233 return current_state_type_; | |
234 } | |
235 | |
236 void MaximizeModeWindowState::AttachState( | |
237 wm::WindowState* window_state, | |
238 wm::WindowState::State* previous_state) { | |
239 current_state_type_ = previous_state->GetType(); | |
240 | |
241 gfx::Rect restore_bounds = GetRestoreBounds(window_state); | |
242 if (!restore_bounds.IsEmpty()) { | |
243 // We do not want to do a session restore to our window states. Therefore | |
244 // we tell the window to use the current default states instead. | |
245 SetWindowRestoreOverrides(window_state->window(), restore_bounds, | |
246 window_state->GetShowState()); | |
247 } | |
248 | |
249 // Initialize the state to a good preset. | |
250 if (current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED && | |
251 current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED && | |
252 current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN && | |
253 current_state_type_ != wm::WINDOW_STATE_TYPE_PINNED && | |
254 current_state_type_ != wm::WINDOW_STATE_TYPE_TRUSTED_PINNED) { | |
255 UpdateWindow(window_state, GetMaximizedOrCenteredWindowType(window_state), | |
256 true); | |
257 } | |
258 | |
259 window_state->set_can_be_dragged(false); | |
260 } | |
261 | |
262 void MaximizeModeWindowState::DetachState(wm::WindowState* window_state) { | |
263 // From now on, we can use the default session restore mechanism again. | |
264 SetWindowRestoreOverrides(window_state->window(), gfx::Rect(), | |
265 ui::SHOW_STATE_NORMAL); | |
266 window_state->set_can_be_dragged(true); | |
267 } | |
268 | |
269 void MaximizeModeWindowState::UpdateWindow(wm::WindowState* window_state, | |
270 wm::WindowStateType target_state, | |
271 bool animated) { | |
272 DCHECK(target_state == wm::WINDOW_STATE_TYPE_MINIMIZED || | |
273 target_state == wm::WINDOW_STATE_TYPE_MAXIMIZED || | |
274 target_state == wm::WINDOW_STATE_TYPE_PINNED || | |
275 target_state == wm::WINDOW_STATE_TYPE_TRUSTED_PINNED || | |
276 (target_state == wm::WINDOW_STATE_TYPE_NORMAL && | |
277 !window_state->CanMaximize()) || | |
278 target_state == wm::WINDOW_STATE_TYPE_FULLSCREEN); | |
279 | |
280 if (current_state_type_ == target_state) { | |
281 if (target_state == wm::WINDOW_STATE_TYPE_MINIMIZED) | |
282 return; | |
283 // If the state type did not change, update it accordingly. | |
284 UpdateBounds(window_state, animated); | |
285 return; | |
286 } | |
287 | |
288 const wm::WindowStateType old_state_type = current_state_type_; | |
289 current_state_type_ = target_state; | |
290 window_state->UpdateWindowPropertiesFromStateType(); | |
291 window_state->NotifyPreStateTypeChange(old_state_type); | |
292 | |
293 if (target_state == wm::WINDOW_STATE_TYPE_MINIMIZED) { | |
294 ::wm::SetWindowVisibilityAnimationType( | |
295 window_state->window(), wm::WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE); | |
296 window_state->window()->Hide(); | |
297 if (window_state->IsActive()) | |
298 window_state->Deactivate(); | |
299 } else { | |
300 UpdateBounds(window_state, animated); | |
301 } | |
302 | |
303 window_state->NotifyPostStateTypeChange(old_state_type); | |
304 | |
305 if (old_state_type == wm::WINDOW_STATE_TYPE_PINNED || | |
306 target_state == wm::WINDOW_STATE_TYPE_PINNED || | |
307 old_state_type == wm::WINDOW_STATE_TYPE_TRUSTED_PINNED || | |
308 target_state == wm::WINDOW_STATE_TYPE_TRUSTED_PINNED) { | |
309 Shell::Get()->screen_pinning_controller()->SetPinnedWindow( | |
310 WmWindow::Get(window_state->window())); | |
311 } | |
312 | |
313 if ((window_state->window()->layer()->GetTargetVisibility() || | |
314 old_state_type == wm::WINDOW_STATE_TYPE_MINIMIZED) && | |
315 !window_state->window()->layer()->visible()) { | |
316 // The layer may be hidden if the window was previously minimized. Make | |
317 // sure it's visible. | |
318 window_state->window()->Show(); | |
319 } | |
320 } | |
321 | |
322 wm::WindowStateType MaximizeModeWindowState::GetMaximizedOrCenteredWindowType( | |
323 wm::WindowState* window_state) { | |
324 return window_state->CanMaximize() ? wm::WINDOW_STATE_TYPE_MAXIMIZED | |
325 : wm::WINDOW_STATE_TYPE_NORMAL; | |
326 } | |
327 | |
328 void MaximizeModeWindowState::UpdateBounds(wm::WindowState* window_state, | |
329 bool animated) { | |
330 if (defer_bounds_updates_) | |
331 return; | |
332 gfx::Rect bounds_in_parent = GetBoundsInMaximizedMode(window_state); | |
333 // If we have a target bounds rectangle, we center it and set it | |
334 // accordingly. | |
335 if (!bounds_in_parent.IsEmpty() && | |
336 bounds_in_parent != window_state->window()->bounds()) { | |
337 if (current_state_type_ == wm::WINDOW_STATE_TYPE_MINIMIZED || | |
338 !window_state->window()->IsVisible() || !animated) { | |
339 window_state->SetBoundsDirect(bounds_in_parent); | |
340 } else { | |
341 // If we animate (to) maximized mode, we want to use the cross fade to | |
342 // avoid flashing. | |
343 if (window_state->IsMaximized()) | |
344 window_state->SetBoundsDirectCrossFade(bounds_in_parent); | |
345 else | |
346 window_state->SetBoundsDirectAnimated(bounds_in_parent); | |
347 } | |
348 } | |
349 } | |
350 | |
351 } // namespace ash | |
OLD | NEW |