Home | History | Annotate | Download | only in notifications
      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 // Handles the visible notification (or balloons).
      6 
      7 #ifndef CHROME_BROWSER_NOTIFICATIONS_BALLOON_COLLECTION_IMPL_H_
      8 #define CHROME_BROWSER_NOTIFICATIONS_BALLOON_COLLECTION_IMPL_H_
      9 
     10 #include <deque>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/compiler_specific.h"
     14 #include "base/memory/weak_ptr.h"
     15 #include "base/message_loop/message_loop.h"
     16 #include "chrome/browser/notifications/balloon_collection.h"
     17 #include "chrome/browser/notifications/balloon_collection_base.h"
     18 #include "content/public/browser/notification_observer.h"
     19 #include "content/public/browser/notification_registrar.h"
     20 #include "ui/gfx/point.h"
     21 #include "ui/gfx/rect.h"
     22 
     23 // Mac balloons grow from the top down and have close buttons on top, so
     24 // offsetting is not necessary for easy multiple-closing.  Other platforms grow
     25 // from the bottom up and have close buttons on top, so it is necessary.
     26 #if defined(OS_MACOSX)
     27 #define USE_OFFSETS 0
     28 #else
     29 #define USE_OFFSETS 1
     30 #endif
     31 
     32 // A balloon collection represents a set of notification balloons being
     33 // shown on the screen.  It positions new notifications according to
     34 // a layout, and monitors for balloons being closed, which it reports
     35 // up to its parent, the notification UI manager.
     36 class BalloonCollectionImpl : public BalloonCollection,
     37                               public content::NotificationObserver
     38 #if USE_OFFSETS
     39                             , public base::MessageLoopForUI::Observer
     40 #endif
     41 {
     42  public:
     43   BalloonCollectionImpl();
     44   virtual ~BalloonCollectionImpl();
     45 
     46   // BalloonCollection interface.
     47   virtual void Add(const Notification& notification,
     48                    Profile* profile) OVERRIDE;
     49   virtual const Notification* FindById(const std::string& id) const OVERRIDE;
     50   virtual bool RemoveById(const std::string& id) OVERRIDE;
     51   virtual bool RemoveBySourceOrigin(const GURL& source_origin) OVERRIDE;
     52   virtual bool RemoveByProfile(Profile* profile) OVERRIDE;
     53   virtual void RemoveAll() OVERRIDE;
     54   virtual bool HasSpace() const OVERRIDE;
     55   virtual void ResizeBalloon(Balloon* balloon, const gfx::Size& size) OVERRIDE;
     56   virtual void SetPositionPreference(PositionPreference position) OVERRIDE;
     57   virtual void DisplayChanged() OVERRIDE;
     58   virtual void OnBalloonClosed(Balloon* source) OVERRIDE;
     59   virtual const Balloons& GetActiveBalloons() OVERRIDE;
     60 
     61   // content::NotificationObserver interface.
     62   virtual void Observe(int type,
     63                        const content::NotificationSource& source,
     64                        const content::NotificationDetails& details) OVERRIDE;
     65 
     66   // MessageLoopForUI::Observer interface.
     67 #if defined(OS_WIN) || defined(USE_AURA)
     68   virtual base::EventStatus WillProcessEvent(
     69       const base::NativeEvent& event) OVERRIDE;
     70   virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE;
     71 #elif defined(TOOLKIT_GTK)
     72   virtual void WillProcessEvent(GdkEvent* event) OVERRIDE;
     73   virtual void DidProcessEvent(GdkEvent* event) OVERRIDE;
     74 #endif
     75 
     76   // base_ is embedded, so this is a simple accessor for the number of
     77   // balloons in the collection.
     78   int count() const { return base_.count(); }
     79 
     80   static int min_balloon_width() { return Layout::min_balloon_width(); }
     81   static int max_balloon_width() { return Layout::max_balloon_width(); }
     82   static int min_balloon_height() { return Layout::min_balloon_height(); }
     83   static int max_balloon_height() { return Layout::max_balloon_height(); }
     84 
     85  protected:
     86   // Calculates layout values for the balloons including
     87   // the scaling, the max/min sizes, and the upper left corner of each.
     88   class Layout {
     89    public:
     90     Layout();
     91 
     92     // These enumerations all are based on a screen orientation where
     93     // the origin is the top-left.
     94     enum Placement {
     95       INVALID,
     96       VERTICALLY_FROM_TOP_LEFT,
     97       VERTICALLY_FROM_TOP_RIGHT,
     98       VERTICALLY_FROM_BOTTOM_LEFT,
     99       VERTICALLY_FROM_BOTTOM_RIGHT
    100     };
    101 
    102     // Refresh the work area and balloon placement.
    103     void OnDisplaySettingsChanged();
    104 
    105     // TODO(johnnyg): Scale the size to account for the system font factor.
    106     static int min_balloon_width() { return kBalloonMinWidth; }
    107     static int max_balloon_width() { return kBalloonMaxWidth; }
    108     static int min_balloon_height() { return kBalloonMinHeight; }
    109     static int max_balloon_height() { return kBalloonMaxHeight; }
    110 
    111     // Utility function constrains the input rectangle to the min and max sizes.
    112     static gfx::Size ConstrainToSizeLimits(const gfx::Size& rect);
    113 
    114     void set_placement(Placement placement) { placement_ = placement; }
    115 
    116     // Returns both the total space available and the maximum
    117     // allowed per balloon.
    118     //
    119     // The size may be a height or length depending on the way that
    120     // balloons are laid out.
    121     void GetMaxLinearSize(int* max_balloon_size, int* total_size) const;
    122 
    123     // Refresh the cached values for work area and drawing metrics.
    124     // The application should call this method to re-acquire metrics after
    125     // any resolution or settings change.
    126     // Returns true if and only if a metric changed.
    127     bool RefreshSystemMetrics();
    128 
    129     // Returns the origin for the sequence of balloons depending on layout.
    130     // Should not be used to place a balloon -- only to call NextPosition().
    131     gfx::Point GetLayoutOrigin() const;
    132 
    133     // Compute the position for the next balloon.
    134     // Start with *position_iterator = GetLayoutOrigin() and call repeatedly
    135     // to get a sequence of positions. Return value is the upper-left coordinate
    136     // for each next balloon.
    137     gfx::Point NextPosition(const gfx::Size& balloon_size,
    138                             gfx::Point* position_iterator) const;
    139 
    140     // Return a offscreen location which is offscreen for this layout,
    141     // to be used as the initial position for an animation into view.
    142     gfx::Point OffScreenLocation() const;
    143 
    144     // Returns true if the layout requires offsetting for keeping the close
    145     // buttons under the cursor during rapid-close interaction.
    146     bool RequiresOffsets() const;
    147 
    148     // Returns true if there is change to the offset that requires the balloons
    149     // to be repositioned.
    150     bool ComputeOffsetToMoveAbovePanels();
    151 
    152     void enable_computing_panel_offset() {
    153       need_to_compute_panel_offset_ = true;
    154     }
    155 
    156    private:
    157     // Layout parameters
    158     int VerticalEdgeMargin() const;
    159     int HorizontalEdgeMargin() const;
    160     int InterBalloonMargin() const;
    161 
    162     bool NeedToMoveAboveLeftSidePanels() const;
    163     bool NeedToMoveAboveRightSidePanels() const;
    164 
    165     // Minimum and maximum size of balloon content.
    166     static const int kBalloonMinWidth = 300;
    167     static const int kBalloonMaxWidth = 300;
    168     static const int kBalloonMinHeight = 24;
    169     static const int kBalloonMaxHeight = 160;
    170 
    171     Placement placement_;
    172     gfx::Rect work_area_;
    173 
    174     // The flag that indicates that the panel offset computation should be
    175     // performed.
    176     bool need_to_compute_panel_offset_;
    177 
    178     // The offset that guarantees that the notificaitions shown in the
    179     // lower-right or lower-left corner of the screen will go above currently
    180     // shown panels and will not be obscured by them.
    181     int offset_to_move_above_panels_;
    182 
    183     DISALLOW_COPY_AND_ASSIGN(Layout);
    184   };
    185 
    186   // Creates a new balloon. Overridable by derived classes and unit tests.
    187   // The caller is responsible for freeing the pointer returned.
    188   virtual Balloon* MakeBalloon(const Notification& notification,
    189                                Profile* profile);
    190 
    191   // Protected implementation of Add with additional add_to_front parameter
    192   // for use by derived classes.
    193   void AddImpl(const Notification& notification,
    194                Profile* profile,
    195                bool add_to_front);
    196 
    197   // Gets a bounding box for all the current balloons in screen coordinates.
    198   gfx::Rect GetBalloonsBoundingBox() const;
    199 
    200   BalloonCollectionBase& base() { return base_; }
    201   Layout& layout() { return layout_; }
    202 
    203  private:
    204   // Adjusts the positions of the balloons (e.g., when one is closed).
    205   // Implemented by each platform for specific UI requirements.
    206   void PositionBalloons(bool is_reposition);
    207 
    208   // Cross-platform internal implementation for PositionBalloons.
    209   void PositionBalloonsInternal(bool is_reposition);
    210 
    211 #if defined(OS_MACOSX)
    212   // Get the work area on Mac OS, without inverting the coordinates.
    213   static gfx::Rect GetMacWorkArea();
    214 #endif
    215 
    216   // Base implementation for the collection of active balloons.
    217   BalloonCollectionBase base_;
    218 
    219   // The layout parameters for balloons in this collection.
    220   Layout layout_;
    221 
    222   content::NotificationRegistrar registrar_;
    223 
    224 #if USE_OFFSETS
    225   // Start and stop observing all UI events.
    226   void AddMessageLoopObserver();
    227   void RemoveMessageLoopObserver();
    228 
    229   // Cancel all offset and reposition the balloons normally.
    230   void CancelOffsets();
    231 
    232   // Handles a mouse motion while the balloons are temporarily offset.
    233   void HandleMouseMoveEvent();
    234 
    235   // Is the current cursor in the balloon area?
    236   bool IsCursorInBalloonCollection() const;
    237 
    238   // Factory for generating delayed reposition tasks on mouse motion.
    239   base::WeakPtrFactory<BalloonCollectionImpl> reposition_factory_;
    240 
    241   // Is the balloon collection currently listening for UI events?
    242   bool added_as_message_loop_observer_;
    243 #endif
    244 
    245   DISALLOW_COPY_AND_ASSIGN(BalloonCollectionImpl);
    246 };
    247 
    248 #endif  // CHROME_BROWSER_NOTIFICATIONS_BALLOON_COLLECTION_IMPL_H_
    249