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