1 // Copyright 2013 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 #ifndef ASH_WM_WINDOW_STATE_H_ 6 #define ASH_WM_WINDOW_STATE_H_ 7 8 #include <memory> 9 10 #include "ash/ash_export.h" 11 #include "ash/display/persistent_window_info.h" 12 #include "ash/wm/drag_details.h" 13 #include "base/gtest_prod_util.h" 14 #include "base/macros.h" 15 #include "base/observer_list.h" 16 #include "base/optional.h" 17 #include "ui/aura/window_observer.h" 18 #include "ui/base/ui_base_types.h" 19 #include "ui/compositor/layer_owner.h" 20 #include "ui/display/display.h" 21 #include "ui/gfx/animation/tween.h" 22 23 namespace chromeos { 24 enum class WindowPinType; 25 enum class WindowStateType; 26 } 27 28 namespace gfx { 29 class Rect; 30 } 31 32 namespace ash { 33 class ClientControlledState; 34 class LockWindowState; 35 class TabletModeWindowState; 36 class WindowState; 37 class WindowStateDelegate; 38 class WindowStateObserver; 39 class WMEvent; 40 41 // WindowState manages and defines ash specific window state and 42 // behavior. Ash specific per-window state (such as ones that controls 43 // window manager behavior) and ash specific window behavior (such as 44 // maximize, minimize, snap sizing etc) should be added here instead 45 // of defining separate functions (like |MaximizeWindow(aura::Window* 46 // window)|) or using aura Window property. 47 // The WindowState gets created when first accessed by 48 // |WindowState::Get()|, and deleted when the window is deleted. 49 // Prefer using this class instead of passing aura::Window* around in 50 // ash code as this is often what you need to interact with, and 51 // accessing the window using |window()| is cheap. 52 class ASH_EXPORT WindowState : public aura::WindowObserver { 53 public: 54 // The default duration for an animation between two sets of bounds. 55 static constexpr base::TimeDelta kBoundsChangeSlideDuration = 56 base::TimeDelta::FromMilliseconds(120); 57 58 // A subclass of State class represents one of the window's states 59 // that corresponds to chromeos::WindowStateType in Ash environment, e.g. 60 // maximized, minimized or side snapped, as subclass. 61 // Each subclass defines its own behavior and transition for each WMEvent. 62 class State { 63 public: State()64 State() {} ~State()65 virtual ~State() {} 66 67 // Update WindowState based on |event|. 68 virtual void OnWMEvent(WindowState* window_state, const WMEvent* event) = 0; 69 70 virtual chromeos::WindowStateType GetType() const = 0; 71 72 // Gets called when the state object became active and the managed window 73 // needs to be adjusted to the State's requirement. 74 // The passed |previous_state| may be used to properly implement state 75 // transitions such as bound animations from the previous state. 76 // Note: This only gets called when the state object gets changed. 77 virtual void AttachState(WindowState* window_state, 78 State* previous_state) = 0; 79 80 // Gets called before the state objects gets deactivated / detached from the 81 // window, so that it can save the various states it is interested in. 82 // Note: This only gets called when the state object gets changed. 83 virtual void DetachState(WindowState* window_state) = 0; 84 85 // Called when the window is being destroyed. OnWindowDestroying(WindowState * window_state)86 virtual void OnWindowDestroying(WindowState* window_state) {} 87 88 private: 89 DISALLOW_COPY_AND_ASSIGN(State); 90 }; 91 92 // Returns the WindowState for |window|. Creates WindowState if it doesn't 93 // exist. The returned value is owned by |window| (you should not delete it). 94 static WindowState* Get(aura::Window* window); 95 static const WindowState* Get(const aura::Window* window); 96 97 // Returns the WindowState for the active window, null if there is no active 98 // window. 99 static WindowState* ForActiveWindow(); 100 101 // Call WindowState::Get() to instantiate this class. 102 ~WindowState() override; 103 window()104 aura::Window* window() { return window_; } window()105 const aura::Window* window() const { return window_; } 106 107 bool HasDelegate() const; 108 void SetDelegate(std::unique_ptr<WindowStateDelegate> delegate); 109 110 // Returns the window's current ash state type. 111 // Refer to chromeos::WindowStateType definition in wm_types.h as for why Ash 112 // has its own state type. 113 chromeos::WindowStateType GetStateType() const; 114 115 // Predicates to check window state. 116 bool IsMinimized() const; 117 bool IsMaximized() const; 118 bool IsFullscreen() const; 119 bool IsSnapped() const; 120 bool IsPinned() const; 121 bool IsTrustedPinned() const; 122 bool IsPip() const; 123 124 // True if the window's state type is chromeos::WindowStateType::kMaximized, 125 // chromeos::WindowStateType::kFullscreen or 126 // chromeos::WindowStateType::kPinned. 127 bool IsMaximizedOrFullscreenOrPinned() const; 128 129 // True if the window's state type is chromeos::WindowStateType::kNormal or 130 // chromeos::WindowStateType::kDefault. 131 bool IsNormalStateType() const; 132 133 bool IsNormalOrSnapped() const; 134 135 bool IsActive() const; 136 137 // Returns true if the window's location can be controlled by the user. 138 bool IsUserPositionable() const; 139 140 // Checks if the window can change its state accordingly. 141 bool CanMaximize() const; 142 bool CanMinimize() const; 143 bool CanResize() const; 144 bool CanSnap() const; 145 bool CanActivate() const; 146 147 // Returns true if the window has restore bounds. 148 bool HasRestoreBounds() const; 149 150 // These methods use aura::WindowProperty to change the window's state 151 // instead of using WMEvent directly. This is to use the same mechanism as 152 // what views::Widget is using. 153 void Maximize(); 154 void Minimize(); 155 void Unminimize(); 156 157 void Activate(); 158 void Deactivate(); 159 160 // Set the window state to normal. 161 // TODO(oshima): Change to use RESTORE event. 162 void Restore(); 163 164 // Caches, then disables z-ordering state and then stacks |window_| below 165 // |window_on_top| if |window_| currently has a special z-order. 166 void DisableZOrdering(aura::Window* window_on_top); 167 168 // Restores the z-ordering state that a window might have cached. 169 void RestoreZOrdering(); 170 171 // Invoked when a WMevent occurs, which drives the internal 172 // state machine. 173 void OnWMEvent(const WMEvent* event); 174 175 // TODO(oshima): Try hiding these methods and making them accessible only to 176 // state impl. State changes should happen through events (as much 177 // as possible). 178 179 // Saves the current bounds to be used as a restore bounds. 180 void SaveCurrentBoundsForRestore(); 181 182 // Same as |GetRestoreBoundsInScreen| except that it returns the 183 // bounds in the parent's coordinates. 184 gfx::Rect GetRestoreBoundsInParent() const; 185 186 // Returns the restore bounds property on the window in the virtual screen 187 // coordinates. The bounds can be NULL if the bounds property does not 188 // exist for the window. The window owns the bounds object. 189 gfx::Rect GetRestoreBoundsInScreen() const; 190 191 // Same as |SetRestoreBoundsInScreen| except that the bounds is in the 192 // parent's coordinates. 193 void SetRestoreBoundsInParent(const gfx::Rect& bounds_in_parent); 194 195 // Sets the restore bounds property on the window in the virtual screen 196 // coordinates. Deletes existing bounds value if exists. 197 void SetRestoreBoundsInScreen(const gfx::Rect& bounds_in_screen); 198 199 // Deletes and clears the restore bounds property on the window. 200 void ClearRestoreBounds(); 201 202 // Replace the State object of a window with a state handler which can 203 // implement a new window manager type. The passed object will be owned 204 // by this object and the returned object will be owned by the caller. 205 std::unique_ptr<State> SetStateObject(std::unique_ptr<State> new_state); 206 207 // Updates |snapped_width_ratio_| based on |event|. 208 void UpdateSnappedWidthRatio(const WMEvent* event); snapped_width_ratio()209 base::Optional<float> snapped_width_ratio() const { 210 return snapped_width_ratio_; 211 } 212 213 // True if the window should be unminimized to the restore bounds, as 214 // opposed to the window's current bounds. |unminimized_to_restore_bounds_| is 215 // reset to the default value after the window is unminimized. unminimize_to_restore_bounds()216 bool unminimize_to_restore_bounds() const { 217 return unminimize_to_restore_bounds_; 218 } set_unminimize_to_restore_bounds(bool value)219 void set_unminimize_to_restore_bounds(bool value) { 220 unminimize_to_restore_bounds_ = value; 221 } 222 223 // Gets/sets whether the shelf should be hidden when this window is 224 // fullscreen. 225 bool GetHideShelfWhenFullscreen() const; 226 void SetHideShelfWhenFullscreen(bool value); 227 228 // Gets/sets whether the shelf should be autohidden when this window is 229 // fullscreen or active. 230 // Note: if true, this will override the logic controlled by 231 // hide_shelf_when_fullscreen. autohide_shelf_when_maximized_or_fullscreen()232 bool autohide_shelf_when_maximized_or_fullscreen() const { 233 return autohide_shelf_when_maximized_or_fullscreen_; 234 } 235 set_autohide_shelf_when_maximized_or_fullscreen(bool value)236 void set_autohide_shelf_when_maximized_or_fullscreen(bool value) { 237 autohide_shelf_when_maximized_or_fullscreen_ = value; 238 } 239 240 // Gets/Sets the bounds of the window before it was moved by the auto window 241 // management. As long as it was not auto-managed, it will return NULL. pre_auto_manage_window_bounds()242 const base::Optional<gfx::Rect> pre_auto_manage_window_bounds() { 243 return pre_auto_manage_window_bounds_; 244 } 245 void SetPreAutoManageWindowBounds(const gfx::Rect& bounds); 246 247 // Gets/Sets the property that is used on window added to workspace event. pre_added_to_workspace_window_bounds()248 const base::Optional<gfx::Rect> pre_added_to_workspace_window_bounds() { 249 return pre_added_to_workspace_window_bounds_; 250 } 251 void SetPreAddedToWorkspaceWindowBounds(const gfx::Rect& bounds); 252 253 // Gets/Sets the persistent window info that is used on restoring persistent 254 // window bounds in multi-displays scenario. persistent_window_info()255 const base::Optional<PersistentWindowInfo> persistent_window_info() { 256 return persistent_window_info_; 257 } 258 void SetPersistentWindowInfo( 259 const PersistentWindowInfo& persistent_window_info); 260 void ResetPersistentWindowInfo(); 261 262 // Layout related properties 263 264 void AddObserver(WindowStateObserver* observer); 265 void RemoveObserver(WindowStateObserver* observer); 266 267 // Whether the window is being dragged. is_dragged()268 bool is_dragged() const { return !!drag_details_; } 269 270 // Whether or not the window's position can be managed by the 271 // auto management logic. 272 bool GetWindowPositionManaged() const; 273 void SetWindowPositionManaged(bool managed); 274 275 // Whether or not the window's position or size was changed by a user. bounds_changed_by_user()276 bool bounds_changed_by_user() const { return bounds_changed_by_user_; } 277 void set_bounds_changed_by_user(bool bounds_changed_by_user); 278 279 // True if the window should be offered a chance to consume special system 280 // keys such as brightness, volume, etc. that are usually handled by the 281 // shell. 282 bool CanConsumeSystemKeys() const; 283 void SetCanConsumeSystemKeys(bool can_consume_system_keys); 284 285 // True if the window is in "immersive full screen mode" which is slightly 286 // different from the normal fullscreen mode by allowing the user to reveal 287 // the top portion of the window through a touch / mouse gesture. It might 288 // also allow the shelf to be shown in some situations. 289 bool IsInImmersiveFullscreen() const; 290 291 // True if the window should not adjust the window's bounds when 292 // virtual keyboard bounds changes. 293 // TODO(oshima): This is hack. Replace this with proper 294 // implementation based on EnsureCaretNotInRect. ignore_keyboard_bounds_change()295 bool ignore_keyboard_bounds_change() const { 296 return ignore_keyboard_bounds_change_; 297 } set_ignore_keyboard_bounds_change(bool ignore_keyboard_bounds_change)298 void set_ignore_keyboard_bounds_change(bool ignore_keyboard_bounds_change) { 299 ignore_keyboard_bounds_change_ = ignore_keyboard_bounds_change; 300 } 301 302 // True if the window bounds can be updated directly using SET_BOUNDS event. set_allow_set_bounds_direct(bool value)303 void set_allow_set_bounds_direct(bool value) { 304 allow_set_bounds_direct_ = value; 305 } allow_set_bounds_direct()306 bool allow_set_bounds_direct() const { return allow_set_bounds_direct_; } 307 308 // Creates and takes ownership of a pointer to DragDetails when resizing is 309 // active. This should be done before a resizer gets created. 310 void CreateDragDetails(const gfx::PointF& point_in_parent, 311 int window_component, 312 ::wm::WindowMoveSource source); 313 314 // Deletes and clears a pointer to DragDetails. This should be done when the 315 // resizer gets destroyed. 316 void DeleteDragDetails(); 317 318 // Sets the currently stored restore bounds and clears the restore bounds. 319 void SetAndClearRestoreBounds(); 320 321 // Notifies that the drag operation has been started. 322 void OnDragStarted(int window_component); 323 324 // Notifies that the drag operation has been either completed or reverted. 325 // |location| is the last position of the pointer device used to drag. 326 void OnCompleteDrag(const gfx::PointF& location); 327 void OnRevertDrag(const gfx::PointF& location); 328 329 // Notifies that the window lost the activation. 330 void OnActivationLost(); 331 332 // Returns a pointer to DragDetails during drag operations. drag_details()333 const DragDetails* drag_details() const { return drag_details_.get(); } drag_details()334 DragDetails* drag_details() { return drag_details_.get(); } 335 336 // Returns the Display that this WindowState is on. 337 display::Display GetDisplay(); 338 339 class TestApi { 340 public: GetStateImpl(WindowState * window_state)341 static State* GetStateImpl(WindowState* window_state) { 342 return window_state->current_state_.get(); 343 } 344 }; 345 346 private: 347 friend class BaseState; 348 friend class ClientControlledState; 349 friend class DefaultState; 350 friend class LockWindowState; 351 friend class TabletModeWindowState; 352 friend class ScopedBoundsChangeAnimation; 353 FRIEND_TEST_ALL_PREFIXES(WindowAnimationsTest, CrossFadeToBounds); 354 FRIEND_TEST_ALL_PREFIXES(WindowAnimationsTest, CrossFadeHistograms); 355 FRIEND_TEST_ALL_PREFIXES(WindowAnimationsTest, 356 CrossFadeToBoundsFromTransform); 357 FRIEND_TEST_ALL_PREFIXES(WindowStateTest, PipWindowMaskRecreated); 358 FRIEND_TEST_ALL_PREFIXES(WindowStateTest, PipWindowHasMaskLayer); 359 360 // Animation type of updating window bounds. "IMMEDIATE" means update bounds 361 // directly without animation. "STEP_END" means update bounds at the end of 362 // the animation. 363 enum class BoundsChangeAnimationType { DEFAULT, IMMEDIATE, STEP_END }; 364 365 // A class can temporarily change the window bounds change animation type. 366 class ScopedBoundsChangeAnimation : public aura::WindowObserver { 367 public: 368 ScopedBoundsChangeAnimation(aura::Window* window, 369 BoundsChangeAnimationType animation_type); 370 ~ScopedBoundsChangeAnimation() override; 371 372 // aura::WindowObserver: 373 void OnWindowDestroying(aura::Window* window) override; 374 375 private: 376 aura::Window* window_; 377 BoundsChangeAnimationType previous_bounds_animation_type_; 378 379 DISALLOW_COPY_AND_ASSIGN(ScopedBoundsChangeAnimation); 380 }; 381 382 explicit WindowState(aura::Window* window); 383 delegate()384 WindowStateDelegate* delegate() { return delegate_.get(); } bounds_animation_type()385 BoundsChangeAnimationType bounds_animation_type() { 386 return bounds_animation_type_; 387 } 388 389 bool HasMaximumWidthOrHeight() const; 390 391 // Returns the window's current z-ordering state. 392 ui::ZOrderLevel GetZOrdering() const; 393 394 // Returns the window's current show state. 395 ui::WindowShowState GetShowState() const; 396 397 // Return the window's current pin type. 398 chromeos::WindowPinType GetPinType() const; 399 400 // Sets the window's bounds in screen coordinates. 401 void SetBoundsInScreen(const gfx::Rect& bounds_in_screen); 402 403 // Adjusts the |bounds| so that they are flush with the edge of the 404 // workspace if the window represented by |window_state| is side snapped. It 405 // is called for workspace events. 406 void AdjustSnappedBounds(gfx::Rect* bounds); 407 408 // Updates the window properties(show state, pin type) according to the 409 // current window state type. 410 // Note that this does not update the window bounds. 411 void UpdateWindowPropertiesFromStateType(); 412 413 void NotifyPreStateTypeChange( 414 chromeos::WindowStateType old_window_state_type); 415 void NotifyPostStateTypeChange( 416 chromeos::WindowStateType old_window_state_type); 417 418 // Sets |bounds| as is and ensure the layer is aligned with pixel boundary. 419 void SetBoundsDirect(const gfx::Rect& bounds); 420 421 // Sets the window's |bounds| with constraint where the size of the 422 // new bounds will not exceeds the size of the work area. 423 void SetBoundsConstrained(const gfx::Rect& bounds); 424 425 // Sets the wndow's |bounds| and transitions to the new bounds with 426 // a scale animation, with duration specified by |duration|. 427 void SetBoundsDirectAnimated( 428 const gfx::Rect& bounds, 429 base::TimeDelta duration = kBoundsChangeSlideDuration, 430 gfx::Tween::Type animation_type = gfx::Tween::LINEAR); 431 432 // Sets the window's |bounds| and transition to the new bounds with 433 // a cross fade animation. 434 void SetBoundsDirectCrossFade(const gfx::Rect& bounds); 435 436 // Called before the state change and update PIP related state, such as next 437 // window animation type, upon state change. 438 void OnPrePipStateChange(chromeos::WindowStateType old_window_state_type); 439 440 // Called after the state change and update PIP related state, such as next 441 // window animation type, upon state change. 442 void OnPostPipStateChange(chromeos::WindowStateType old_window_state_type); 443 444 // Update the PIP bounds if necessary. This may need to happen when the 445 // display work area changes, or if system ui regions like the virtual 446 // keyboard position changes. 447 void UpdatePipBounds(); 448 449 // Collects PIP enter and exit metrics: 450 void CollectPipEnterExitMetrics(bool enter); 451 452 // aura::WindowObserver: 453 void OnWindowPropertyChanged(aura::Window* window, 454 const void* key, 455 intptr_t old) override; 456 void OnWindowAddedToRootWindow(aura::Window* window) override; 457 void OnWindowDestroying(aura::Window* window) override; 458 void OnWindowBoundsChanged(aura::Window* window, 459 const gfx::Rect& old_bounds, 460 const gfx::Rect& new_bounds, 461 ui::PropertyChangeReason reason) override; 462 463 // The owner of this window settings. 464 aura::Window* window_; 465 std::unique_ptr<WindowStateDelegate> delegate_; 466 467 bool bounds_changed_by_user_; 468 bool can_consume_system_keys_; 469 std::unique_ptr<DragDetails> drag_details_; 470 471 bool unminimize_to_restore_bounds_; 472 bool ignore_keyboard_bounds_change_ = false; 473 bool hide_shelf_when_fullscreen_; 474 bool autohide_shelf_when_maximized_or_fullscreen_; 475 ui::ZOrderLevel cached_z_order_; 476 bool allow_set_bounds_direct_ = false; 477 478 // A property to save the ratio between snapped window width and display 479 // workarea width. It is used to update snapped window width on 480 // AdjustSnappedBounds() when handling workspace events. 481 base::Optional<float> snapped_width_ratio_; 482 483 // A property to remember the window position which was set before the 484 // auto window position manager changed the window bounds, so that it can 485 // get restored when only this one window gets shown. 486 base::Optional<gfx::Rect> pre_auto_manage_window_bounds_; 487 488 // A property which resets when bounds is changed by user and sets when it 489 // is nullptr, and window is removing from a workspace. 490 base::Optional<gfx::Rect> pre_added_to_workspace_window_bounds_; 491 492 // A property to remember the persistent window info used in multi-displays 493 // scenario to attempt to restore windows to their original bounds when 494 // displays are restored to their previous states. 495 base::Optional<PersistentWindowInfo> persistent_window_info_; 496 497 base::ObserverList<WindowStateObserver>::Unchecked observer_list_; 498 499 // True to ignore a property change event to avoid reentrance in 500 // UpdateWindowStateType() 501 bool ignore_property_change_; 502 503 std::unique_ptr<State> current_state_; 504 505 // The animation type for the bounds change. 506 BoundsChangeAnimationType bounds_animation_type_ = 507 BoundsChangeAnimationType::DEFAULT; 508 509 // When the current (or last) PIP session started. 510 base::TimeTicks pip_start_time_; 511 512 DISALLOW_COPY_AND_ASSIGN(WindowState); 513 }; 514 515 } // namespace ash 516 517 #endif // ASH_WM_WINDOW_STATE_H_ 518