Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ash/wm/default_state.h" | 5 #include "ash/wm/default_state.h" |
| 6 | 6 |
| 7 #include "ash/display/display_controller.h" | |
| 7 #include "ash/screen_util.h" | 8 #include "ash/screen_util.h" |
| 8 #include "ash/shell.h" | 9 #include "ash/shell.h" |
| 9 #include "ash/wm/coordinate_conversion.h" | 10 #include "ash/wm/coordinate_conversion.h" |
| 11 #include "ash/wm/window_animations.h" | |
| 10 #include "ash/wm/window_state.h" | 12 #include "ash/wm/window_state.h" |
| 13 #include "ash/wm/window_state_delegate.h" | |
| 14 #include "ash/wm/window_util.h" | |
| 15 #include "ash/wm/workspace/workspace_window_resizer.h" | |
| 16 #include "ui/aura/client/aura_constants.h" | |
| 11 #include "ui/aura/window.h" | 17 #include "ui/aura/window.h" |
| 12 #include "ui/aura/window_delegate.h" | 18 #include "ui/aura/window_delegate.h" |
| 13 #include "ui/gfx/display.h" | 19 #include "ui/gfx/display.h" |
| 14 #include "ui/gfx/rect.h" | 20 #include "ui/gfx/rect.h" |
| 15 | 21 |
| 16 namespace ash { | 22 namespace ash { |
| 17 namespace wm { | 23 namespace wm { |
| 24 namespace { | |
| 25 | |
| 26 gfx::Rect BoundsWithScreenEdgeVisible( | |
| 27 aura::Window* window, | |
| 28 const gfx::Rect& restore_bounds) { | |
| 29 gfx::Rect max_bounds = | |
| 30 ash::ScreenUtil::GetMaximizedWindowBoundsInParent(window); | |
| 31 // If the restore_bounds are more than 1 grid step away from the size the | |
| 32 // window would be when maximized, inset it. | |
| 33 max_bounds.Inset(ash::internal::WorkspaceWindowResizer::kScreenEdgeInset, | |
| 34 ash::internal::WorkspaceWindowResizer::kScreenEdgeInset); | |
| 35 if (restore_bounds.Contains(max_bounds)) | |
| 36 return max_bounds; | |
| 37 return restore_bounds; | |
| 38 } | |
| 39 | |
| 40 void MoveToDisplayForRestore(wm::WindowState* window_state) { | |
| 41 if (!window_state->HasRestoreBounds()) | |
| 42 return; | |
| 43 const gfx::Rect& restore_bounds = window_state->GetRestoreBoundsInScreen(); | |
| 44 | |
| 45 // Move only if the restore bounds is outside of | |
| 46 // the display. There is no information about in which | |
| 47 // display it should be restored, so this is best guess. | |
| 48 // TODO(oshima): Restore information should contain the | |
| 49 // work area information like WindowResizer does for the | |
| 50 // last window location. | |
| 51 gfx::Rect display_area = Shell::GetScreen()->GetDisplayNearestWindow( | |
| 52 window_state->window()).bounds(); | |
| 53 | |
| 54 if (!display_area.Intersects(restore_bounds)) { | |
| 55 const gfx::Display& display = | |
| 56 Shell::GetScreen()->GetDisplayMatching(restore_bounds); | |
| 57 DisplayController* display_controller = | |
| 58 Shell::GetInstance()->display_controller(); | |
| 59 aura::Window* new_root = | |
| 60 display_controller->GetRootWindowForDisplayId(display.id()); | |
| 61 if (new_root != window_state->window()->GetRootWindow()) { | |
| 62 aura::Window* new_container = | |
| 63 Shell::GetContainer(new_root, window_state->window()->parent()->id()); | |
| 64 new_container->AddChild(window_state->window()); | |
| 65 } | |
| 66 } | |
| 67 } | |
| 68 | |
| 69 } // namespace; | |
| 18 | 70 |
| 19 DefaultState::DefaultState() {} | 71 DefaultState::DefaultState() {} |
| 20 DefaultState::~DefaultState() {} | 72 DefaultState::~DefaultState() {} |
| 21 | 73 |
| 22 void DefaultState::OnWMEvent(WindowState* window_state, | 74 void DefaultState::OnWMEvent(WindowState* window_state, |
| 23 WMEvent event) { | 75 WMEvent event) { |
| 76 if (ProcessCompoundEvents(window_state, event)) | |
| 77 return; | |
| 78 | |
| 79 WindowShowType next_show_type; | |
| 80 | |
| 81 switch (event) { | |
| 82 case NORMAL: | |
| 83 next_show_type = SHOW_TYPE_NORMAL; | |
| 84 break; | |
| 85 case MAXIMIZE: | |
| 86 next_show_type = SHOW_TYPE_MAXIMIZED; | |
| 87 break; | |
| 88 case MINIMIZE: | |
| 89 next_show_type = SHOW_TYPE_MINIMIZED; | |
| 90 break; | |
| 91 case FULLSCREEN: | |
| 92 next_show_type = SHOW_TYPE_FULLSCREEN; | |
| 93 break; | |
| 94 case SNAP_LEFT: | |
| 95 next_show_type = SHOW_TYPE_LEFT_SNAPPED; | |
| 96 break; | |
| 97 case SNAP_RIGHT: | |
| 98 next_show_type = SHOW_TYPE_RIGHT_SNAPPED; | |
| 99 break; | |
| 100 case TOGGLE_MAXIMIZE_CAPTION: | |
| 101 case TOGGLE_MAXIMIZE: | |
| 102 case TOGGLE_VERTICAL_MAXIMIZE: | |
| 103 case TOGGLE_HORIZONTAL_MAXIMIZE: | |
| 104 case TOGGLE_FULLSCREEN: | |
| 105 NOTREACHED() << "Compound event should not reach here:" << event; | |
| 106 return; | |
| 107 } | |
| 108 | |
| 109 WindowShowType current = window_state->window_show_type(); | |
| 110 if (current != next_show_type) { | |
| 111 window_state->UpdateWindowShowType(next_show_type); | |
| 112 window_state->NotifyPreShowTypeChange(current); | |
| 113 if (!window_state->IsDocked()) | |
| 114 UpdateBoundsFromShowType(window_state, current); | |
| 115 window_state->NotifyPostShowTypeChange(current); | |
| 116 } | |
| 117 }; | |
| 118 | |
| 119 // static | |
| 120 bool DefaultState::ProcessCompoundEvents(WindowState* window_state, | |
| 121 WMEvent event) { | |
| 24 aura::Window* window = window_state->window(); | 122 aura::Window* window = window_state->window(); |
| 25 | 123 |
| 26 switch (event) { | 124 switch (event) { |
| 27 case TOGGLE_MAXIMIZE_CAPTION: | 125 case TOGGLE_MAXIMIZE_CAPTION: |
| 28 if (window_state->IsFullscreen()) { | 126 if (window_state->IsFullscreen()) { |
| 29 window_state->ToggleFullscreen(); | 127 window_state->ToggleFullscreen(); |
| 30 } else if (window_state->IsMaximized()) { | 128 } else if (window_state->IsMaximized()) { |
| 31 window_state->Restore(); | 129 window_state->Restore(); |
| 32 } else if (window_state->IsNormalShowType() || | 130 } else if (window_state->IsNormalShowType() || |
| 33 window_state->IsSnapped()) { | 131 window_state->IsSnapped()) { |
| 34 if (window_state->CanMaximize()) | 132 if (window_state->CanMaximize()) |
| 35 window_state->Maximize(); | 133 window_state->Maximize(); |
| 36 } | 134 } |
| 37 break; | 135 return true; |
| 38 | |
| 39 case TOGGLE_MAXIMIZE: | 136 case TOGGLE_MAXIMIZE: |
| 40 if (window_state->IsFullscreen()) | 137 if (window_state->IsFullscreen()) |
| 41 window_state->ToggleFullscreen(); | 138 window_state->ToggleFullscreen(); |
| 42 else if (window_state->IsMaximized()) | 139 else if (window_state->IsMaximized()) |
| 43 window_state->Restore(); | 140 window_state->Restore(); |
| 44 else if (window_state->CanMaximize()) | 141 else if (window_state->CanMaximize()) |
| 45 window_state->Maximize(); | 142 window_state->Maximize(); |
| 46 break; | 143 return true; |
| 47 | |
| 48 case TOGGLE_VERTICAL_MAXIMIZE: { | 144 case TOGGLE_VERTICAL_MAXIMIZE: { |
| 49 gfx::Rect work_area = | 145 gfx::Rect work_area = |
| 50 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window); | 146 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window); |
| 51 | 147 |
| 52 // Maximize vertically if: | 148 // Maximize vertically if: |
| 53 // - The window does not have a max height defined. | 149 // - The window does not have a max height defined. |
| 54 // - The window has the normal show type. Snapped windows are excluded | 150 // - The window has the normal show type. Snapped windows are excluded |
| 55 // because they are already maximized vertically and reverting to the | 151 // because they are already maximized vertically and reverting to the |
| 56 // restored bounds looks weird. | 152 // restored bounds looks weird. |
| 57 if (window->delegate()->GetMaximumSize().height() != 0 || | 153 if (window->delegate()->GetMaximumSize().height() != 0 || |
| 58 !window_state->IsNormalShowType()) { | 154 !window_state->IsNormalShowType()) { |
| 59 return; | 155 return true; |
| 60 } | 156 } |
| 61 if (window_state->HasRestoreBounds() && | 157 if (window_state->HasRestoreBounds() && |
| 62 (window->bounds().height() == work_area.height() && | 158 (window->bounds().height() == work_area.height() && |
| 63 window->bounds().y() == work_area.y())) { | 159 window->bounds().y() == work_area.y())) { |
| 64 window_state->SetAndClearRestoreBounds(); | 160 window_state->SetAndClearRestoreBounds(); |
| 65 } else { | 161 } else { |
| 66 window_state->SaveCurrentBoundsForRestore(); | 162 window_state->SaveCurrentBoundsForRestore(); |
| 67 window->SetBounds(gfx::Rect(window->bounds().x(), | 163 window->SetBounds(gfx::Rect(window->bounds().x(), |
| 68 work_area.y(), | 164 work_area.y(), |
| 69 window->bounds().width(), | 165 window->bounds().width(), |
| 70 work_area.height())); | 166 work_area.height())); |
| 71 } | 167 } |
| 72 break; | 168 return true; |
| 73 } | 169 } |
| 74 case TOGGLE_HORIZONTAL_MAXIMIZE: { | 170 case TOGGLE_HORIZONTAL_MAXIMIZE: { |
| 75 // Maximize horizontally if: | 171 // Maximize horizontally if: |
| 76 // - The window does not have a max width defined. | 172 // - The window does not have a max width defined. |
| 77 // - The window is snapped or has the normal show type. | 173 // - The window is snapped or has the normal show type. |
| 78 if (window->delegate()->GetMaximumSize().width() != 0) | 174 if (window->delegate()->GetMaximumSize().width() != 0) |
| 79 return; | 175 return true; |
| 80 if (!window_state->IsNormalShowType() && !window_state->IsSnapped()) | 176 if (!window_state->IsNormalShowType() && !window_state->IsSnapped()) |
| 81 return; | 177 return true; |
| 82 | |
| 83 gfx::Rect work_area = | 178 gfx::Rect work_area = |
| 84 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window); | 179 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window); |
| 85 | |
| 86 if (window_state->IsNormalShowType() && | 180 if (window_state->IsNormalShowType() && |
| 87 window_state->HasRestoreBounds() && | 181 window_state->HasRestoreBounds() && |
| 88 (window->bounds().width() == work_area.width() && | 182 (window->bounds().width() == work_area.width() && |
| 89 window->bounds().x() == work_area.x())) { | 183 window->bounds().x() == work_area.x())) { |
| 90 window_state->SetAndClearRestoreBounds(); | 184 window_state->SetAndClearRestoreBounds(); |
| 91 } else { | 185 } else { |
| 92 gfx::Rect new_bounds(work_area.x(), | 186 gfx::Rect new_bounds(work_area.x(), |
| 93 window->bounds().y(), | 187 window->bounds().y(), |
| 94 work_area.width(), | 188 work_area.width(), |
| 95 window->bounds().height()); | 189 window->bounds().height()); |
| 96 | 190 |
| 97 gfx::Rect restore_bounds = window->bounds(); | 191 gfx::Rect restore_bounds = window->bounds(); |
| 98 if (window_state->IsSnapped()) { | 192 if (window_state->IsSnapped()) { |
| 99 window_state->SetRestoreBoundsInParent(new_bounds); | 193 window_state->SetRestoreBoundsInParent(new_bounds); |
| 100 window_state->Restore(); | 194 window_state->Restore(); |
| 101 | 195 |
| 102 // The restore logic prevents a window from being restored to bounds | 196 // The restore logic prevents a window from being restored to bounds |
| 103 // which match the workspace bounds exactly so it is necessary to set | 197 // which match the workspace bounds exactly so it is necessary to set |
| 104 // the bounds again below. | 198 // the bounds again below. |
| 105 } | 199 } |
| 106 | 200 |
| 107 window_state->SetRestoreBoundsInParent(restore_bounds); | 201 window_state->SetRestoreBoundsInParent(restore_bounds); |
| 108 window->SetBounds(new_bounds); | 202 window->SetBounds(new_bounds); |
| 109 } | 203 } |
| 204 return true; | |
| 205 } | |
| 206 case TOGGLE_FULLSCREEN: { | |
| 207 // Window which cannot be maximized should not be fullscreened. | |
| 208 // It can, however, be restored if it was fullscreened. | |
| 209 bool is_fullscreen = window_state->IsFullscreen(); | |
| 210 if (!is_fullscreen && !window_state->CanMaximize()) | |
| 211 return true; | |
| 212 if (window_state->delegate() && | |
| 213 window_state->delegate()->ToggleFullscreen(window_state)) { | |
| 214 return true; | |
| 215 } | |
| 216 if (is_fullscreen) { | |
| 217 window_state->Restore(); | |
| 218 } else { | |
| 219 // | |
| 220 window_state->window()->SetProperty(aura::client::kShowStateKey, | |
| 221 ui::SHOW_STATE_FULLSCREEN); | |
| 222 } | |
| 223 return true; | |
| 224 } | |
| 225 case NORMAL: | |
| 226 case MAXIMIZE: | |
| 227 case MINIMIZE: | |
| 228 case FULLSCREEN: | |
| 229 case SNAP_LEFT: | |
| 230 case SNAP_RIGHT: | |
| 231 break; | |
| 232 } | |
| 233 return false; | |
| 234 } | |
| 235 | |
| 236 // static | |
| 237 void DefaultState::UpdateBoundsFromShowType(wm::WindowState* window_state, | |
|
oshima
2014/02/11 21:49:35
The code that updates window state in OnWindowShow
| |
| 238 wm::WindowShowType old_show_type) { | |
| 239 if (old_show_type != wm::SHOW_TYPE_MINIMIZED && | |
| 240 !window_state->HasRestoreBounds() && | |
| 241 window_state->IsMaximizedOrFullscreen() && | |
| 242 !wm::IsMaximizedOrFullscreenWindowShowType(old_show_type)) { | |
| 243 window_state->SaveCurrentBoundsForRestore(); | |
| 244 } | |
| 245 | |
| 246 // When restoring from a minimized state, we want to restore to the previous | |
| 247 // bounds. However, we want to maintain the restore bounds. (The restore | |
| 248 // bounds are set if a user maximized the window in one axis by double | |
| 249 // clicking the window border for example). | |
| 250 gfx::Rect restore; | |
| 251 if (old_show_type == wm::SHOW_TYPE_MINIMIZED && | |
| 252 window_state->IsNormalShowState() && | |
| 253 window_state->HasRestoreBounds() && | |
| 254 !window_state->unminimize_to_restore_bounds()) { | |
| 255 restore = window_state->GetRestoreBoundsInScreen(); | |
| 256 window_state->SaveCurrentBoundsForRestore(); | |
| 257 } | |
| 258 | |
| 259 aura::Window* window = window_state->window(); | |
| 260 if (window_state->IsMaximizedOrFullscreen()) | |
| 261 MoveToDisplayForRestore(window_state); | |
| 262 | |
| 263 gfx::Rect work_area_in_parent = | |
| 264 ScreenUtil::GetDisplayWorkAreaBoundsInParent(window_state->window()); | |
| 265 | |
| 266 wm::WindowShowType show_type = window_state->window_show_type(); | |
| 267 gfx::Rect bounds_in_parent; | |
| 268 switch (show_type) { | |
| 269 case wm::SHOW_TYPE_DEFAULT: | |
| 270 case wm::SHOW_TYPE_NORMAL: | |
| 271 case wm::SHOW_TYPE_LEFT_SNAPPED: | |
| 272 case wm::SHOW_TYPE_RIGHT_SNAPPED: | |
| 273 if (window_state->HasRestoreBounds()) | |
| 274 bounds_in_parent = window_state->GetRestoreBoundsInParent(); | |
| 275 else | |
| 276 bounds_in_parent = window->bounds(); | |
| 277 // Make sure that part of the window is always visible. | |
| 278 wm::AdjustBoundsToEnsureMinimumWindowVisibility( | |
| 279 work_area_in_parent, &bounds_in_parent); | |
| 280 | |
| 281 if (show_type == wm::SHOW_TYPE_LEFT_SNAPPED || | |
| 282 show_type == wm::SHOW_TYPE_RIGHT_SNAPPED) { | |
| 283 window_state->AdjustSnappedBounds(&bounds_in_parent); | |
| 284 } else { | |
| 285 bounds_in_parent = BoundsWithScreenEdgeVisible( | |
| 286 window, | |
| 287 bounds_in_parent); | |
| 288 } | |
| 289 break; | |
| 290 | |
| 291 case wm::SHOW_TYPE_MAXIMIZED: | |
| 292 bounds_in_parent = ScreenUtil::GetMaximizedWindowBoundsInParent(window); | |
| 293 break; | |
| 294 | |
| 295 case wm::SHOW_TYPE_FULLSCREEN: | |
| 296 bounds_in_parent = ScreenUtil::GetDisplayBoundsInParent(window); | |
| 297 break; | |
| 298 | |
| 299 case wm::SHOW_TYPE_MINIMIZED: | |
| 300 break; | |
| 301 case wm::SHOW_TYPE_INACTIVE: | |
| 302 case wm::SHOW_TYPE_DETACHED: | |
| 303 case wm::SHOW_TYPE_END: | |
| 304 case wm::SHOW_TYPE_AUTO_POSITIONED: | |
| 305 return; | |
| 306 } | |
| 307 | |
| 308 if (show_type != wm::SHOW_TYPE_MINIMIZED) { | |
| 309 if (old_show_type == wm::SHOW_TYPE_MINIMIZED || | |
| 310 (window_state->IsFullscreen() && | |
| 311 !window_state->animate_to_fullscreen())) { | |
| 312 window_state->SetBoundsDirect(bounds_in_parent); | |
| 313 } else if (window_state->IsMaximizedOrFullscreen() || | |
| 314 IsMaximizedOrFullscreenWindowShowType(old_show_type)) { | |
| 315 CrossFadeToBounds(window, bounds_in_parent); | |
| 316 } else { | |
| 317 window_state->SetBoundsDirectAnimated(bounds_in_parent); | |
| 110 } | 318 } |
| 111 } | 319 } |
| 112 }; | 320 |
| 321 if (window_state->IsMinimized()) { | |
| 322 if (old_show_type == wm::SHOW_TYPE_MINIMIZED) | |
| 323 return; | |
| 324 | |
| 325 // Save the previous show state so that we can correctly restore it. | |
| 326 window_state->window()->SetProperty(aura::client::kRestoreShowStateKey, | |
| 327 wm::ToWindowShowState(old_show_type)); | |
| 328 views::corewm::SetWindowVisibilityAnimationType( | |
| 329 window_state->window(), WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE); | |
| 330 | |
| 331 // Hide the window. | |
| 332 window_state->window()->Hide(); | |
| 333 // Activate another window. | |
| 334 if (window_state->IsActive()) | |
| 335 window_state->Deactivate(); | |
| 336 } else if ((window_state->window()->TargetVisibility() || | |
| 337 old_show_type == wm::SHOW_TYPE_MINIMIZED) && | |
| 338 !window_state->window()->layer()->visible()) { | |
| 339 // The layer may be hidden if the window was previously minimized. Make | |
| 340 // sure it's visible. | |
| 341 window_state->window()->Show(); | |
| 342 if (old_show_type == wm::SHOW_TYPE_MINIMIZED && | |
| 343 !window_state->IsMaximizedOrFullscreen()) { | |
| 344 window_state->set_unminimize_to_restore_bounds(false); | |
| 345 } | |
| 346 } | |
| 347 | |
| 348 if (window_state->IsNormalShowState()) | |
| 349 window_state->ClearRestoreBounds(); | |
| 350 | |
| 351 // Set the restore rectangle to the previously set restore rectangle. | |
| 352 if (!restore.IsEmpty()) | |
| 353 window_state->SetRestoreBoundsInScreen(restore); | |
| 354 } | |
| 113 | 355 |
| 114 } // namespace wm | 356 } // namespace wm |
| 115 } // namespace ash | 357 } // namespace ash |
| OLD | NEW |