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
18namespace aura {
19class Window;
20}
21
22namespace gfx {
23class Rect;
24}
25
26namespace ash {
27class WorkspaceLayoutManager;
28class LockWindowState;
29class MaximizeModeWindowState;
30
31namespace wm {
32class WindowStateDelegate;
33class WindowStateObserver;
34class 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.
47class 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.
384ASH_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|.
388ASH_EXPORT WindowState* GetWindowState(aura::Window* window);
389
390// const version of GetWindowState.
391ASH_EXPORT const WindowState*
392GetWindowState(const aura::Window* window);
393
394}  // namespace wm
395}  // namespace ash
396
397#endif  // ASH_WM_WINDOW_STATE_H_
398