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