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