• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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_SHELF_SHELF_LAYOUT_MANAGER_H_
6 #define ASH_SHELF_SHELF_LAYOUT_MANAGER_H_
7 
8 #include <vector>
9 
10 #include "ash/ash_export.h"
11 #include "ash/session/session_state_observer.h"
12 #include "ash/shelf/background_animator.h"
13 #include "ash/shelf/shelf.h"
14 #include "ash/shelf/shelf_types.h"
15 #include "ash/shell_observer.h"
16 #include "ash/system/status_area_widget.h"
17 #include "ash/wm/dock/docked_window_layout_manager_observer.h"
18 #include "ash/wm/lock_state_observer.h"
19 #include "ash/wm/workspace/workspace_types.h"
20 #include "base/basictypes.h"
21 #include "base/compiler_specific.h"
22 #include "base/logging.h"
23 #include "base/observer_list.h"
24 #include "base/timer/timer.h"
25 #include "ui/aura/layout_manager.h"
26 #include "ui/gfx/insets.h"
27 #include "ui/gfx/rect.h"
28 #include "ui/keyboard/keyboard_controller.h"
29 #include "ui/keyboard/keyboard_controller_observer.h"
30 #include "ui/wm/public/activation_change_observer.h"
31 
32 namespace aura {
33 class RootWindow;
34 }
35 
36 namespace ui {
37 class GestureEvent;
38 class ImplicitAnimationObserver;
39 }
40 
41 namespace ash {
42 class PanelLayoutManagerTest;
43 class ScreenAsh;
44 class ShelfBezelEventFilter;
45 class ShelfLayoutManagerObserver;
46 class ShelfLayoutManagerTest;
47 class ShelfWidget;
48 class StatusAreaWidget;
49 class WorkspaceController;
50 FORWARD_DECLARE_TEST(WebNotificationTrayTest, PopupAndFullscreen);
51 
52 // ShelfLayoutManager is the layout manager responsible for the shelf and
53 // status widgets. The shelf is given the total available width and told the
54 // width of the status area. This allows the shelf to draw the background and
55 // layout to the status area.
56 // To respond to bounds changes in the status area StatusAreaLayoutManager works
57 // closely with ShelfLayoutManager.
58 class ASH_EXPORT ShelfLayoutManager :
59     public aura::LayoutManager,
60     public ash::ShellObserver,
61     public aura::client::ActivationChangeObserver,
62     public DockedWindowLayoutManagerObserver,
63     public keyboard::KeyboardControllerObserver,
64     public LockStateObserver,
65     public SessionStateObserver {
66  public:
67 
68   // We reserve a small area on the edge of the workspace area to ensure that
69   // the resize handle at the edge of the window can be hit.
70   static const int kWorkspaceAreaVisibleInset;
71 
72   // When autohidden we extend the touch hit target onto the screen so that the
73   // user can drag the shelf out.
74   static const int kWorkspaceAreaAutoHideInset;
75 
76   // Size of the shelf when auto-hidden.
77   static const int kAutoHideSize;
78 
79   // Inset between the inner edge of the shelf (towards centre of screen), and
80   // the shelf items, notifications, status area etc.
81   static const int kShelfItemInset;
82 
83   explicit ShelfLayoutManager(ShelfWidget* shelf);
84   virtual ~ShelfLayoutManager();
85 
86   // Sets the ShelfAutoHideBehavior. See enum description for details.
87   void SetAutoHideBehavior(ShelfAutoHideBehavior behavior);
auto_hide_behavior()88   ShelfAutoHideBehavior auto_hide_behavior() const {
89     return auto_hide_behavior_;
90   }
91 
92   // Sets the alignment. Returns true if the alignment is changed. Otherwise,
93   // returns false.
94   bool SetAlignment(ShelfAlignment alignment);
95   // Returns the desired alignment for the current state, either the user's
96   // set alignment (alignment_) or SHELF_ALIGNMENT_BOTTOM when the screen
97   // is locked.
98   ShelfAlignment GetAlignment() const;
99 
set_workspace_controller(WorkspaceController * controller)100   void set_workspace_controller(WorkspaceController* controller) {
101     workspace_controller_ = controller;
102   }
103 
updating_bounds()104   bool updating_bounds() const { return updating_bounds_; }
105 
106   // Clears internal data for shutdown process.
107   void PrepareForShutdown();
108 
109   // Returns whether the shelf and its contents (shelf, status) are visible
110   // on the screen.
111   bool IsVisible() const;
112 
113   // Returns the ideal bounds of the shelf assuming it is visible.
114   gfx::Rect GetIdealBounds();
115 
116   // Returns the docked area bounds.
dock_bounds()117   const gfx::Rect& dock_bounds() const { return dock_bounds_; }
118 
119   // Stops any animations and sets the bounds of the shelf and status
120   // widgets.
121   void LayoutShelf();
122 
123   // Returns shelf visibility state based on current value of auto hide
124   // behavior setting.
125   ShelfVisibilityState CalculateShelfVisibility();
126 
127   // Updates the visibility state.
128   void UpdateVisibilityState();
129 
130   // Invoked by the shelf when the auto-hide state may have changed.
131   void UpdateAutoHideState();
132 
visibility_state()133   ShelfVisibilityState visibility_state() const {
134     return state_.visibility_state;
135   }
auto_hide_state()136   ShelfAutoHideState auto_hide_state() const { return state_.auto_hide_state; }
137 
shelf_widget()138   ShelfWidget* shelf_widget() { return shelf_; }
139 
140   // Sets whether any windows overlap the shelf. If a window overlaps the shelf
141   // the shelf renders slightly differently.
142   void SetWindowOverlapsShelf(bool value);
window_overlaps_shelf()143   bool window_overlaps_shelf() const { return window_overlaps_shelf_; }
144 
145   void AddObserver(ShelfLayoutManagerObserver* observer);
146   void RemoveObserver(ShelfLayoutManagerObserver* observer);
147 
148   // Gesture related functions:
149   void OnGestureEdgeSwipe(const ui::GestureEvent& gesture);
150   void StartGestureDrag(const ui::GestureEvent& gesture);
151   enum DragState {
152     DRAG_SHELF,
153     DRAG_TRAY
154   };
155   // Returns DRAG_SHELF if the gesture should continue to drag the entire shelf.
156   // Returns DRAG_TRAY if the gesture can start dragging the tray-bubble from
157   // this point on.
158   DragState UpdateGestureDrag(const ui::GestureEvent& gesture);
159   void CompleteGestureDrag(const ui::GestureEvent& gesture);
160   void CancelGestureDrag();
161 
162   // Set an animation duration override for the show / hide animation of the
163   // shelf. Specifying 0 leads to use the default.
164   void SetAnimationDurationOverride(int duration_override_in_ms);
165 
166   // Overridden from aura::LayoutManager:
167   virtual void OnWindowResized() OVERRIDE;
168   virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE;
169   virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE;
170   virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE;
171   virtual void OnChildWindowVisibilityChanged(aura::Window* child,
172                                               bool visible) OVERRIDE;
173   virtual void SetChildBounds(aura::Window* child,
174                               const gfx::Rect& requested_bounds) OVERRIDE;
175 
176   // Overridden from ash::ShellObserver:
177   virtual void OnLockStateChanged(bool locked) OVERRIDE;
178   virtual void OnMaximizeModeStarted() OVERRIDE;
179 
180   // Overriden from aura::client::ActivationChangeObserver:
181   virtual void OnWindowActivated(aura::Window* gained_active,
182                                  aura::Window* lost_active) OVERRIDE;
183 
184   // Overridden from ash::LockStateObserver:
185   virtual void OnLockStateEvent(LockStateObserver::EventType event) OVERRIDE;
186 
187   // Overridden from ash::SessionStateObserver:
188   virtual void SessionStateChanged(
189       SessionStateDelegate::SessionState state) OVERRIDE;
190 
191   // TODO(harrym|oshima): These templates will be moved to
192   // new Shelf class.
193   // A helper function that provides a shortcut for choosing
194   // values specific to a shelf alignment.
195   template<typename T>
SelectValueForShelfAlignment(T bottom,T left,T right,T top)196   T SelectValueForShelfAlignment(T bottom, T left, T right, T top) const {
197     switch (GetAlignment()) {
198       case SHELF_ALIGNMENT_BOTTOM:
199         return bottom;
200       case SHELF_ALIGNMENT_LEFT:
201         return left;
202       case SHELF_ALIGNMENT_RIGHT:
203         return right;
204       case SHELF_ALIGNMENT_TOP:
205         return top;
206     }
207     NOTREACHED();
208     return right;
209   }
210 
211   template<typename T>
PrimaryAxisValue(T horizontal,T vertical)212   T PrimaryAxisValue(T horizontal, T vertical) const {
213     return IsHorizontalAlignment() ? horizontal : vertical;
214   }
215 
216   // Is the shelf's alignment horizontal?
217   bool IsHorizontalAlignment() const;
218 
219   // Returns a ShelfLayoutManager on the display which has a shelf for
220   // given |window|. See RootWindowController::ForShelf for more info.
221   static ShelfLayoutManager* ForShelf(aura::Window* window);
222 
223  private:
224   class AutoHideEventFilter;
225   class UpdateShelfObserver;
226   friend class ash::ScreenAsh;
227   friend class PanelLayoutManagerTest;
228   friend class ShelfLayoutManagerTest;
229   FRIEND_TEST_ALL_PREFIXES(ash::WebNotificationTrayTest, PopupAndFullscreen);
230 
231   struct TargetBounds {
232     TargetBounds();
233     ~TargetBounds();
234 
235     float opacity;
236     float status_opacity;
237     gfx::Rect shelf_bounds_in_root;
238     gfx::Rect shelf_bounds_in_shelf;
239     gfx::Rect status_bounds_in_shelf;
240     gfx::Insets work_area_insets;
241   };
242 
243   struct State {
StateState244     State() : visibility_state(SHELF_VISIBLE),
245               auto_hide_state(SHELF_AUTO_HIDE_HIDDEN),
246               window_state(WORKSPACE_WINDOW_STATE_DEFAULT),
247               is_screen_locked(false) {}
248 
249     // Returns true if the two states are considered equal. As
250     // |auto_hide_state| only matters if |visibility_state| is
251     // |SHELF_AUTO_HIDE|, Equals() ignores the |auto_hide_state| as
252     // appropriate.
EqualsState253     bool Equals(const State& other) const {
254       return other.visibility_state == visibility_state &&
255           (visibility_state != SHELF_AUTO_HIDE ||
256            other.auto_hide_state == auto_hide_state) &&
257           other.window_state == window_state &&
258           other.is_screen_locked == is_screen_locked;
259     }
260 
261     ShelfVisibilityState visibility_state;
262     ShelfAutoHideState auto_hide_state;
263     WorkspaceWindowState window_state;
264     bool is_screen_locked;
265   };
266 
267   // Sets the visibility of the shelf to |state|.
268   void SetState(ShelfVisibilityState visibility_state);
269 
270   // Updates the bounds and opacity of the shelf and status widgets.
271   // If |observer| is specified, it will be called back when the animations, if
272   // any, are complete.
273   void UpdateBoundsAndOpacity(const TargetBounds& target_bounds,
274                               bool animate,
275                               ui::ImplicitAnimationObserver* observer);
276 
277   // Stops any animations and progresses them to the end.
278   void StopAnimating();
279 
280   // Returns the width (if aligned to the side) or height (if aligned to the
281   // bottom).
282   void GetShelfSize(int* width, int* height);
283 
284   // Insets |bounds| by |inset| on the edge the shelf is aligned to.
285   void AdjustBoundsBasedOnAlignment(int inset, gfx::Rect* bounds) const;
286 
287   // Calculates the target bounds assuming visibility of |visible|.
288   void CalculateTargetBounds(const State& state, TargetBounds* target_bounds);
289 
290   // Updates the target bounds if a gesture-drag is in progress. This is only
291   // used by |CalculateTargetBounds()|.
292   void UpdateTargetBoundsForGesture(TargetBounds* target_bounds) const;
293 
294   // Updates the background of the shelf.
295   void UpdateShelfBackground(BackgroundAnimatorChangeType type);
296 
297   // Returns how the shelf background is painted.
298   ShelfBackgroundType GetShelfBackgroundType() const;
299 
300   // Updates the auto hide state immediately.
301   void UpdateAutoHideStateNow();
302 
303   // Stops the auto hide timer and clears
304   // |mouse_over_shelf_when_auto_hide_timer_started_|.
305   void StopAutoHideTimer();
306 
307   // Returns the bounds of an additional region which can trigger showing the
308   // shelf. This region exists to make it easier to trigger showing the shelf
309   // when the shelf is auto hidden and the shelf is on the boundary between
310   // two displays.
311   gfx::Rect GetAutoHideShowShelfRegionInScreen() const;
312 
313   // Returns the AutoHideState. This value is determined from the shelf and
314   // tray.
315   ShelfAutoHideState CalculateAutoHideState(
316       ShelfVisibilityState visibility_state) const;
317 
318   // Returns true if |window| is a descendant of the shelf.
319   bool IsShelfWindow(aura::Window* window);
320 
321   int GetWorkAreaSize(const State& state, int size) const;
322 
323   // Overridden from keyboard::KeyboardControllerObserver:
324   virtual void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) OVERRIDE;
325 
326   // Overridden from DockedWindowLayoutManagerObserver:
327   virtual void OnDockBoundsChanging(
328       const gfx::Rect& dock_bounds,
329       DockedWindowLayoutManagerObserver::Reason reason) OVERRIDE;
330 
331   // The RootWindow is cached so that we don't invoke Shell::GetInstance() from
332   // our destructor. We avoid that as at the time we're deleted Shell is being
333   // deleted too.
334   aura::Window* root_window_;
335 
336   // True when inside UpdateBoundsAndOpacity() method. Used to prevent calling
337   // UpdateBoundsAndOpacity() again from SetChildBounds().
338   bool updating_bounds_;
339 
340   // See description above setter.
341   ShelfAutoHideBehavior auto_hide_behavior_;
342 
343   // See description above getter.
344   ShelfAlignment alignment_;
345 
346   // Current state.
347   State state_;
348 
349   ShelfWidget* shelf_;
350 
351   WorkspaceController* workspace_controller_;
352 
353   // Do any windows overlap the shelf? This is maintained by WorkspaceManager.
354   bool window_overlaps_shelf_;
355 
356   base::OneShotTimer<ShelfLayoutManager> auto_hide_timer_;
357 
358   // Whether the mouse was over the shelf when the auto hide timer started.
359   // False when neither the auto hide timer nor the timer task are running.
360   bool mouse_over_shelf_when_auto_hide_timer_started_;
361 
362   // EventFilter used to detect when user moves the mouse over the shelf to
363   // trigger showing the shelf.
364   scoped_ptr<AutoHideEventFilter> auto_hide_event_filter_;
365 
366   // EventFilter used to detect when user issues a gesture on a bezel sensor.
367   scoped_ptr<ShelfBezelEventFilter> bezel_event_filter_;
368 
369   ObserverList<ShelfLayoutManagerObserver> observers_;
370 
371   // The shelf reacts to gesture-drags, and can be set to auto-hide for certain
372   // gestures. Some shelf behaviour (e.g. visibility state, background color
373   // etc.) are affected by various stages of the drag. The enum keeps track of
374   // the present status of the gesture drag.
375   enum GestureDragStatus {
376     GESTURE_DRAG_NONE,
377     GESTURE_DRAG_IN_PROGRESS,
378     GESTURE_DRAG_CANCEL_IN_PROGRESS,
379     GESTURE_DRAG_COMPLETE_IN_PROGRESS
380   };
381   GestureDragStatus gesture_drag_status_;
382 
383   // Tracks the amount of the drag. The value is only valid when
384   // |gesture_drag_status_| is set to GESTURE_DRAG_IN_PROGRESS.
385   float gesture_drag_amount_;
386 
387   // Manage the auto-hide state during the gesture.
388   ShelfAutoHideState gesture_drag_auto_hide_state_;
389 
390   // Used to delay updating shelf background.
391   UpdateShelfObserver* update_shelf_observer_;
392 
393   // The bounds of the keyboard.
394   gfx::Rect keyboard_bounds_;
395 
396   // The bounds of the dock.
397   gfx::Rect dock_bounds_;
398 
399   // The show hide animation duration override or 0 for default.
400   int duration_override_in_ms_;
401 
402   DISALLOW_COPY_AND_ASSIGN(ShelfLayoutManager);
403 };
404 
405 }  // namespace ash
406 
407 #endif  // ASH_SHELF_SHELF_LAYOUT_MANAGER_H_
408