Index: chrome/browser/notifications/balloon_win.cc |
diff --git a/chrome/browser/notifications/balloon_win.cc b/chrome/browser/notifications/balloon_win.cc |
new file mode 100755 |
index 0000000000000000000000000000000000000000..0afacd86c41d8e8ddb0d0935b230ef45cda564b3 |
--- /dev/null |
+++ b/chrome/browser/notifications/balloon_win.cc |
@@ -0,0 +1,294 @@ |
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/notifications/balloons.h" |
+ |
+#include "base/logging.h" |
+#include "base/gfx/rect.h" |
+#include "chrome/browser/notifications/balloon_view_win.h" |
+#include "chrome/browser/renderer_host/render_view_host.h" |
+#include "chrome/browser/renderer_host/render_widget_host_view_win.h" |
+#include "chrome/browser/renderer_host/site_instance.h" |
+#include "views/window/window_win.h" |
+ |
+namespace { |
+// Portion of the screen allotted for notifications. |
+// When notification balloons extend over this threshold, no new notifications |
+// are shown until some balloons are expired/closed. |
+const double kPercentBalloonFillFactor = 0.7; |
+ |
+// Allow at least this number of balloons on the screen. |
+const int kMinAllowedBalloonCount = 2; |
+ |
+void GetMainScreenWorkArea(gfx::Rect* bounds) { |
+ DCHECK(bounds); |
+ RECT work_area = {0}; |
+ if (::SystemParametersInfo(SPI_GETWORKAREA, 0, &work_area, 0)) { |
+ bounds->SetRect(work_area.left, |
+ work_area.top, |
+ work_area.right, |
+ work_area.bottom); |
+ } else { |
+ // If failed to call SystemParametersInfo for some reason, we simply get the |
+ // full screen size as an alternative. |
+ bounds->SetRect(0, |
+ 0, |
+ ::GetSystemMetrics(SM_CXSCREEN) - 1, |
+ ::GetSystemMetrics(SM_CYSCREEN) - 1); |
+ } |
+} |
+ |
+double GetSystemFontScaleFactor() { |
+ return 1.0; |
+} |
+} // namespace |
+ |
+BalloonCollection::BalloonCollection() { |
+} |
+ |
+void BalloonCollection::AddObserver(BalloonCollectionObserver* observer) { |
+ DCHECK(observer); |
+ observers_.push_back(observer); |
+ observer->OnBalloonSpaceChanged(); |
+} |
+ |
+bool BalloonCollection::HasSpace() const { |
+ if (count() < kMinAllowedBalloonCount) { |
+ return true; |
+ } |
+ |
+ int max_balloon_length = 0; |
+ int total_length = 0; |
+ layout_.GetMaxLengths(&max_balloon_length, &total_length); |
+ |
+ int current_max_length = max_balloon_length * count(); |
+ int max_allowed_length = static_cast<int>(total_length * |
+ kPercentBalloonFillFactor); |
+ return current_max_length < max_allowed_length - max_balloon_length; |
+} |
+ |
+void BalloonCollection::Add(const Notification& notification, |
+ Profile* profile, |
+ SiteInstance* site_instance) { |
+ Balloon* new_balloon = MakeBalloon(notification, profile, site_instance); |
+ gfx::Size size(layout_.min_balloon_width(), layout_.min_balloon_height()); |
+ new_balloon->SetSize(size); |
+ balloons_.push_back(new_balloon); |
+ gfx::Point origin = layout_.GetOrigin(); |
+ for (Balloons::iterator it = balloons_.begin(); it != balloons_.end(); ++it) { |
+ gfx::Point upper_left = layout_.NextPosition((*it)->size(), &origin); |
+ (*it)->SetPosition(upper_left, false); |
+ } |
+ new_balloon->Show(); |
+ notification.display(); |
+ for (BalloonObservers::iterator it = observers_.begin(); |
+ it != observers_.end(); |
+ ++it) { |
+ (*it)->OnBalloonSpaceChanged(); |
+ } |
+} |
+ |
+void BalloonCollection::OnBalloonClosed(Balloon* source) { |
+ source->notification().close(true); |
+ |
+ for (Balloons::iterator it = balloons_.begin(); it != balloons_.end(); ++it) { |
+ if (*it == source) { |
+ balloons_.erase(it); |
+ break; |
+ } |
+ } |
+ |
+ gfx::Point origin = layout_.GetOrigin(); |
+ for (Balloons::iterator it = balloons_.begin(); it != balloons_.end(); ++it) { |
+ gfx::Point upper_left = layout_.NextPosition((*it)->size(), &origin); |
+ (*it)->SetPosition(upper_left, true); |
+ } |
+} |
+ |
+void BalloonCollection::ShowAll() { |
+} |
+ |
+void BalloonCollection::HideAll() { |
+} |
+ |
+Balloon::Balloon(const Notification& notification, |
+ Profile* profile, |
+ SiteInstance* site_instance, |
+ BalloonCloseListener* listener) |
+ : profile_(profile), |
+ site_instance_(site_instance), |
+ notification_(notification), |
+ close_listener_(listener) { |
+} |
+ |
+Balloon::~Balloon() { |
+} |
+ |
+void Balloon::Show() { |
+ if (!balloon_view_.get()) { |
+ balloon_view_.reset(new BalloonView()); |
+ balloon_view_->Show(this); |
+ } |
+} |
+ |
+ |
+void Balloon::Close() { |
+ if (close_listener_) { |
+ close_listener_->OnBalloonClosed(this); |
+ } |
+} |
+ |
+void Balloon::SetPosition(const gfx::Point& upper_left, bool reposition) { |
+ position_ = upper_left; |
+ if (reposition && balloon_view_.get()) { |
+ balloon_view_->RepositionToBalloon(); |
+ } |
+} |
+ |
+void Balloon::SetSize(const gfx::Size& size) { |
+ size_ = size; |
+} |
+ |
+const gfx::Point& Balloon::position() const { |
+ return position_; |
+} |
+ |
+const gfx::Size& Balloon::size() const { |
+ return size_; |
+} |
+ |
+BalloonCollection::Layout::Placement BalloonCollection::Layout::placement_ = |
+ BalloonCollection::Layout::VERTICALLY_FROM_BOTTOM_RIGHT; |
+ |
+BalloonCollection::Layout::Layout() |
+ : font_scale_factor_(1.0) { |
+ RefreshSystemMetrics(); |
+} |
+ |
+// Scale the size to count in the system font factor |
+int BalloonCollection::Layout::ScaleSize(int size) const { |
+ return static_cast<int>(size * font_scale_factor_); |
+} |
+ |
+int BalloonCollection::Layout::min_balloon_width() const { |
+ return ScaleSize(kBalloonMinWidth); |
+} |
+ |
+int BalloonCollection::Layout::max_balloon_width() const { |
+ return ScaleSize(kBalloonMaxWidth); |
+} |
+ |
+int BalloonCollection::Layout::min_balloon_height() const { |
+ return ScaleSize(kBalloonMinHeight); |
+} |
+ |
+int BalloonCollection::Layout::max_balloon_height() const { |
+ return ScaleSize(kBalloonMaxHeight); |
+} |
+ |
+gfx::Point BalloonCollection::Layout::GetOrigin() const { |
+ int x = 0; |
+ int y = 0; |
+ switch (placement_) { |
+ case HORIZONTALLY_FROM_BOTTOM_LEFT: |
+ x = work_area_.x(); |
+ y = work_area_.bottom(); |
+ break; |
+ case HORIZONTALLY_FROM_BOTTOM_RIGHT: |
+ x = work_area_.right(); |
+ y = work_area_.bottom(); |
+ break; |
+ case VERTICALLY_FROM_TOP_RIGHT: |
+ x = work_area_.right(); |
+ y = work_area_.y(); |
+ break; |
+ case VERTICALLY_FROM_BOTTOM_RIGHT: |
+ x = work_area_.right(); |
+ y = work_area_.bottom(); |
+ break; |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+ return gfx::Point(x, y); |
+} |
+ |
+gfx::Point BalloonCollection::Layout::NextPosition( |
+ const gfx::Size& balloon_size, |
+ gfx::Point* origin) const { |
+ DCHECK(origin); |
+ |
+ int x = 0; |
+ int y = 0; |
+ switch (placement_) { |
+ case HORIZONTALLY_FROM_BOTTOM_LEFT: |
+ x = origin->x(); |
+ y = origin->y() - balloon_size.height(); |
+ origin->set_x(origin->x() + balloon_size.width()); |
+ break; |
+ case HORIZONTALLY_FROM_BOTTOM_RIGHT: |
+ origin->set_x(origin->x() - balloon_size.width()); |
+ x = origin->x(); |
+ y = origin->y() - balloon_size.height(); |
+ break; |
+ case VERTICALLY_FROM_TOP_RIGHT: |
+ x = origin->x() - balloon_size.width(); |
+ y = origin->y(); |
+ origin->set_y(origin->y() + balloon_size.height()); |
+ break; |
+ case VERTICALLY_FROM_BOTTOM_RIGHT: |
+ origin->set_y(origin->y() - balloon_size.height()); |
+ x = origin->x() - balloon_size.width(); |
+ y = origin->y(); |
+ break; |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+ return gfx::Point(x, y); |
+} |
+ |
+bool BalloonCollection::Layout::RefreshSystemMetrics() { |
+ bool changed = false; |
+ |
+ gfx::Rect new_work_area(work_area_.x(), work_area_.y(), |
+ work_area_.width(), work_area_.height()); |
+ GetMainScreenWorkArea(&new_work_area); |
+ if (!work_area_.Equals(new_work_area)) { |
+ work_area_.SetRect(new_work_area.x(), new_work_area.y(), |
+ new_work_area.width(), new_work_area.height()); |
+ changed = true; |
+ } |
+ |
+ double new_font_scale_factor = font_scale_factor_; |
+ new_font_scale_factor = GetSystemFontScaleFactor(); |
+ if (font_scale_factor_ != new_font_scale_factor) { |
+ font_scale_factor_ = new_font_scale_factor; |
+ changed = true; |
+ } |
+ return changed; |
+} |
+ |
+const void BalloonCollection::Layout::GetMaxLengths( |
+ int* max_balloon_length, |
+ int* total_length) const { |
+ DCHECK(max_balloon_length && total_length); |
+ |
+ switch (placement_) { |
+ case HORIZONTALLY_FROM_BOTTOM_LEFT: |
+ case HORIZONTALLY_FROM_BOTTOM_RIGHT: |
+ *total_length = work_area_.width(); |
+ *max_balloon_length = max_balloon_width(); |
+ break; |
+ case VERTICALLY_FROM_TOP_RIGHT: |
+ case VERTICALLY_FROM_BOTTOM_RIGHT: |
+ *total_length = work_area_.height(); |
+ *max_balloon_length = max_balloon_height(); |
+ break; |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+} |
+ |