summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorjohnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-29 17:51:36 +0000
committerjohnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-29 17:51:36 +0000
commitc8173315b15ccf58d8062900fd25eebfd56eb327 (patch)
treea73c01e3f081369ec15cc91fefb80b2baf8eb94f /chrome/browser
parent276aa6a60396329c7fb4a988bd0be7f7d0895651 (diff)
downloadchromium_src-c8173315b15ccf58d8062900fd25eebfd56eb327.zip
chromium_src-c8173315b15ccf58d8062900fd25eebfd56eb327.tar.gz
chromium_src-c8173315b15ccf58d8062900fd25eebfd56eb327.tar.bz2
Adds UI components for desktop notifications, including balloon view classes to display toasts on the screen, and manager for controlling the layout of the balloons.
BUG=none TEST=none yet (part of larger patch) Review URL: http://codereview.chromium.org/338051 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@30471 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/notifications/balloon.cc43
-rw-r--r--chrome/browser/notifications/balloon.h91
-rw-r--r--chrome/browser/notifications/balloon_collection.cc172
-rw-r--r--chrome/browser/notifications/balloon_collection.h151
-rw-r--r--chrome/browser/notifications/balloon_collection_linux.cc21
-rw-r--r--chrome/browser/notifications/balloon_collection_mac.mm22
-rw-r--r--chrome/browser/notifications/balloon_collection_win.cc54
-rw-r--r--chrome/browser/notifications/balloons.h200
-rw-r--r--chrome/browser/views/notifications/balloon_view.cc354
-rw-r--r--chrome/browser/views/notifications/balloon_view.h134
-rw-r--r--chrome/browser/views/notifications/balloon_view_host.cc107
-rw-r--r--chrome/browser/views/notifications/balloon_view_host.h92
-rw-r--r--chrome/browser/views/notifications/balloon_view_host_gtk.cc12
13 files changed, 1253 insertions, 200 deletions
diff --git a/chrome/browser/notifications/balloon.cc b/chrome/browser/notifications/balloon.cc
new file mode 100644
index 0000000..71abe66
--- /dev/null
+++ b/chrome/browser/notifications/balloon.cc
@@ -0,0 +1,43 @@
+// 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/balloon.h"
+
+#include "base/gfx/rect.h"
+#include "base/logging.h"
+#include "chrome/browser/notifications/balloon_collection.h"
+#include "chrome/browser/renderer_host/site_instance.h"
+
+Balloon::Balloon(const Notification& notification, Profile* profile,
+ BalloonCloseListener* listener)
+ : profile_(profile),
+ notification_(notification),
+ close_listener_(listener) {
+}
+
+Balloon::~Balloon() {
+}
+
+void Balloon::SetPosition(const gfx::Point& upper_left, bool reposition) {
+ position_ = upper_left;
+ if (reposition && balloon_view_.get())
+ balloon_view_->RepositionToBalloon();
+}
+
+void Balloon::set_view(BalloonView* balloon_view) {
+ balloon_view_.reset(balloon_view);
+}
+
+void Balloon::Show() {
+ notification_.Display();
+ if (balloon_view_.get()) {
+ balloon_view_->Show(this);
+ }
+}
+
+void Balloon::Close(bool by_user) {
+ notification_.Close(by_user);
+ if (close_listener_)
+ close_listener_->OnBalloonClosed(this);
+}
diff --git a/chrome/browser/notifications/balloon.h b/chrome/browser/notifications/balloon.h
new file mode 100644
index 0000000..5559f09
--- /dev/null
+++ b/chrome/browser/notifications/balloon.h
@@ -0,0 +1,91 @@
+// 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.
+
+// Handles the visible notification (or balloons).
+
+#ifndef CHROME_BROWSER_NOTIFICATIONS_BALLOON_H_
+#define CHROME_BROWSER_NOTIFICATIONS_BALLOON_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/gfx/point.h"
+#include "base/gfx/rect.h"
+#include "base/gfx/size.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/notifications/notification.h"
+
+class Balloon;
+class Profile;
+class SiteInstance;
+
+// Interface for a view that displays a balloon.
+class BalloonView {
+ public:
+ virtual ~BalloonView() { }
+
+ // Show the view on the screen.
+ virtual void Show(Balloon* balloon) = 0;
+
+ // Reposition the view to match the position of its balloon.
+ virtual void RepositionToBalloon() = 0;
+
+ // Close the view.
+ virtual void Close() = 0;
+};
+
+// Represents a Notification on the screen.
+class Balloon {
+ public:
+ class BalloonCloseListener {
+ public:
+ virtual ~BalloonCloseListener() {}
+
+ // Called when a balloon is closed.
+ virtual void OnBalloonClosed(Balloon* source) = 0;
+ };
+
+ // |listener| may be null in unit tests w/o actual UI.
+ Balloon(const Notification& notification,
+ Profile* profile,
+ BalloonCloseListener* listener);
+ virtual ~Balloon();
+
+ const Notification& notification() const { return notification_; }
+ Profile* profile() const { return profile_; }
+
+ const gfx::Point& position() const { return position_; }
+ void SetPosition(const gfx::Point& upper_left, bool reposition);
+
+ const gfx::Size& size() const { return size_; }
+ void set_size(const gfx::Size& size) { size_ = size; }
+
+ // Provides a view for this balloon. Ownership transfers
+ // to this object.
+ void set_view(BalloonView* balloon_view);
+
+ virtual void Show();
+ virtual void Close(bool by_user);
+
+ private:
+ // Non-owned pointer to the profile.
+ Profile* profile_;
+
+ // The notification being shown in this balloon.
+ Notification notification_;
+
+ // A listener to be called when the balloon closes.
+ BalloonCloseListener* close_listener_;
+
+ // The actual UI element for the balloon.
+ scoped_ptr<BalloonView> balloon_view_;
+
+ // Position and size of the balloon on the screen.
+ gfx::Point position_;
+ gfx::Size size_;
+
+ DISALLOW_COPY_AND_ASSIGN(Balloon);
+};
+
+#endif // CHROME_BROWSER_NOTIFICATIONS_BALLOON_H_
diff --git a/chrome/browser/notifications/balloon_collection.cc b/chrome/browser/notifications/balloon_collection.cc
new file mode 100644
index 0000000..d979ddd
--- /dev/null
+++ b/chrome/browser/notifications/balloon_collection.cc
@@ -0,0 +1,172 @@
+// 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/balloon_collection.h"
+
+#include "base/gfx/rect.h"
+#include "base/logging.h"
+#include "base/stl_util-inl.h"
+#include "chrome/browser/notifications/balloon.h"
+
+namespace {
+
+// Portion of the screen allotted for notifications. When notification balloons
+// extend over this, no new notifications are shown until some are closed.
+const double kPercentBalloonFillFactor = 0.7;
+
+// Allow at least this number of balloons on the screen.
+const int kMinAllowedBalloonCount = 2;
+
+} // namespace
+
+// static
+BalloonCollectionImpl::Layout::Placement
+ BalloonCollectionImpl::Layout::placement_ =
+ Layout::VERTICALLY_FROM_BOTTOM_RIGHT;
+
+BalloonCollectionImpl::BalloonCollectionImpl()
+ : space_change_listener_(NULL) {
+}
+
+BalloonCollectionImpl::~BalloonCollectionImpl() {
+ STLDeleteElements(&balloons_);
+}
+
+void BalloonCollectionImpl::Add(const Notification& notification,
+ Profile* profile) {
+ Balloon* new_balloon = MakeBalloon(notification, profile);
+ balloons_.push_back(new_balloon);
+ PositionBalloons(false);
+ new_balloon->Show();
+
+ // There may be no listener in a unit test.
+ if (space_change_listener_)
+ space_change_listener_->OnBalloonSpaceChanged();
+}
+
+bool BalloonCollectionImpl::HasSpace() const {
+ if (count() < kMinAllowedBalloonCount)
+ return true;
+
+ int max_balloon_size = 0;
+ int total_size = 0;
+ layout_.GetMaxLinearSize(&max_balloon_size, &total_size);
+
+ int current_max_size = max_balloon_size * count();
+ int max_allowed_size = static_cast<int>(total_size *
+ kPercentBalloonFillFactor);
+ return current_max_size < max_allowed_size - max_balloon_size;
+}
+
+void BalloonCollectionImpl::OnBalloonClosed(Balloon* source) {
+ // We want to free the balloon when finished.
+ scoped_ptr<Balloon> closed(source);
+ for (Balloons::iterator it = balloons_.begin(); it != balloons_.end(); ++it) {
+ if (*it == source) {
+ balloons_.erase(it);
+ break;
+ }
+ }
+ PositionBalloons(true);
+
+ // There may be no listener in a unit test.
+ if (space_change_listener_)
+ space_change_listener_->OnBalloonSpaceChanged();
+}
+
+void BalloonCollectionImpl::PositionBalloons(bool reposition) {
+ gfx::Point origin = layout_.GetLayoutOrigin();
+ for (Balloons::iterator it = balloons_.begin(); it != balloons_.end(); ++it) {
+ gfx::Point upper_left = layout_.NextPosition((*it)->size(), &origin);
+ (*it)->SetPosition(upper_left, reposition);
+ }
+}
+
+BalloonCollectionImpl::Layout::Layout() {
+ RefreshSystemMetrics();
+}
+
+const void BalloonCollectionImpl::Layout::GetMaxLinearSize(
+ int* max_balloon_size,
+ int* total_size) const {
+ DCHECK(max_balloon_size && total_size);
+
+ switch (placement_) {
+ case HORIZONTALLY_FROM_BOTTOM_LEFT:
+ case HORIZONTALLY_FROM_BOTTOM_RIGHT:
+ *total_size = work_area_.width();
+ *max_balloon_size = max_balloon_width();
+ break;
+ case VERTICALLY_FROM_TOP_RIGHT:
+ case VERTICALLY_FROM_BOTTOM_RIGHT:
+ *total_size = work_area_.height();
+ *max_balloon_size = max_balloon_height();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+gfx::Point BalloonCollectionImpl::Layout::GetLayoutOrigin() 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 BalloonCollectionImpl::Layout::NextPosition(
+ const gfx::Size& balloon_size,
+ gfx::Point* position_iterator) const {
+ DCHECK(position_iterator);
+
+ int x = 0;
+ int y = 0;
+ switch (placement_) {
+ case HORIZONTALLY_FROM_BOTTOM_LEFT:
+ x = position_iterator->x();
+ y = position_iterator->y() - balloon_size.height();
+ position_iterator->set_x(position_iterator->x() + balloon_size.width());
+ break;
+ case HORIZONTALLY_FROM_BOTTOM_RIGHT:
+ position_iterator->set_x(position_iterator->x() - balloon_size.width());
+ x = position_iterator->x();
+ y = position_iterator->y() - balloon_size.height();
+ break;
+ case VERTICALLY_FROM_TOP_RIGHT:
+ x = position_iterator->x() - balloon_size.width();
+ y = position_iterator->y();
+ position_iterator->set_y(position_iterator->y() + balloon_size.height());
+ break;
+ case VERTICALLY_FROM_BOTTOM_RIGHT:
+ position_iterator->set_y(position_iterator->y() - balloon_size.height());
+ x = position_iterator->x() - balloon_size.width();
+ y = position_iterator->y();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ return gfx::Point(x, y);
+}
diff --git a/chrome/browser/notifications/balloon_collection.h b/chrome/browser/notifications/balloon_collection.h
new file mode 100644
index 0000000..a756936
--- /dev/null
+++ b/chrome/browser/notifications/balloon_collection.h
@@ -0,0 +1,151 @@
+// 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.
+
+// Handles the visible notification (or balloons).
+
+#ifndef CHROME_BROWSER_NOTIFICATIONS_BALLOON_COLLECTION_H_
+#define CHROME_BROWSER_NOTIFICATIONS_BALLOON_COLLECTION_H_
+
+#include <deque>
+
+#include "base/gfx/point.h"
+#include "base/gfx/rect.h"
+#include "base/gfx/size.h"
+#include "chrome/browser/notifications/balloon.h"
+#include "chrome/browser/notifications/notification.h"
+
+class Balloon;
+class Profile;
+
+class BalloonCollection {
+ public:
+ virtual ~BalloonCollection() {}
+
+ // Adds a new balloon for the specified notification.
+ virtual void Add(const Notification& notification,
+ Profile* profile) = 0;
+
+ // Is there room to add another notification?
+ virtual bool HasSpace() const = 0;
+};
+
+// A balloon collection represents a set of notification balloons being
+// shown on the screen. It positions new notifications according to
+// a layout, and monitors for balloons being closed, which it reports
+// up to its parent, the notification UI manager.
+class BalloonCollectionImpl : public BalloonCollection,
+ public Balloon::BalloonCloseListener {
+ public:
+ class BalloonSpaceChangeListener {
+ public:
+ virtual ~BalloonSpaceChangeListener() {}
+
+ // Called when there is more or less space for balloons due to
+ // monitor size changes or balloons disappearing.
+ virtual void OnBalloonSpaceChanged() = 0;
+ };
+
+ BalloonCollectionImpl();
+ virtual ~BalloonCollectionImpl();
+
+ BalloonSpaceChangeListener* space_change_listener() {
+ return space_change_listener_;
+ }
+ void set_space_change_listener(BalloonSpaceChangeListener* listener) {
+ space_change_listener_ = listener;
+ }
+
+ // BalloonCollectionInterface overrides
+ virtual void Add(const Notification& notification,
+ Profile* profile);
+ virtual bool HasSpace() const;
+
+ // Balloon::BalloonCloseListener interface
+ virtual void OnBalloonClosed(Balloon* source);
+
+ protected:
+ // Creates a new balloon. Overridable by unit tests. The caller is
+ // responsible for freeing the pointer returned.
+ virtual Balloon* MakeBalloon(const Notification& notification,
+ Profile* profile);
+
+ private:
+ // The number of balloons being displayed.
+ int count() const { return balloons_.size(); }
+
+ // Adjusts the positions of the balloons (e.g., when one is closed).
+ void PositionBalloons(bool is_reposition);
+
+ // Calculates layout values for the balloons including
+ // the scaling, the max/min sizes, and the upper left corner of each.
+ class Layout {
+ public:
+ Layout();
+
+ // Refresh the work area and balloon placement.
+ void OnDisplaySettingsChanged();
+
+ // TODO(johnnyg): Scale the size to account for the system font factor.
+ int min_balloon_width() const { return kBalloonMinWidth; }
+ int max_balloon_width() const { return kBalloonMaxWidth; }
+ int min_balloon_height() const { return kBalloonMinHeight; }
+ int max_balloon_height() const { return kBalloonMaxHeight; }
+
+ // Returns both the total space available and the maximum
+ // allowed per balloon.
+ //
+ // The size may be a height or length depending on the way that
+ // balloons are laid out.
+ const void GetMaxLinearSize(int* max_balloon_size, int* total_size) const;
+
+ // Refresh the cached values for work area and drawing metrics.
+ // The application should call this method to re-acquire metrics after
+ // any resolution or settings change.
+ // Returns true if and only if a metric changed.
+ bool RefreshSystemMetrics();
+
+ // Returns the origin for the sequence of balloons depending on layout.
+ // Should not be used to place a balloon -- only to call NextPosition().
+ gfx::Point GetLayoutOrigin() const;
+
+ // Compute the position for the next balloon.
+ // Start with *position_iterator = GetLayoutOrigin() and call repeatedly
+ // to get a sequence of positions. Return value is the upper-left coordinate
+ // for each next balloon.
+ gfx::Point NextPosition(const gfx::Size& balloon_size,
+ gfx::Point* position_iterator) const;
+
+ private:
+ enum Placement {
+ HORIZONTALLY_FROM_BOTTOM_LEFT,
+ HORIZONTALLY_FROM_BOTTOM_RIGHT,
+ VERTICALLY_FROM_TOP_RIGHT,
+ VERTICALLY_FROM_BOTTOM_RIGHT
+ };
+
+ // Minimum and maximum size of balloon
+ static const int kBalloonMinWidth = 300;
+ static const int kBalloonMaxWidth = 300;
+ static const int kBalloonMinHeight = 90;
+ static const int kBalloonMaxHeight = 120;
+
+ static Placement placement_;
+ gfx::Rect work_area_;
+ DISALLOW_COPY_AND_ASSIGN(Layout);
+ };
+
+ // Non-owned pointer to an object listening for space changes.
+ BalloonSpaceChangeListener* space_change_listener_;
+
+ // Queue of active balloons.
+ typedef std::deque<Balloon*> Balloons;
+ Balloons balloons_;
+
+ // The layout parameters for balloons in this collection.
+ Layout layout_;
+
+ DISALLOW_COPY_AND_ASSIGN(BalloonCollectionImpl);
+};
+
+#endif // CHROME_BROWSER_NOTIFICATIONS_BALLOON_COLLECTION_H_
diff --git a/chrome/browser/notifications/balloon_collection_linux.cc b/chrome/browser/notifications/balloon_collection_linux.cc
new file mode 100644
index 0000000..6d29f97
--- /dev/null
+++ b/chrome/browser/notifications/balloon_collection_linux.cc
@@ -0,0 +1,21 @@
+// 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/balloon_collection.h"
+
+#include "base/gfx/size.h"
+#include "base/logging.h"
+
+Balloon* BalloonCollectionImpl::MakeBalloon(const Notification& notification,
+ Profile* profile) {
+ // TODO(johnnyg): http://crbug.com/23954. Part of future Linux support.
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+bool BalloonCollectionImpl::Layout::RefreshSystemMetrics() {
+ // TODO(johnnyg): http://crbug.com/23954. Part of future Linux support.
+ NOTIMPLEMENTED();
+ return false;
+}
diff --git a/chrome/browser/notifications/balloon_collection_mac.mm b/chrome/browser/notifications/balloon_collection_mac.mm
new file mode 100644
index 0000000..45728fb
--- /dev/null
+++ b/chrome/browser/notifications/balloon_collection_mac.mm
@@ -0,0 +1,22 @@
+// 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/balloon_collection.h"
+
+#include "base/gfx/size.h"
+#include "base/logging.h"
+
+Balloon* BalloonCollectionImpl::MakeBalloon(const Notification& notification,
+ Profile* profile) {
+ // TODO(johnnyg): http://crbug.com/23066. Part of future Mac support.
+ NOTIMPLEMENTED();
+ return NULL;
+}
+
+bool BalloonCollectionImpl::Layout::RefreshSystemMetrics() {
+ // TODO(johnnyg): http://crbug.com/23066. Part of future Mac support.
+ NOTIMPLEMENTED();
+ return false;
+}
+
diff --git a/chrome/browser/notifications/balloon_collection_win.cc b/chrome/browser/notifications/balloon_collection_win.cc
new file mode 100644
index 0000000..45f7921
--- /dev/null
+++ b/chrome/browser/notifications/balloon_collection_win.cc
@@ -0,0 +1,54 @@
+// 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/balloon_collection.h"
+
+#include "base/gfx/rect.h"
+#include "base/logging.h"
+#include "base/stl_util-inl.h"
+#include "chrome/browser/notifications/balloon.h"
+#include "chrome/browser/views/notifications/balloon_view.h"
+
+namespace {
+
+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 call to ::SystemParametersInfo fails 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);
+ }
+}
+
+} // namespace
+
+Balloon* BalloonCollectionImpl::MakeBalloon(const Notification& notification,
+ Profile* profile) {
+ Balloon* balloon = new Balloon(notification, profile, this);
+ balloon->set_view(new BalloonViewImpl());
+ gfx::Size size(layout_.min_balloon_width(), layout_.min_balloon_height());
+ balloon->set_size(size);
+ return balloon;
+}
+
+bool BalloonCollectionImpl::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;
+ }
+
+ return changed;
+}
diff --git a/chrome/browser/notifications/balloons.h b/chrome/browser/notifications/balloons.h
deleted file mode 100644
index 6191d53..0000000
--- a/chrome/browser/notifications/balloons.h
+++ /dev/null
@@ -1,200 +0,0 @@
-// 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.
-
-// Handles the visible notification (or balloons).
-
-#ifndef CHROME_BROWSER_NOTIFICATIONS_BALLOONS_H_
-#define CHROME_BROWSER_NOTIFICATIONS_BALLOONS_H_
-
-#include <deque>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/gfx/point.h"
-#include "base/gfx/rect.h"
-#include "base/gfx/size.h"
-#include "base/scoped_ptr.h"
-#include "chrome/browser/notifications/notification.h"
-
-class Balloon;
-class BalloonView;
-class Profile;
-class SiteInstance;
-
-class BalloonCloseListener {
- public:
- virtual ~BalloonCloseListener() { }
-
- // Called when a balloon is closed.
- virtual void OnBalloonClosed(Balloon* source) = 0;
-};
-
-class BalloonSpaceChangeListener {
- public:
- virtual ~BalloonSpaceChangeListener() { }
-
- // Called when there is more or less space for balloons due to
- // monitor size changes or balloons disappearing.
- virtual void OnBalloonSpaceChanged() = 0;
-};
-
-class BalloonCollectionInterface {
- public:
- virtual ~BalloonCollectionInterface() {}
-
- // Adds a new balloon for the specified notification.
- virtual void Add(const Notification& notification,
- Profile* profile,
- SiteInstance* site_instance) = 0;
-
- // Is there room to add another notification?
- virtual bool HasSpace() const = 0;
-};
-
-typedef std::deque<Balloon*> Balloons;
-
-// Represents a Notification on the screen.
-class Balloon {
- public:
- Balloon(const Notification& notification,
- Profile* profile,
- SiteInstance* site_instance,
- BalloonCloseListener* listener);
- ~Balloon();
-
- const Notification& notification() const {
- return notification_;
- }
-
- Profile* profile() const {
- return profile_;
- }
-
- SiteInstance* site_instance() const {
- return site_instance_;
- }
-
- void SetPosition(const gfx::Point& upper_left, bool reposition);
- void SetSize(const gfx::Size& size);
- void Show();
- void Close();
-
- const gfx::Point& position() const;
- const gfx::Size& size() const;
-
- private:
- Profile* profile_;
- SiteInstance* site_instance_;
- Notification notification_;
- BalloonCloseListener* close_listener_;
- scoped_ptr<BalloonView> balloon_view_;
- gfx::Point position_;
- gfx::Size size_;
- DISALLOW_COPY_AND_ASSIGN(Balloon);
-};
-
-class BalloonCollection : public BalloonCollectionInterface,
- public BalloonCloseListener {
- public:
- explicit BalloonCollection();
-
- BalloonSpaceChangeListener* space_change_listener() { return listener_; }
- void set_space_change_listener(BalloonSpaceChangeListener* listener) {
- listener_ = listener;
- }
-
- // BalloonCollectionInterface overrides
- virtual void Add(const Notification& notification,
- Profile* profile,
- SiteInstance* site_instance);
- virtual void ShowAll();
- virtual void HideAll();
- virtual bool HasSpace() const;
-
- // BalloonCloseListener interface
- virtual void OnBalloonClosed(Balloon* source);
-
- protected:
- // Overridable by unit tests.
- virtual Balloon* MakeBalloon(const Notification& notification,
- Profile* profile,
- SiteInstance* site_instance) {
- return new Balloon(notification, profile, site_instance, this);
- }
-
- private:
- // The number of balloons being displayed.
- int count() const { return balloons_.size(); }
-
- // Calculates layout values for the balloons including
- // the scaling, the max/min sizes, and the upper left corner of each.
- class Layout {
- public:
- Layout();
-
- // Refresh the work area and balloon placement.
- void OnDisplaySettingsChanged();
-
- int min_balloon_width() const;
- int max_balloon_width() const;
- int min_balloon_height() const;
- int max_balloon_height() const;
-
- // Returns both the total length available and the maximum
- // allowed per balloon.
- //
- // The length may be a height or length depending on the way that
- // balloons are laid out.
- const void GetMaxLengths(int* max_balloon_length, int* total_length) const;
-
- // Scale the size to count in the system font factor.
- int ScaleSize(int size) const;
-
- // Refresh the cached values for work area and drawing metrics.
- // This is done automatically first time and the application should
- // call this method to re-acquire metrics after any
- // resolution or settings change.
- //
- // Return true if and only if a metric changed.
- bool RefreshSystemMetrics();
-
- // Returns the starting value for NextUpperLeftPosition.
- gfx::Point GetStartPosition() const;
-
- // Compute the position for the next balloon.
- // Modifies origin.
- // Returns the position of the upper left coordinate for the given
- // balloon.
- gfx::Point NextPosition(const gfx::Size& balloon_size,
- gfx::Point* origin) const;
-
- private:
- enum Placement {
- HORIZONTALLY_FROM_BOTTOM_LEFT,
- HORIZONTALLY_FROM_BOTTOM_RIGHT,
- VERTICALLY_FROM_TOP_RIGHT,
- VERTICALLY_FROM_BOTTOM_RIGHT
- };
-
- // Minimum and maximum size of balloon
- static const int kBalloonMinWidth = 300;
- static const int kBalloonMaxWidth = 300;
- static const int kBalloonMinHeight = 90;
- static const int kBalloonMaxHeight = 120;
-
- static Placement placement_;
- gfx::Rect work_area_;
- double font_scale_factor_;
- DISALLOW_COPY_AND_ASSIGN(Layout);
- };
-
- // Non-owned pointer to an object listening for space changes.
- BalloonSpaceChangeListener* listener_;
-
- Balloons balloons_;
- Layout layout_;
- DISALLOW_COPY_AND_ASSIGN(BalloonCollection);
-};
-
-#endif // CHROME_BROWSER_NOTIFICATIONS_BALLOONS_H_
diff --git a/chrome/browser/views/notifications/balloon_view.cc b/chrome/browser/views/notifications/balloon_view.cc
new file mode 100644
index 0000000..a092ce4
--- /dev/null
+++ b/chrome/browser/views/notifications/balloon_view.cc
@@ -0,0 +1,354 @@
+// 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/views/notifications/balloon_view.h"
+
+#include <vector>
+
+#include "app/gfx/canvas.h"
+#include "app/gfx/gdi_util.h"
+#include "app/gfx/insets.h"
+#include "app/gfx/native_widget_types.h"
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "chrome/browser/browser_theme_provider.h"
+#include "chrome/browser/notifications/balloon.h"
+#include "chrome/browser/views/notifications/balloon_view_host.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "views/controls/button/button.h"
+#include "views/controls/button/text_button.h"
+#include "views/controls/label.h"
+#include "views/controls/native/native_view_host.h"
+#include "views/painter.h"
+#include "views/widget/widget_win.h"
+
+using views::Widget;
+
+namespace {
+
+// How many pixels of overlap there is between the shelf top and the
+// balloon bottom.
+const int kTopMargin = 1;
+const int kBottomMargin = 1;
+const int kLeftMargin = 1;
+const int kRightMargin = 1;
+const int kShelfBorderTopOverlap = 2;
+
+// Properties of the dismiss button.
+const int kDismissButtonWidth = 46;
+const int kDismissButtonHeight = 20;
+
+// Properties of the origin label.
+const int kLeftLabelMargin = 5;
+
+// TODO(johnnyg): Add a shadow for the frame.
+const int kLeftShadowWidth = 0;
+const int kRightShadowWidth = 0;
+const int kTopShadowWidth = 0;
+const int kBottomShadowWidth = 0;
+
+// Optional animation.
+const bool kAnimateEnabled = true;
+
+// The shelf height for the system default font size. It is scaled
+// with changes in the default font size.
+const int kDefaultShelfHeight = 22;
+
+} // namespace
+
+class BalloonCloseButtonListener : public views::ButtonListener {
+ public:
+ explicit BalloonCloseButtonListener(BalloonView* view)
+ : view_(view) {}
+ virtual ~BalloonCloseButtonListener() {}
+
+ // The only button currently is the close button.
+ virtual void ButtonPressed(views::Button* sender, const views::Event&) {
+ view_->Close();
+ }
+
+ private:
+ // Non-owned pointer to the view which owns this object.
+ BalloonView* view_;
+};
+
+BalloonViewImpl::BalloonViewImpl()
+ : balloon_(NULL),
+ frame_container_(NULL),
+ html_container_(NULL),
+ html_contents_(NULL),
+ shelf_background_(NULL),
+ balloon_background_(NULL),
+ close_button_(NULL),
+ close_button_listener_(NULL),
+ animation_(NULL),
+ method_factory_(this) {
+ // This object is not to be deleted by the views hierarchy,
+ // as it is owned by the balloon.
+ SetParentOwned(false);
+
+ // Load the sprites for the frames.
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ SkBitmap* shelf_bitmap = rb.GetBitmapNamed(IDR_BALLOON_SHELF);
+ SkBitmap* border_bitmap = rb.GetBitmapNamed(IDR_BALLOON_BORDER);
+
+ // Insets are such because the sprites have 3x3 corners.
+ gfx::Insets insets(3, 3, 3, 3);
+ shelf_background_.reset(
+ views::Painter::CreateImagePainter(*shelf_bitmap, insets, true));
+ balloon_background_.reset(
+ views::Painter::CreateImagePainter(*border_bitmap, insets, false));
+}
+
+BalloonViewImpl::~BalloonViewImpl() {
+}
+
+void BalloonViewImpl::Close() {
+ MessageLoop::current()->PostTask(FROM_HERE,
+ method_factory_.NewRunnableMethod(&BalloonViewImpl::DelayedClose));
+}
+
+void BalloonViewImpl::DelayedClose() {
+ html_contents_->Shutdown();
+ html_container_->CloseNow();
+ frame_container_->CloseNow();
+ balloon_->Close(true);
+}
+
+void BalloonViewImpl::DidChangeBounds(const gfx::Rect& previous,
+ const gfx::Rect& current) {
+ SizeContentsWindow();
+}
+
+void BalloonViewImpl::SizeContentsWindow() {
+ if (!html_container_ || !frame_container_)
+ return;
+
+ gfx::Rect contents_rect = GetContentsRectangle();
+ html_container_->SetBounds(contents_rect);
+ html_container_->MoveAbove(frame_container_);
+
+ gfx::Path path;
+ GetContentsMask(contents_rect, &path);
+ html_container_->SetShape(path);
+}
+
+void BalloonViewImpl::RepositionToBalloon() {
+ DCHECK(frame_container_);
+ DCHECK(html_container_);
+ DCHECK(balloon_);
+
+ if (!kAnimateEnabled) {
+ frame_container_->SetBounds(
+ gfx::Rect(balloon_->position(), balloon_->size()));
+ gfx::Rect contents_rect = GetContentsRectangle();
+ html_container_->SetBounds(contents_rect);
+ return;
+ }
+
+ anim_frame_end_ = gfx::Rect(balloon_->position().x(),
+ balloon_->position().y(),
+ balloon_->size().width(),
+ balloon_->size().height());
+ frame_container_->GetBounds(&anim_frame_start_, false);
+ animation_.reset(new SlideAnimation(this));
+ animation_->Show();
+}
+
+void BalloonViewImpl::AnimationProgressed(const Animation* animation) {
+ DCHECK(animation == animation_.get());
+
+ // Linear interpolation from start to end position.
+ double e = animation->GetCurrentValue();
+ double s = (1.0 - e);
+
+ gfx::Rect frame_position(
+ static_cast<int>(s * anim_frame_start_.x() +
+ e * anim_frame_end_.x()),
+ static_cast<int>(s * anim_frame_start_.y() +
+ e * anim_frame_end_.y()),
+ static_cast<int>(s * anim_frame_start_.width() +
+ e * anim_frame_end_.width()),
+ static_cast<int>(s * anim_frame_start_.height() +
+ e * anim_frame_end_.height()));
+
+ frame_container_->SetBounds(frame_position);
+ html_container_->SetBounds(GetContentsRectangle());
+}
+
+void BalloonViewImpl::Show(Balloon* balloon) {
+ balloon_ = balloon;
+ close_button_listener_.reset(new BalloonCloseButtonListener(this));
+
+ SetBounds(balloon_->position().x(), balloon_->position().y(),
+ balloon_->size().width(), balloon_->size().height());
+
+ // We have to create two windows: one for the contents and one for the
+ // frame. Why?
+ // * The contents is an html window which cannot be a
+ // layered window (because it may have child windows for instance).
+ // * The frame is a layered window so that we can have nicely rounded
+ // corners using alpha blending (and we may do other alpha blending
+ // effects).
+ // Unfortunately, layered windows cannot have child windows. (Well, they can
+ // but the child windows don't render).
+ //
+ // We carefully keep these two windows in sync to present the illusion of
+ // one window to the user.
+ gfx::Rect contents_rect = GetContentsRectangle();
+ html_contents_ = new BalloonViewHost(balloon);
+ html_contents_->SetPreferredSize(gfx::Size(10000, 10000));
+
+ html_container_ = Widget::CreatePopupWidget(Widget::NotTransparent,
+ Widget::AcceptEvents,
+ Widget::DeleteOnDestroy);
+ html_container_->SetAlwaysOnTop(true);
+ html_container_->Init(NULL, contents_rect);
+ html_container_->SetContentsView(html_contents_);
+
+ gfx::Rect balloon_rect(x(), y(), width(), height());
+ frame_container_ = Widget::CreatePopupWidget(Widget::Transparent,
+ Widget::AcceptEvents,
+ Widget::DeleteOnDestroy);
+ frame_container_->SetAlwaysOnTop(true);
+ frame_container_->Init(NULL, balloon_rect);
+ frame_container_->SetContentsView(this);
+
+ const std::wstring dismiss_text =
+ l10n_util::GetString(IDS_NOTIFICATION_BALLOON_DISMISS_LABEL);
+ close_button_ = new views::TextButton(close_button_listener_.get(),
+ dismiss_text);
+ close_button_->SetFont(
+ ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::SmallFont));
+ close_button_->SetEnabledColor(BrowserThemeProvider::kDefaultColorTabText);
+ close_button_->set_alignment(views::TextButton::ALIGN_CENTER);
+ close_button_->SetBounds(width() - kDismissButtonWidth
+ - kRightMargin,
+ height() - kDismissButtonHeight
+ - kShelfBorderTopOverlap
+ - kBottomMargin,
+ kDismissButtonWidth,
+ kDismissButtonHeight);
+ AddChildView(close_button_);
+
+ const std::wstring source_label_text = l10n_util::GetStringF(
+ IDS_NOTIFICATION_BALLOON_SOURCE_LABEL,
+ ASCIIToWide(this->balloon_->notification().origin_url().spec()));
+
+ views::Label* source_label = new views::Label(source_label_text);
+ source_label->SetFont(ResourceBundle::GetSharedInstance().GetFont(
+ ResourceBundle::SmallFont));
+ source_label->SetColor(BrowserThemeProvider::kDefaultColorTabText);
+ source_label->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
+ source_label->SetBounds(kLeftLabelMargin,
+ height() - kDismissButtonHeight
+ - kShelfBorderTopOverlap
+ - kBottomMargin,
+ width() - kDismissButtonWidth
+ - kRightMargin,
+ kDismissButtonHeight);
+ AddChildView(source_label);
+
+ SizeContentsWindow();
+ html_container_->Show();
+ frame_container_->Show();
+
+ notification_registrar_.Add(this,
+ NotificationType::NOTIFY_BALLOON_DISCONNECTED, Source<Balloon>(balloon));
+}
+
+
+void BalloonViewImpl::GetContentsMask(const gfx::Rect& rect,
+ gfx::Path* path) const {
+ // This needs to remove areas that look like the following from each corner:
+ //
+ // xx
+ // x
+ path->moveTo(SkScalar(1), SkScalar(0));
+ // Upper right corner
+ path->arcTo(rect.width() - SkScalar(2), SkScalar(0),
+ rect.width() - SkScalar(1), SkScalar(2),
+ SkScalar(1));
+ // Lower right corner
+ path->arcTo(rect.width() - SkScalar(1), rect.height() - SkScalar(2),
+ rect.width() - SkScalar(2), rect.height() - SkScalar(1),
+ SkScalar(1));
+ // Lower left corner
+ path->arcTo(SkScalar(1), rect.height() - SkScalar(1),
+ 0, rect.height() - SkScalar(2),
+ SkScalar(1));
+ // Upper left corner
+ path->arcTo(0, SkScalar(1), SkScalar(1), 0, SkScalar(1));
+}
+
+gfx::Point BalloonViewImpl::GetContentsOffset() const {
+ return gfx::Point(kTopShadowWidth + kTopMargin,
+ kLeftShadowWidth + kLeftMargin);
+}
+
+int BalloonViewImpl::GetShelfHeight() const {
+ // TODO(johnnyg): add scaling here.
+ return kDefaultShelfHeight;
+}
+
+int BalloonViewImpl::GetFrameWidth() const {
+ return size().width() - kLeftShadowWidth - kRightShadowWidth;
+}
+
+int BalloonViewImpl::GetTotalFrameHeight() const {
+ return size().height() - kTopShadowWidth - kBottomShadowWidth;
+}
+
+int BalloonViewImpl::GetBalloonFrameHeight() const {
+ return GetTotalFrameHeight() - GetShelfHeight();
+}
+
+gfx::Rect BalloonViewImpl::GetContentsRectangle() const {
+ if (!frame_container_)
+ return gfx::Rect();
+
+ int contents_width = GetFrameWidth() - kLeftMargin - kRightMargin;
+ int contents_height = GetBalloonFrameHeight() - kTopMargin - kBottomMargin;
+ gfx::Point offset = GetContentsOffset();
+ gfx::Rect frame_rect;
+ frame_container_->GetBounds(&frame_rect, true);
+ return gfx::Rect(frame_rect.x() + offset.x(), frame_rect.y() + offset.y(),
+ contents_width, contents_height);
+}
+
+void BalloonViewImpl::Paint(gfx::Canvas* canvas) {
+ DCHECK(canvas);
+ int background_width = GetFrameWidth();
+ int background_height = GetBalloonFrameHeight();
+ balloon_background_->Paint(background_width, background_height, canvas);
+ canvas->save();
+ SkScalar y_offset =
+ static_cast<SkScalar>(background_height - kShelfBorderTopOverlap);
+ canvas->translate(0, y_offset);
+ shelf_background_->Paint(background_width, GetShelfHeight(), canvas);
+ canvas->restore();
+
+ View::Paint(canvas);
+}
+
+void BalloonViewImpl::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type != NotificationType::NOTIFY_BALLOON_DISCONNECTED) {
+ NOTREACHED();
+ return;
+ }
+
+ // If the renderer process attached to this balloon is disconnected
+ // (e.g., because of a crash), we want to close the balloon.
+ notification_registrar_.Remove(this,
+ NotificationType::NOTIFY_BALLOON_DISCONNECTED, Source<Balloon>(balloon_));
+ Close();
+}
diff --git a/chrome/browser/views/notifications/balloon_view.h b/chrome/browser/views/notifications/balloon_view.h
new file mode 100644
index 0000000..35f6db2
--- /dev/null
+++ b/chrome/browser/views/notifications/balloon_view.h
@@ -0,0 +1,134 @@
+// 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.
+
+// Draws the view for the balloons.
+
+#ifndef CHROME_BROWSER_VIEWS_NOTIFICATIONS_BALLOON_VIEW_H_
+#define CHROME_BROWSER_VIEWS_NOTIFICATIONS_BALLOON_VIEW_H_
+
+#include "app/gfx/path.h"
+#include "app/slide_animation.h"
+#include "base/basictypes.h"
+#include "base/gfx/point.h"
+#include "base/gfx/rect.h"
+#include "base/gfx/size.h"
+#include "base/scoped_ptr.h"
+#include "base/task.h"
+#include "chrome/browser/notifications/balloon.h"
+#include "chrome/common/notification_registrar.h"
+#include "chrome/common/notification_service.h"
+#include "views/view.h"
+
+namespace views {
+class ButtonListener;
+class ImagePainter;
+class TextButton;
+class WidgetWin;
+} // namespace views
+
+class BalloonViewHost;
+class NotificationDetails;
+class NotificationSource;
+class SlideAnimation;
+
+// A balloon view is the UI component for a desktop notification toasts.
+// It draws a border, and within the border an HTML renderer.
+class BalloonViewImpl : public BalloonView,
+ public views::View,
+ public NotificationObserver,
+ public AnimationDelegate {
+ public:
+ BalloonViewImpl();
+ ~BalloonViewImpl();
+
+ // BalloonView interface.
+ void Show(Balloon* balloon);
+ void RepositionToBalloon();
+ void Close();
+
+ private:
+ // Overridden from views::View.
+ virtual void Paint(gfx::Canvas* canvas);
+ virtual void DidChangeBounds(const gfx::Rect& previous,
+ const gfx::Rect& current);
+ virtual gfx::Size GetPreferredSize() {
+ return gfx::Size(1000, 1000);
+ }
+
+ // NotificationObserver method.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // AnimationDelegate method.
+ virtual void AnimationProgressed(const Animation* animation);
+
+ // How to mask the balloon contents to fit within the frame.
+ // Populates |path| with the outline.
+ void GetContentsMask(const gfx::Rect& contents_rect, gfx::Path* path) const;
+
+ // Adjust the contents window size to be appropriate for the frame.
+ void SizeContentsWindow();
+
+ // Do the delayed close work.
+ void DelayedClose();
+
+ // The height of the balloon's shelf.
+ // The shelf is where is close button is located.
+ int GetShelfHeight() const;
+
+ // The width of the frame (not including any shadow).
+ int GetFrameWidth() const;
+
+ // The height of the frame (not including any shadow).
+ int GetTotalFrameHeight() const;
+
+ // The height of the part of the frame around the balloon.
+ int GetBalloonFrameHeight() const;
+
+ // Where the balloon contents should be placed with respect to the top left
+ // of the frame.
+ gfx::Point GetContentsOffset() const;
+
+ // Where the balloon contents should be in screen coordinates.
+ gfx::Rect GetContentsRectangle() const;
+
+ // Non-owned pointer to the balloon which owns this object.
+ Balloon* balloon_;
+
+ // The window that contains the frame of the notification.
+ // Pointer owned by the View subclass.
+ views::Widget* frame_container_;
+
+ // The window that contains the contents of the notification.
+ // Pointer owned by the View subclass.
+ views::Widget* html_container_;
+
+ // The renderer of the HTML contents. Pointer owned by the views hierarchy.
+ BalloonViewHost* html_contents_;
+
+ // The following factory is used to call methods at a later time.
+ ScopedRunnableMethodFactory<BalloonViewImpl> method_factory_;
+
+ // Image painters for the frame of the toast.
+ scoped_ptr<views::Painter> shelf_background_;
+ scoped_ptr<views::Painter> balloon_background_;
+
+ // Pointer to sub-view is owned by the View sub-class.
+ views::TextButton* close_button_;
+
+ // Listener for clicks on the close button.
+ scoped_ptr<views::ButtonListener> close_button_listener_;
+
+ // An animation to move the balloon on the screen as its position changes.
+ scoped_ptr<SlideAnimation> animation_;
+ gfx::Rect anim_frame_start_;
+ gfx::Rect anim_frame_end_;
+
+ NotificationRegistrar notification_registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(BalloonViewImpl);
+};
+
+#endif // CHROME_BROWSER_VIEWS_NOTIFICATIONS_BALLOON_VIEW_H_
diff --git a/chrome/browser/views/notifications/balloon_view_host.cc b/chrome/browser/views/notifications/balloon_view_host.cc
new file mode 100644
index 0000000..cccb5f2
--- /dev/null
+++ b/chrome/browser/views/notifications/balloon_view_host.cc
@@ -0,0 +1,107 @@
+// 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/views/notifications/balloon_view_host.h"
+
+#include "base/string_util.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/notifications/balloon.h"
+#include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/render_widget_host_view.h"
+#if defined(OS_WIN)
+#include "chrome/browser/renderer_host/render_widget_host_view_win.h"
+#endif
+#include "chrome/browser/renderer_host/site_instance.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/renderer_preferences.h"
+#include "views/widget/widget.h"
+#include "views/widget/widget_win.h"
+
+BalloonViewHost::BalloonViewHost(Balloon* balloon)
+ : balloon_(balloon),
+ site_instance_(SiteInstance::CreateSiteInstance(balloon->profile())),
+ render_view_host_(NULL),
+ should_notify_on_disconnect_(false),
+ initialized_(false) {
+ DCHECK(balloon_);
+}
+
+void BalloonViewHost::Shutdown() {
+ if (render_view_host_) {
+ render_view_host_->Shutdown();
+ render_view_host_ = NULL;
+ }
+}
+
+RendererPreferences BalloonViewHost::GetRendererPrefs() const {
+ // We want links (a.k.a. top_level_requests) to be forwarded to the browser so
+ // that we can open them in a new tab rather than in the balloon.
+ RendererPreferences prefs = RendererPreferences();
+ prefs.browser_handles_top_level_requests = true;
+ return prefs;
+}
+
+void BalloonViewHost::RequestOpenURL(const GURL& url,
+ const GURL& referrer,
+ WindowOpenDisposition disposition) {
+ // Always open a link triggered within the notification balloon in a new tab.
+ BrowserList::GetLastActive()->AddTabWithURL(url, referrer,
+ PageTransition::LINK, true, 0, 0, GetSiteInstance());
+}
+
+void BalloonViewHost::RendererReady(RenderViewHost* /* render_view_host */) {
+ should_notify_on_disconnect_ = true;
+ NotificationService::current()->Notify(
+ NotificationType::NOTIFY_BALLOON_CONNECTED,
+ Source<Balloon>(balloon_), NotificationService::NoDetails());
+}
+
+void BalloonViewHost::RendererGone(RenderViewHost* /* render_view_host */) {
+ if (!should_notify_on_disconnect_)
+ return;
+
+ should_notify_on_disconnect_ = false;
+ NotificationService::current()->Notify(
+ NotificationType::NOTIFY_BALLOON_DISCONNECTED,
+ Source<Balloon>(balloon_), NotificationService::NoDetails());
+}
+
+void BalloonViewHost::Init(gfx::NativeView parent_hwnd) {
+ DCHECK(!render_view_host_) << "BalloonViewHost already initialized.";
+ RenderViewHost* rvh = new RenderViewHost(site_instance_.get(),
+ this, MSG_ROUTING_NONE);
+ render_view_host_ = rvh;
+
+ // Pointer is owned by the RVH.
+ RenderWidgetHostView* view = RenderWidgetHostView::CreateViewForWidget(rvh);
+ rvh->set_view(view);
+
+ // TODO(johnnyg): http://crbug.com/23954. Need a cross-platform solution.
+#if defined(OS_WIN)
+ RenderWidgetHostViewWin* view_win =
+ static_cast<RenderWidgetHostViewWin*>(view);
+
+ // Create the HWND.
+ HWND hwnd = view_win->Create(parent_hwnd);
+ view_win->ShowWindow(SW_SHOW);
+ Attach(hwnd);
+#else
+ NOTIMPLEMENTED();
+#endif
+
+ // Start up the renderer and point it at the balloon contents URL.
+ rvh->CreateRenderView();
+ rvh->NavigateToURL(balloon_->notification().content_url());
+ initialized_ = true;
+}
+
+void BalloonViewHost::ViewHierarchyChanged(bool is_add, views::View* parent,
+ views::View* child) {
+ NativeViewHost::ViewHierarchyChanged(is_add, parent, child);
+ if (is_add && GetWidget() && !initialized_)
+ Init(GetWidget()->GetNativeView());
+}
diff --git a/chrome/browser/views/notifications/balloon_view_host.h b/chrome/browser/views/notifications/balloon_view_host.h
new file mode 100644
index 0000000..5ef8294
--- /dev/null
+++ b/chrome/browser/views/notifications/balloon_view_host.h
@@ -0,0 +1,92 @@
+// 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.
+
+#ifndef CHROME_BROWSER_VIEWS_NOTIFICATIONS_BALLOON_VIEW_HOST_H_
+#define CHROME_BROWSER_VIEWS_NOTIFICATIONS_BALLOON_VIEW_HOST_H_
+
+#include "chrome/browser/notifications/balloon.h"
+#include "chrome/browser/renderer_host/render_view_host_delegate.h"
+#include "chrome/browser/renderer_host/site_instance.h"
+#include "views/controls/native/native_view_host.h"
+#include "webkit/glue/webpreferences.h"
+
+class Profile;
+class RenderViewHost;
+
+// BalloonViewHost class is a delegate to the renderer host for the HTML
+// notification. When initialized it creates a new RenderViewHost and loads
+// the contents of the toast into it. It also handles links within the toast,
+// loading them into a new tab.
+class BalloonViewHost : public views::NativeViewHost,
+ public RenderViewHostDelegate {
+ public:
+ explicit BalloonViewHost(Balloon* balloon);
+
+ ~BalloonViewHost() {
+ Shutdown();
+ }
+
+ // Stops showing the balloon.
+ void Shutdown();
+
+ // RenderViewHostDelegate overrides.
+ virtual WebPreferences GetWebkitPrefs() { return WebPreferences(); }
+ virtual RendererPreferences GetRendererPrefs() const;
+ virtual SiteInstance* GetSiteInstance() const {
+ return site_instance_.get();
+ }
+ virtual Profile* GetProfile() const { return balloon_->profile(); }
+ virtual const GURL& GetURL() const {
+ return balloon_->notification().content_url();
+ }
+ virtual void RequestOpenURL(const GURL& url, const GURL& referrer,
+ WindowOpenDisposition disposition);
+ virtual void RendererReady(RenderViewHost* render_view_host);
+ virtual void RendererGone(RenderViewHost* render_view_host);
+ virtual void UpdateTitle(RenderViewHost* /* render_view_host */,
+ int32 /* page_id */, const std::wstring& title) {
+ title_ = title;
+ }
+ virtual int GetBrowserWindowID() const { return -1; }
+ virtual ViewType::Type GetRenderViewType() const {
+ return ViewType::TAB_CONTENTS;
+ }
+
+ // Accessors.
+ RenderViewHost* render_view_host() const { return render_view_host_; }
+ const std::wstring& title() const { return title_; }
+
+ private:
+ // View overrides.
+ virtual void ViewHierarchyChanged(bool is_add,
+ views::View *parent,
+ views::View *child);
+
+ // Initialize the view, parented to |parent|, and show it.
+ void Init(gfx::NativeView parent);
+
+ // True after Init() has completed.
+ bool initialized_;
+
+ // Non-owned pointer to the associated balloon.
+ Balloon* balloon_;
+
+ // Site instance for the balloon/profile, to be used for opening new links.
+ scoped_refptr<SiteInstance> site_instance_;
+
+ // Owned pointer to to host for the renderer process.
+ RenderViewHost* render_view_host_;
+
+ // Indicates whether we should notify about disconnection of this balloon.
+ // This is used to ensure disconnection notifications only happen if
+ // a connection notification has happened and that they happen only once.
+ bool should_notify_on_disconnect_;
+
+ // The title of the balloon page.
+ std::wstring title_;
+
+ DISALLOW_COPY_AND_ASSIGN(BalloonViewHost);
+};
+
+#endif // CHROME_BROWSER_VIEWS_NOTIFICATIONS_BALLOON_VIEW_HOST_H_
diff --git a/chrome/browser/views/notifications/balloon_view_host_gtk.cc b/chrome/browser/views/notifications/balloon_view_host_gtk.cc
new file mode 100644
index 0000000..f3477f4
--- /dev/null
+++ b/chrome/browser/views/notifications/balloon_view_host_gtk.cc
@@ -0,0 +1,12 @@
+// 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/views/notifications/balloon_view_host.h"
+
+#include "base/logging.h"
+
+BalloonViewHost::BalloonViewHost(Balloon* balloon) {
+ // TODO(johnnyg): http://crbug.com/23954
+ NOTIMPLEMENTED();
+}