Home | History | Annotate | Download | only in wm
      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 "ash/ash_export.h"
      9 #include "ash/wm/drag_details.h"
     10 #include "ash/wm/wm_types.h"
     11 #include "base/basictypes.h"
     12 #include "base/gtest_prod_util.h"
     13 #include "base/memory/scoped_ptr.h"
     14 #include "base/observer_list.h"
     15 #include "ui/aura/window_observer.h"
     16 #include "ui/base/ui_base_types.h"
     17 
     18 namespace aura {
     19 class Window;
     20 }
     21 
     22 namespace gfx {
     23 class Rect;
     24 }
     25 
     26 namespace ash {
     27 class WorkspaceLayoutManager;
     28 class LockWindowState;
     29 class MaximizeModeWindowState;
     30 
     31 namespace wm {
     32 class WindowStateDelegate;
     33 class WindowStateObserver;
     34 class WMEvent;
     35 
     36 // WindowState manages and defines ash specific window state and
     37 // behavior. Ash specific per-window state (such as ones that controls
     38 // window manager behavior) and ash specific window behavior (such as
     39 // maximize, minimize, snap sizing etc) should be added here instead
     40 // of defining separate functions (like |MaximizeWindow(aura::Window*
     41 // window)|) or using aura Window property.
     42 // The WindowState gets created when first accessed by
     43 // |wm::GetWindowState|, and deleted when the window is deleted.
     44 // Prefer using this class instead of passing aura::Window* around in
     45 // ash code as this is often what you need to interact with, and
     46 // accessing the window using |window()| is cheap.
     47 class ASH_EXPORT WindowState : public aura::WindowObserver {
     48  public:
     49 
     50   // A subclass of State class represents one of the window's states
     51   // that corresponds to WindowStateType in Ash environment, e.g.
     52   // maximized, minimized or side snapped, as subclass.
     53   // Each subclass defines its own behavior and transition for each WMEvent.
     54   class State {
     55    public:
     56     State() {}
     57     virtual ~State() {}
     58 
     59     // Update WindowState based on |event|.
     60     virtual void OnWMEvent(WindowState* window_state, const WMEvent* event) = 0;
     61 
     62     virtual WindowStateType GetType() const = 0;
     63 
     64     // Gets called when the state object became active and the managed window
     65     // needs to be adjusted to the State's requirement.
     66     // The passed |previous_state| may be used to properly implement state
     67     // transitions such as bound animations from the previous state.
     68     // Note: This only gets called when the state object gets changed.
     69     virtual void AttachState(WindowState* window_state,
     70                              State* previous_state) = 0;
     71 
     72     // Gets called before the state objects gets deactivated / detached from the
     73     // window, so that it can save the various states it is interested in.
     74     // Note: This only gets called when the state object gets changed.
     75     virtual void DetachState(WindowState* window_state) = 0;
     76 
     77    private:
     78     DISALLOW_COPY_AND_ASSIGN(State);
     79   };
     80 
     81   // Call GetWindowState() to instantiate this class.
     82   virtual ~WindowState();
     83 
     84   aura::Window* window() { return window_; }
     85   const aura::Window* window() const { return window_; }
     86 
     87   bool HasDelegate() const;
     88   void SetDelegate(scoped_ptr<WindowStateDelegate> delegate);
     89 
     90   // Returns the window's current ash state type.
     91   // Refer to WindowStateType definition in wm_types.h as for why Ash
     92   // has its own state type.
     93   WindowStateType GetStateType() const;
     94 
     95   // Predicates to check window state.
     96   bool IsMinimized() const;
     97   bool IsMaximized() const;
     98   bool IsFullscreen() const;
     99   bool IsMaximizedOrFullscreen() const;
    100   bool IsSnapped() const;
    101 
    102   // True if the window's state type is WINDOW_STATE_TYPE_NORMAL or
    103   // WINDOW_STATE_TYPE_DEFAULT.
    104   bool IsNormalStateType() const;
    105 
    106   bool IsNormalOrSnapped() const;
    107 
    108   bool IsActive() const;
    109   bool IsDocked() const;
    110 
    111   // Checks if the window can change its state accordingly.
    112   bool CanMaximize() const;
    113   bool CanMinimize() const;
    114   bool CanResize() const;
    115   bool CanSnap() const;
    116   bool CanActivate() const;
    117 
    118   // Returns true if the window has restore bounds.
    119   bool HasRestoreBounds() const;
    120 
    121   // These methods use aura::WindowProperty to change the window's state
    122   // instead of using WMEvent directly. This is to use the same mechanism as
    123   // what views::Widget is using.
    124   void Maximize();
    125   void Minimize();
    126   void Unminimize();
    127 
    128   void Activate();
    129   void Deactivate();
    130 
    131   // Set the window state to normal.
    132   // TODO(oshima): Change to use RESTORE event.
    133   void Restore();
    134 
    135   // Invoked when a WMevent occurs, which drives the internal
    136   // state machine.
    137   void OnWMEvent(const WMEvent* event);
    138 
    139   // TODO(oshima): Try hiding these methods and making them accessible only to
    140   // state impl. State changes should happen through events (as much
    141   // as possible).
    142 
    143   // Saves the current bounds to be used as a restore bounds.
    144   void SaveCurrentBoundsForRestore();
    145 
    146   // Same as |GetRestoreBoundsInScreen| except that it returns the
    147   // bounds in the parent's coordinates.
    148   gfx::Rect GetRestoreBoundsInParent() const;
    149 
    150   // Returns the restore bounds property on the window in the virtual screen
    151   // coordinates. The bounds can be NULL if the bounds property does not
    152   // exist for the window. The window owns the bounds object.
    153   gfx::Rect GetRestoreBoundsInScreen() const;
    154 
    155   // Same as |SetRestoreBoundsInScreen| except that the bounds is in the
    156   // parent's coordinates.
    157   void SetRestoreBoundsInParent(const gfx::Rect& bounds_in_parent);
    158 
    159   // Sets the restore bounds property on the window in the virtual screen
    160   // coordinates.  Deletes existing bounds value if exists.
    161   void SetRestoreBoundsInScreen(const gfx::Rect& bounds_in_screen);
    162 
    163   // Deletes and clears the restore bounds property on the window.
    164   void ClearRestoreBounds();
    165 
    166   // Replace the State object of a window with a state handler which can
    167   // implement a new window manager type. The passed object will be owned
    168   // by this object and the returned object will be owned by the caller.
    169   scoped_ptr<State> SetStateObject(scoped_ptr<State> new_state);
    170 
    171   // True if the window should be unminimized to the restore bounds, as
    172   // opposed to the window's current bounds. |unminimized_to_restore_bounds_| is
    173   // reset to the default value after the window is unminimized.
    174   bool unminimize_to_restore_bounds() const {
    175     return unminimize_to_restore_bounds_;
    176   }
    177   void set_unminimize_to_restore_bounds(bool value) {
    178     unminimize_to_restore_bounds_ = value;
    179   }
    180 
    181   // Gets/sets whether the shelf should be hidden when this window is
    182   // fullscreen.
    183   bool hide_shelf_when_fullscreen() const {
    184     return hide_shelf_when_fullscreen_;
    185   }
    186 
    187   void set_hide_shelf_when_fullscreen(bool value) {
    188     hide_shelf_when_fullscreen_ = value;
    189   }
    190 
    191   // If the minimum visibilty is true, ash will try to keep a
    192   // minimum amount of the window is always visible on the work area
    193   // when shown.
    194   // TODO(oshima): Consolidate this and window_position_managed
    195   // into single parameter to control the window placement.
    196   bool minimum_visibility() const {
    197     return minimum_visibility_;
    198   }
    199   void set_minimum_visibility(bool minimum_visibility) {
    200     minimum_visibility_ = minimum_visibility;
    201   }
    202 
    203   // Specifies if the window can be dragged by the user via the caption or not.
    204   bool can_be_dragged() const {
    205     return can_be_dragged_;
    206   }
    207   void set_can_be_dragged(bool can_be_dragged) {
    208     can_be_dragged_ = can_be_dragged;
    209   }
    210 
    211   // Gets/Sets the bounds of the window before it was moved by the auto window
    212   // management. As long as it was not auto-managed, it will return NULL.
    213   const gfx::Rect* pre_auto_manage_window_bounds() const {
    214     return pre_auto_manage_window_bounds_.get();
    215   }
    216   void SetPreAutoManageWindowBounds(const gfx::Rect& bounds);
    217 
    218   // Layout related properties
    219 
    220   void AddObserver(WindowStateObserver* observer);
    221   void RemoveObserver(WindowStateObserver* observer);
    222 
    223   // Whether the window is being dragged.
    224   bool is_dragged() const {
    225     return drag_details_;
    226   }
    227 
    228   // Whether or not the window's position can be managed by the
    229   // auto management logic.
    230   bool window_position_managed() const { return window_position_managed_; }
    231   void set_window_position_managed(bool window_position_managed) {
    232     window_position_managed_ = window_position_managed;
    233   }
    234 
    235   // Whether or not the window's position or size was changed by a user.
    236   bool bounds_changed_by_user() const { return bounds_changed_by_user_; }
    237   void set_bounds_changed_by_user(bool bounds_changed_by_user);
    238 
    239   // True if this window is an attached panel.
    240   bool panel_attached() const {
    241     return panel_attached_;
    242   }
    243   void set_panel_attached(bool panel_attached) {
    244     panel_attached_ = panel_attached;
    245   }
    246 
    247   // True if the window is ignored by the shelf layout manager for
    248   // purposes of darkening the shelf.
    249   bool ignored_by_shelf() const { return ignored_by_shelf_; }
    250   void set_ignored_by_shelf(bool ignored_by_shelf) {
    251     ignored_by_shelf_ = ignored_by_shelf;
    252   }
    253 
    254   // True if the window should be offered a chance to consume special system
    255   // keys such as brightness, volume, etc. that are usually handled by the
    256   // shell.
    257   bool can_consume_system_keys() const { return can_consume_system_keys_; }
    258   void set_can_consume_system_keys(bool can_consume_system_keys) {
    259     can_consume_system_keys_ = can_consume_system_keys;
    260   }
    261 
    262   // True if this window has requested that the top-row keys (back, forward,
    263   // brightness, volume) should be treated as function keys.
    264   bool top_row_keys_are_function_keys() const {
    265     return top_row_keys_are_function_keys_;
    266   }
    267   void set_top_row_keys_are_function_keys(bool value) {
    268     top_row_keys_are_function_keys_ = value;
    269   }
    270 
    271   // True if the window is in "immersive full screen mode" which is slightly
    272   // different from the normal fullscreen mode by allowing the user to reveal
    273   // the top portion of the window through a touch / mouse gesture. It might
    274   // also allow the shelf to be shown in some situations.
    275   bool in_immersive_fullscreen() const {
    276     return in_immersive_fullscreen_;
    277   }
    278   void set_in_immersive_fullscreen(bool enable) {
    279     in_immersive_fullscreen_ = enable;
    280   }
    281 
    282   // Creates and takes ownership of a pointer to DragDetails when resizing is
    283   // active. This should be done before a resizer gets created.
    284   void CreateDragDetails(aura::Window* window,
    285                          const gfx::Point& point_in_parent,
    286                          int window_component,
    287                          aura::client::WindowMoveSource source);
    288 
    289   // Deletes and clears a pointer to DragDetails. This should be done when the
    290   // resizer gets destroyed.
    291   void DeleteDragDetails();
    292 
    293   // Sets the currently stored restore bounds and clears the restore bounds.
    294   void SetAndClearRestoreBounds();
    295 
    296   // Returns a pointer to DragDetails during drag operations.
    297   const DragDetails* drag_details() const { return drag_details_.get(); }
    298   DragDetails* drag_details() { return drag_details_.get(); }
    299 
    300   // aura::WindowObserver overrides:
    301   virtual void OnWindowPropertyChanged(aura::Window* window,
    302                                        const void* key,
    303                                        intptr_t old) OVERRIDE;
    304 
    305  private:
    306   friend class DefaultState;
    307   friend class ash::LockWindowState;
    308   friend class ash::MaximizeModeWindowState;
    309   friend ASH_EXPORT WindowState* GetWindowState(aura::Window*);
    310   FRIEND_TEST_ALL_PREFIXES(WindowAnimationsTest, CrossFadeToBounds);
    311 
    312   explicit WindowState(aura::Window* window);
    313 
    314   WindowStateDelegate* delegate() { return delegate_.get(); }
    315 
    316   // Returns the window's current show state.
    317   ui::WindowShowState GetShowState() const;
    318 
    319   // Sets the window's bounds in screen coordinates.
    320   void SetBoundsInScreen(const gfx::Rect& bounds_in_screen);
    321 
    322   // Adjusts the |bounds| so that they are flush with the edge of the
    323   // workspace if the window represented by |window_state| is side snapped.
    324   void AdjustSnappedBounds(gfx::Rect* bounds);
    325 
    326   // Updates the window show state according to the current window state type.
    327   // Note that this does not update the window bounds.
    328   void UpdateWindowShowStateFromStateType();
    329 
    330   void NotifyPreStateTypeChange(WindowStateType old_window_state_type);
    331   void NotifyPostStateTypeChange(WindowStateType old_window_state_type);
    332 
    333   // Sets |bounds| as is and ensure the layer is aligned with pixel boundary.
    334   void SetBoundsDirect(const gfx::Rect& bounds);
    335 
    336   // Sets the window's |bounds| with constraint where the size of the
    337   // new bounds will not exceeds the size of the work area.
    338   void SetBoundsConstrained(const gfx::Rect& bounds);
    339 
    340   // Sets the wndow's |bounds| and transitions to the new bounds with
    341   // a scale animation.
    342   void SetBoundsDirectAnimated(const gfx::Rect& bounds);
    343 
    344   // Sets the window's |bounds| and transition to the new bounds with
    345   // a cross fade animation.
    346   void SetBoundsDirectCrossFade(const gfx::Rect& bounds);
    347 
    348   // The owner of this window settings.
    349   aura::Window* window_;
    350   scoped_ptr<WindowStateDelegate> delegate_;
    351 
    352   bool window_position_managed_;
    353   bool bounds_changed_by_user_;
    354   bool panel_attached_;
    355   bool ignored_by_shelf_;
    356   bool can_consume_system_keys_;
    357   bool top_row_keys_are_function_keys_;
    358   scoped_ptr<DragDetails> drag_details_;
    359 
    360   bool unminimize_to_restore_bounds_;
    361   bool in_immersive_fullscreen_;
    362   bool hide_shelf_when_fullscreen_;
    363   bool minimum_visibility_;
    364   bool can_be_dragged_;
    365 
    366   // A property to remember the window position which was set before the
    367   // auto window position manager changed the window bounds, so that it can get
    368   // restored when only this one window gets shown.
    369   scoped_ptr<gfx::Rect> pre_auto_manage_window_bounds_;
    370 
    371   ObserverList<WindowStateObserver> observer_list_;
    372 
    373   // True to ignore a property change event to avoid reentrance in
    374   // UpdateWindowStateType()
    375   bool ignore_property_change_;
    376 
    377   scoped_ptr<State> current_state_;
    378 
    379   DISALLOW_COPY_AND_ASSIGN(WindowState);
    380 };
    381 
    382 // Returns the WindowState for active window. Returns |NULL|
    383 // if there is no active window.
    384 ASH_EXPORT WindowState* GetActiveWindowState();
    385 
    386 // Returns the WindowState for |window|. Creates WindowState
    387 // if it didn't exist. The settings object is owned by |window|.
    388 ASH_EXPORT WindowState* GetWindowState(aura::Window* window);
    389 
    390 // const version of GetWindowState.
    391 ASH_EXPORT const WindowState*
    392 GetWindowState(const aura::Window* window);
    393 
    394 }  // namespace wm
    395 }  // namespace ash
    396 
    397 #endif  // ASH_WM_WINDOW_STATE_H_
    398