Index: chrome/browser/notifications/balloon_collection_impl.cc |
diff --git a/chrome/browser/notifications/balloon_collection_impl.cc b/chrome/browser/notifications/balloon_collection_impl.cc |
index 9d234c222aa41ebe7753061c00b7ec4f1c3bccbc..173c78caba6898a8077e4e7417204a0e0fc3d279 100644 |
--- a/chrome/browser/notifications/balloon_collection_impl.cc |
+++ b/chrome/browser/notifications/balloon_collection_impl.cc |
@@ -10,7 +10,13 @@ |
#include "chrome/browser/notifications/balloon.h" |
#include "chrome/browser/notifications/balloon_host.h" |
#include "chrome/browser/notifications/notification.h" |
+#include "chrome/browser/ui/browser.h" |
+#include "chrome/browser/ui/panels/panel_manager.h" |
+#include "chrome/browser/ui/panels/panel.h" |
#include "chrome/browser/ui/window_sizer.h" |
+#include "chrome/common/chrome_notification_types.h" |
+#include "content/public/browser/notification_registrar.h" |
+#include "content/public/browser/notification_service.h" |
#include "ui/gfx/rect.h" |
#include "ui/gfx/size.h" |
@@ -27,6 +33,9 @@ const int kMinAllowedBalloonCount = 2; |
// there is a relayout, in milliseconds. |
const int kRepositionDelay = 300; |
+// The spacing between the balloon and the panel. |
+const int kVerticalSpacingBetweenBalloonAndPanel = 5; |
+ |
} // namespace |
BalloonCollectionImpl::BalloonCollectionImpl() |
@@ -35,6 +44,12 @@ BalloonCollectionImpl::BalloonCollectionImpl() |
added_as_message_loop_observer_(false) |
#endif |
{ |
+ registrar_.Add(this, chrome::NOTIFICATION_PANEL_ADDED, |
+ content::NotificationService::AllSources()); |
+ registrar_.Add(this, chrome::NOTIFICATION_PANEL_REMOVED, |
+ content::NotificationService::AllSources()); |
+ registrar_.Add(this, chrome::NOTIFICATION_PANEL_CHANGED_BOUNDS, |
+ content::NotificationService::AllSources()); |
SetPositionPreference(BalloonCollection::DEFAULT_POSITION); |
} |
@@ -153,6 +168,26 @@ const BalloonCollection::Balloons& BalloonCollectionImpl::GetActiveBalloons() { |
return base_.balloons(); |
} |
+void BalloonCollectionImpl::Observe( |
+ int type, |
+ const content::NotificationSource& source, |
+ const content::NotificationDetails& details) { |
+ gfx::Rect bounds; |
+ switch (type) { |
+ case chrome::NOTIFICATION_PANEL_CHANGED_BOUNDS: |
+ bounds = content::Source<Panel>(source).ptr()->GetBounds(); |
+ // Fall through. |
+ case chrome::NOTIFICATION_PANEL_ADDED: |
+ case chrome::NOTIFICATION_PANEL_REMOVED: |
+ if (layout_.ComputeOffsetToMoveAbovePanels(bounds)) |
+ PositionBalloons(true); |
+ break; |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+} |
+ |
void BalloonCollectionImpl::PositionBalloonsInternal(bool reposition) { |
const Balloons& balloons = base_.balloons(); |
@@ -231,7 +266,9 @@ void BalloonCollectionImpl::HandleMouseMoveEvent() { |
} |
#endif |
-BalloonCollectionImpl::Layout::Layout() : placement_(INVALID) { |
+BalloonCollectionImpl::Layout::Layout() |
+ : placement_(INVALID), |
+ offset_to_move_above_panels_(0) { |
RefreshSystemMetrics(); |
} |
@@ -245,24 +282,30 @@ void BalloonCollectionImpl::Layout::GetMaxLinearSize(int* max_balloon_size, |
} |
gfx::Point BalloonCollectionImpl::Layout::GetLayoutOrigin() const { |
+ // For lower-left and lower-right positioning, we need to add an offset |
+ // to ensure balloons to stay on top of panels to avoid overlapping. |
int x = 0; |
int y = 0; |
switch (placement_) { |
- case VERTICALLY_FROM_TOP_LEFT: |
+ case VERTICALLY_FROM_TOP_LEFT: { |
x = work_area_.x() + HorizontalEdgeMargin(); |
- y = work_area_.y() + VerticalEdgeMargin(); |
+ y = work_area_.y() + VerticalEdgeMargin() + offset_to_move_above_panels_; |
break; |
- case VERTICALLY_FROM_TOP_RIGHT: |
+ } |
+ case VERTICALLY_FROM_TOP_RIGHT: { |
x = work_area_.right() - HorizontalEdgeMargin(); |
- y = work_area_.y() + VerticalEdgeMargin(); |
+ y = work_area_.y() + VerticalEdgeMargin() + offset_to_move_above_panels_; |
break; |
+ } |
case VERTICALLY_FROM_BOTTOM_LEFT: |
x = work_area_.x() + HorizontalEdgeMargin(); |
- y = work_area_.bottom() - VerticalEdgeMargin(); |
+ y = work_area_.bottom() - VerticalEdgeMargin() - |
+ offset_to_move_above_panels_; |
break; |
case VERTICALLY_FROM_BOTTOM_RIGHT: |
x = work_area_.right() - HorizontalEdgeMargin(); |
- y = work_area_.bottom() - VerticalEdgeMargin(); |
+ y = work_area_.bottom() - VerticalEdgeMargin() - |
+ offset_to_move_above_panels_; |
break; |
default: |
NOTREACHED(); |
@@ -311,30 +354,21 @@ gfx::Point BalloonCollectionImpl::Layout::NextPosition( |
} |
gfx::Point BalloonCollectionImpl::Layout::OffScreenLocation() const { |
- int x = 0; |
- int y = 0; |
+ gfx::Point location = GetLayoutOrigin(); |
switch (placement_) { |
case VERTICALLY_FROM_TOP_LEFT: |
- x = work_area_.x() + HorizontalEdgeMargin(); |
- y = work_area_.y() + kBalloonMaxHeight + VerticalEdgeMargin(); |
- break; |
- case VERTICALLY_FROM_TOP_RIGHT: |
- x = work_area_.right() - kBalloonMaxWidth - HorizontalEdgeMargin(); |
- y = work_area_.y() + kBalloonMaxHeight + VerticalEdgeMargin(); |
- break; |
case VERTICALLY_FROM_BOTTOM_LEFT: |
- x = work_area_.x() + HorizontalEdgeMargin(); |
- y = work_area_.bottom() + kBalloonMaxHeight + VerticalEdgeMargin(); |
+ location.Offset(0, kBalloonMaxHeight); |
break; |
+ case VERTICALLY_FROM_TOP_RIGHT: |
case VERTICALLY_FROM_BOTTOM_RIGHT: |
- x = work_area_.right() - kBalloonMaxWidth - HorizontalEdgeMargin(); |
- y = work_area_.bottom() + kBalloonMaxHeight + VerticalEdgeMargin(); |
+ location.Offset(-kBalloonMaxWidth, kBalloonMaxHeight); |
break; |
default: |
NOTREACHED(); |
break; |
} |
- return gfx::Point(x, y); |
+ return location; |
} |
bool BalloonCollectionImpl::Layout::RequiresOffsets() const { |
@@ -363,6 +397,68 @@ gfx::Size BalloonCollectionImpl::Layout::ConstrainToSizeLimits( |
std::min(max_balloon_height(), size.height()))); |
} |
+bool BalloonCollectionImpl::Layout::ComputeOffsetToMoveAbovePanels( |
+ const gfx::Rect& panel_bounds) { |
+ const PanelManager::Panels& panels = PanelManager::GetInstance()->panels(); |
+ int offset_to_move_above_panels = 0; |
+ |
+ // The offset is the maximum height of panels that could overlap with the |
+ // balloons. |
+ if (NeedToMoveAboveLeftSidePanels()) { |
+ // If the affecting panel does not lie in the balloon area, no need to |
+ // update the offset. |
+ if (!panel_bounds.IsEmpty() && |
+ (panel_bounds.right() <= work_area_.x() || |
+ panel_bounds.x() >= work_area_.x() + max_balloon_width())) { |
+ return false; |
+ } |
+ |
+ for (PanelManager::Panels::const_reverse_iterator iter = panels.rbegin(); |
+ iter != panels.rend(); ++iter) { |
+ // No need to check panels beyond the area occupied by the balloons. |
+ if ((*iter)->GetBounds().x() >= work_area_.x() + max_balloon_width()) |
jennb
2011/11/11 23:02:43
FYI, until your overflow changes are in, this will
|
+ break; |
+ |
+ int current_height = (*iter)->GetBounds().height(); |
+ if (current_height > offset_to_move_above_panels) |
+ offset_to_move_above_panels = current_height; |
+ } |
+ } else if (NeedToMoveAboveRightSidePanels()) { |
+ // If the affecting panel does not lie in the balloon area, no need to |
+ // update the offset. |
+ if (!panel_bounds.IsEmpty() && |
+ (panel_bounds.right() <= work_area_.right() - max_balloon_width() || |
+ panel_bounds.x() >= work_area_.right())) { |
+ return false; |
+ } |
+ |
+ for (PanelManager::Panels::const_iterator iter = panels.begin(); |
+ iter != panels.end(); ++iter) { |
+ // No need to check panels beyond the area occupied by the balloons. |
+ if ((*iter)->GetBounds().right() <= |
+ work_area_.right() - max_balloon_width()) |
+ break; |
+ |
+ int current_height = (*iter)->GetBounds().height(); |
+ if (current_height > offset_to_move_above_panels) |
+ offset_to_move_above_panels = current_height; |
+ } |
+ } |
+ |
+ // Ensure that we have some sort of margin between the 1st balloon and the |
+ // panel beneath it even the vertical edge margin is 0 as on Mac. |
+ if (offset_to_move_above_panels && !VerticalEdgeMargin()) |
+ offset_to_move_above_panels += kVerticalSpacingBetweenBalloonAndPanel; |
+ |
+ // If no change is detected, return false to indicate that we do not need to |
+ // reposition balloons. |
+ if (offset_to_move_above_panels_ == offset_to_move_above_panels) |
+ return false; |
+ |
+ offset_to_move_above_panels_ = offset_to_move_above_panels; |
+ return true; |
+} |
+ |
bool BalloonCollectionImpl::Layout::RefreshSystemMetrics() { |
bool changed = false; |