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_OVERVIEW_OVERVIEW_ITEM_H_ 6 #define ASH_WM_OVERVIEW_OVERVIEW_ITEM_H_ 7 8 #include <memory> 9 10 #include "ash/ash_export.h" 11 #include "ash/wm/overview/overview_session.h" 12 #include "ash/wm/overview/scoped_overview_transform_window.h" 13 #include "ash/wm/window_state_observer.h" 14 #include "base/macros.h" 15 #include "base/memory/weak_ptr.h" 16 #include "base/optional.h" 17 #include "ui/aura/window.h" 18 #include "ui/aura/window_observer.h" 19 #include "ui/gfx/geometry/rect.h" 20 #include "ui/gfx/geometry/rect_f.h" 21 #include "ui/views/controls/button/button.h" 22 23 namespace ui { 24 class Shadow; 25 } // namespace ui 26 27 namespace views { 28 class Widget; 29 } // namespace views 30 31 namespace ash { 32 class DragWindowController; 33 class OverviewGrid; 34 class OverviewItemView; 35 class RoundedLabelWidget; 36 37 // This class represents an item in overview mode. 38 class ASH_EXPORT OverviewItem : public aura::WindowObserver, 39 public WindowStateObserver { 40 public: 41 OverviewItem(aura::Window* window, 42 OverviewSession* overview, 43 OverviewGrid* overview_grid); 44 ~OverviewItem() override; 45 46 aura::Window* GetWindow(); 47 48 // Returns true if |target| is contained in this OverviewItem. 49 bool Contains(const aura::Window* target) const; 50 51 // This called when the window is dragged and dropped on the mini view of 52 // another desk, which prepares this item for being removed from the grid, and 53 // the window to restore its transform. 54 void OnMovingWindowToAnotherDesk(); 55 56 // Restores and animates the managed window to its non overview mode state. 57 // If |reset_transform| equals false, the window's transform will not be 58 // reset to identity transform when exiting overview mode. It's needed when 59 // dragging an Arc app window in overview mode to put it in split screen. In 60 // this case the restore of its transform needs to be deferred until the Arc 61 // app window is snapped successfully, otherwise the animation will look very 62 // ugly (the Arc app window enlarges itself to maximized window bounds and 63 // then shrinks to its snapped window bounds). Note if the window's transform 64 // is not reset here, it must be reset by someone else at some point. 65 void RestoreWindow(bool reset_transform); 66 67 // Ensures that a possibly minimized window becomes visible after restore. 68 void EnsureVisible(); 69 70 // Restores stacking of window captions above the windows, then fades out. 71 void Shutdown(); 72 73 // Dispatched before beginning window overview. This will do any necessary 74 // one time actions such as restoring minimized windows. 75 void PrepareForOverview(); 76 77 // Calculates and returns an optimal scale ratio. With MD this is only 78 // taking into account |size.height()| as the width can vary. Without MD this 79 // returns the scale that allows the item to fully fit within |size|. 80 float GetItemScale(const gfx::Size& size); 81 82 // Returns the union of the original target bounds of all transformed windows 83 // managed by |this| item, i.e. all regular (normal or panel transient 84 // descendants of the window returned by GetWindow()). 85 gfx::RectF GetTargetBoundsInScreen() const; 86 87 // Returns the transformed bound of |transform_window_|. 88 gfx::RectF GetTransformedBounds() const; 89 90 // Sets the bounds of this overview item to |target_bounds| in the 91 // |root_window_| root window. The bounds change will be animated as specified 92 // by |animation_type|. 93 void SetBounds(const gfx::RectF& target_bounds, 94 OverviewAnimationType animation_type); 95 96 // Sends an accessibility event indicating that this window became selected 97 // so that it is highlighted and announced. 98 void SendAccessibleSelectionEvent(); 99 100 // Slides the item up or down and then closes the associated window. Used by 101 // overview swipe to close. 102 void AnimateAndCloseWindow(bool up); 103 104 // Closes |transform_window_|. 105 void CloseWindow(); 106 107 // Shows the cannot snap warning if currently in splitview, and the associated 108 // window cannot be snapped. 109 void UpdateCannotSnapWarningVisibility(); 110 111 // Hides the cannot snap warning (if it was showing) until the next call to 112 // |UpdateCannotSnapWarningVisibility|. 113 void HideCannotSnapWarning(); 114 115 // Called when a OverviewItem on any grid is dragged. Hides the close button 116 // when a drag is started, and reshows it when a drag is finished. 117 // Additionally hides the title and window icon if |item| is this. 118 void OnSelectorItemDragStarted(OverviewItem* item); 119 void OnSelectorItemDragEnded(bool snap); 120 121 // Shows/Hides window item during window dragging. Used when swiping up a 122 // window from shelf. 123 void SetVisibleDuringWindowDragging(bool visible, bool animate); 124 125 OverviewGridWindowFillMode GetWindowDimensionsType() const; 126 127 // Recalculates the window dimensions type of |transform_window_|. Called when 128 // |window_|'s bounds change. 129 void UpdateWindowDimensionsType(); 130 131 // TODO(minch): Do not actually scale up the item to get the bounds. 132 // http://crbug.com/876567. 133 // Returns the bounds of the selected item, which will be scaled up a little 134 // bit and header view will be hidden after being selected. Note, the item 135 // will be restored back after scaled up. 136 gfx::Rect GetBoundsOfSelectedItem(); 137 138 // Increases the bounds of the dragged item. 139 void ScaleUpSelectedItem(OverviewAnimationType animation_type); 140 141 // If the window item represents a minimized window, update its content view. 142 void UpdateItemContentViewForMinimizedWindow(); 143 144 // Checks if this item is currently being dragged. 145 bool IsDragItem(); 146 147 // Inserts the window back to its original stacking order so that the order of 148 // windows is the same as when entering overview. 149 void Restack(); 150 151 // Updates |phantoms_for_dragging_|. If |phantoms_for_dragging_| is null, then 152 // a new object is created for it. 153 void UpdatePhantomsForDragging(bool is_touch_dragging); 154 155 void DestroyPhantomsForDragging(); 156 157 // Sets the bounds of the window shadow. If |bounds_in_screen| is nullopt, 158 // the shadow is hidden. 159 void SetShadowBounds(base::Optional<gfx::RectF> bounds_in_screen); 160 161 // Updates the rounded corners and shadow on this overview window item. 162 void UpdateRoundedCornersAndShadow(); 163 164 // Called when the starting animation is completed, or called immediately 165 // if there was no starting animation. 166 void OnStartingAnimationComplete(); 167 168 // Stops the current animation of |item_widget_|. 169 void StopWidgetAnimation(); 170 171 // Changes the opacity of all the windows the item owns. 172 void SetOpacity(float opacity); 173 float GetOpacity(); 174 175 OverviewAnimationType GetExitOverviewAnimationType(); 176 OverviewAnimationType GetExitTransformAnimationType(); 177 178 // If kNewOverviewLayout is on, use this function for handling events. 179 void HandleGestureEventForTabletModeLayout(ui::GestureEvent* event); 180 181 // Handles events forwarded from |overview_item_view_|. 182 void HandleMouseEvent(const ui::MouseEvent& event); 183 void HandleGestureEvent(ui::GestureEvent* event); 184 void OnHighlightedViewActivated(); 185 void OnHighlightedViewClosed(); 186 187 // aura::WindowObserver: 188 void OnWindowPropertyChanged(aura::Window* window, 189 const void* key, 190 intptr_t old) override; 191 void OnWindowBoundsChanged(aura::Window* window, 192 const gfx::Rect& old_bounds, 193 const gfx::Rect& new_bounds, 194 ui::PropertyChangeReason reason) override; 195 void OnWindowDestroying(aura::Window* window) override; 196 197 // WindowStateObserver: 198 void OnPreWindowStateTypeChange(WindowState* window_state, 199 chromeos::WindowStateType old_type) override; 200 void OnPostWindowStateTypeChange(WindowState* window_state, 201 chromeos::WindowStateType old_type) override; 202 203 // Returns the root window on which this item is shown. root_window()204 aura::Window* root_window() { return root_window_; } 205 target_bounds()206 const gfx::RectF& target_bounds() const { return target_bounds_; } 207 item_widget()208 views::Widget* item_widget() { return item_widget_.get(); } 209 overview_item_view()210 OverviewItemView* overview_item_view() { return overview_item_view_; } 211 overview_grid()212 OverviewGrid* overview_grid() { return overview_grid_; } 213 is_moving_to_another_desk()214 bool is_moving_to_another_desk() const { return is_moving_to_another_desk_; } 215 set_should_use_spawn_animation(bool value)216 void set_should_use_spawn_animation(bool value) { 217 should_use_spawn_animation_ = value; 218 } should_use_spawn_animation()219 bool should_use_spawn_animation() const { 220 return should_use_spawn_animation_; 221 } 222 set_should_animate_when_entering(bool should_animate)223 void set_should_animate_when_entering(bool should_animate) { 224 should_animate_when_entering_ = should_animate; 225 } should_animate_when_entering()226 bool should_animate_when_entering() const { 227 return should_animate_when_entering_; 228 } 229 set_should_animate_when_exiting(bool should_animate)230 void set_should_animate_when_exiting(bool should_animate) { 231 should_animate_when_exiting_ = should_animate; 232 } should_animate_when_exiting()233 bool should_animate_when_exiting() const { 234 return should_animate_when_exiting_; 235 } 236 set_should_restack_on_animation_end(bool val)237 void set_should_restack_on_animation_end(bool val) { 238 should_restack_on_animation_end_ = val; 239 } 240 set_animating_to_close(bool val)241 void set_animating_to_close(bool val) { animating_to_close_ = val; } animating_to_close()242 bool animating_to_close() const { return animating_to_close_; } 243 set_disable_mask(bool disable)244 void set_disable_mask(bool disable) { disable_mask_ = disable; } 245 set_unclipped_size(base::Optional<gfx::Size> unclipped_size)246 void set_unclipped_size(base::Optional<gfx::Size> unclipped_size) { 247 unclipped_size_ = unclipped_size; 248 } 249 250 gfx::Rect GetShadowBoundsForTesting(); cannot_snap_widget_for_testing()251 RoundedLabelWidget* cannot_snap_widget_for_testing() { 252 return cannot_snap_widget_.get(); 253 } set_target_bounds_for_testing(const gfx::RectF & target_bounds)254 void set_target_bounds_for_testing(const gfx::RectF& target_bounds) { 255 target_bounds_ = target_bounds; 256 } 257 258 private: 259 friend class OverviewSessionTest; 260 FRIEND_TEST_ALL_PREFIXES(SplitViewOverviewSessionTest, Clipping); 261 262 // Returns the target bounds of |window_|. Same as |target_bounds_|, with some 263 // insets. 264 gfx::RectF GetWindowTargetBoundsWithInsets() const; 265 266 // The shadow should match the size of the transformed window or preview 267 // window if unclipped. 268 gfx::RectF GetUnclippedShadowBounds() const; 269 270 // Functions to be called back when their associated animations complete. 271 void OnWindowCloseAnimationCompleted(); 272 void OnItemSpawnedAnimationCompleted(); 273 void OnItemBoundsAnimationStarted(); 274 void OnItemBoundsAnimationEnded(); 275 276 // Performs the spawn-item-in-overview animation (which is a fade-in plus 277 // scale-up animation), on the given |window|. |target_transform| is the final 278 // transform that should be applied to |window| at the end of the animation. 279 // |window| is either the real window associated with this item (from 280 // GetWindow()), or the `item_widget_->GetNativeWindow()` if the associated 281 // window is minimized. 282 void PerformItemSpawnedAnimation(aura::Window* window, 283 const gfx::Transform& target_transform); 284 285 // Sets the bounds of this overview item to |target_bounds| in |root_window_|. 286 // The bounds change will be animated as specified by |animation_type|. 287 // |is_first_update| is true when we set this item's bounds for the first 288 // time. 289 void SetItemBounds(const gfx::RectF& target_bounds, 290 OverviewAnimationType animation_type, 291 bool is_first_update); 292 293 // Creates |item_widget_|, which holds |overview_item_view_|. 294 void CreateItemWidget(); 295 296 // Updates the |item_widget|'s bounds. Any change in bounds will be animated 297 // from the current bounds to the new bounds as per the |animation_type|. 298 void UpdateHeaderLayout(OverviewAnimationType animation_type); 299 300 // Animates opacity of the |transform_window_| and its caption to |opacity| 301 // using |animation_type|. 302 void AnimateOpacity(float opacity, OverviewAnimationType animation_type); 303 304 // Called before dragging. Scales up the window a little bit to indicate its 305 // selection and stacks the window at the top of the Z order in order to keep 306 // it visible while dragging around. 307 void StartDrag(); 308 309 void CloseButtonPressed(); 310 311 // TODO(sammiequon): Current events go from OverviewItemView to 312 // OverviewItem to OverviewSession to OverviewWindowDragController. We may be 313 // able to shorten this pipeline. 314 void HandlePressEvent(const gfx::PointF& location_in_screen, 315 bool from_touch_gesture); 316 void HandleReleaseEvent(const gfx::PointF& location_in_screen); 317 void HandleDragEvent(const gfx::PointF& location_in_screen); 318 void HandleLongPressEvent(const gfx::PointF& location_in_screen); 319 void HandleFlingStartEvent(const gfx::PointF& location_in_screen, 320 float velocity_x, 321 float velocity_y); 322 void HandleTapEvent(); 323 void HandleGestureEndEvent(); 324 325 // Returns the list of windows that we want to slide up or down when swiping 326 // on the shelf in tablet mode. 327 aura::Window::Windows GetWindowsForHomeGesture(); 328 329 // The root window this item is being displayed on. 330 aura::Window* root_window_; 331 332 // The contained Window's wrapper. 333 ScopedOverviewTransformWindow transform_window_; 334 335 // The target bounds this overview item is fit within. When in splitview, 336 // |item_widget_| is fit within these bounds, but the window itself is 337 // transformed to |unclipped_size_|, and then clipped. 338 gfx::RectF target_bounds_; 339 340 // True if running SetItemBounds. This prevents recursive calls resulting from 341 // the bounds update when calling ::wm::RecreateWindowLayers to copy 342 // a window layer for display on another monitor. 343 bool in_bounds_update_ = false; 344 345 // A widget stacked under the |transform_window_|. The widget has 346 // |overview_item_view_| as its contents view. The widget is backed by a 347 // NOT_DRAWN layer since most of its surface is transparent. 348 std::unique_ptr<views::Widget> item_widget_; 349 350 // The view associated with |item_widget_|. Contains a title, close button and 351 // maybe a backdrop. Forwards certain events to |this|. 352 OverviewItemView* overview_item_view_ = nullptr; 353 354 // A widget with text that may show up on top of |transform_window_| to notify 355 // users this window cannot be snapped. 356 std::unique_ptr<RoundedLabelWidget> cannot_snap_widget_; 357 358 // Responsible for phantoms that look like the window on all displays during 359 // dragging. 360 std::unique_ptr<DragWindowController> phantoms_for_dragging_; 361 362 // Pointer to the Overview that owns the OverviewGrid containing |this|. 363 // Guaranteed to be non-null for the lifetime of |this|. 364 OverviewSession* overview_session_; 365 366 // Pointer to the OverviewGrid that contains |this|. Guaranteed to be non-null 367 // for the lifetime of |this|. 368 OverviewGrid* overview_grid_; 369 370 // True when the item is dragged and dropped on another desk's mini view. This 371 // causes it to restore its transform immediately without any animations, 372 // since it is moving to an inactive desk, and therefore won't be visible. 373 bool is_moving_to_another_desk_ = false; 374 375 // True if this item should be added to an active overview session using the 376 // spawn animation on its first update. This implies an animation type of 377 // OVERVIEW_ANIMATION_SPAWN_ITEM_IN_OVERVIEW. This value will be reset to 378 // false once the spawn animation is performed. 379 bool should_use_spawn_animation_ = false; 380 381 // True if the contained window should animate during the entering animation. 382 bool should_animate_when_entering_ = true; 383 384 // True if the contained window should animate during the exiting animation. 385 bool should_animate_when_exiting_ = true; 386 387 // True if after an animation, we need to reorder the stacking order of the 388 // widgets. 389 bool should_restack_on_animation_end_ = false; 390 391 // True if the windows are still alive so they can have a closing animation. 392 // These windows should not be used in calculations for 393 // OverviewGrid::PositionWindows. 394 bool animating_to_close_ = false; 395 396 // True if this overview item is currently being dragged around. 397 bool is_being_dragged_ = false; 398 399 // True to always disable mask regardless of the state. 400 bool disable_mask_ = false; 401 402 bool prepared_for_overview_ = false; 403 404 // This has a value when there is a snapped window, or a window about to be 405 // snapped (triggering a splitview preview area). This will be set when items 406 // are positioned in OverviewGrid. The bounds delivered in |SetBounds| are the 407 // true bounds of this item, but we want to maintain the aspect ratio of the 408 // window, who's bounds are not set to split view size. So in |SetItemBounds|, 409 // we transform the window not to |target_bounds_| but to this value, and then 410 // apply clipping on the window to |target_bounds_|. 411 base::Optional<gfx::Size> unclipped_size_ = base::nullopt; 412 413 // The shadow around the overview window. Shadows the original window, not 414 // |item_widget_|. Done here instead of on the original window because of the 415 // rounded edges mask applied on entering overview window. 416 std::unique_ptr<ui::Shadow> shadow_; 417 418 base::WeakPtrFactory<OverviewItem> weak_ptr_factory_{this}; 419 420 DISALLOW_COPY_AND_ASSIGN(OverviewItem); 421 }; 422 423 } // namespace ash 424 425 #endif // ASH_WM_OVERVIEW_OVERVIEW_ITEM_H_ 426