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