diff options
author | johnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-29 17:51:36 +0000 |
---|---|---|
committer | johnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-29 17:51:36 +0000 |
commit | c8173315b15ccf58d8062900fd25eebfd56eb327 (patch) | |
tree | a73c01e3f081369ec15cc91fefb80b2baf8eb94f /chrome/browser | |
parent | 276aa6a60396329c7fb4a988bd0be7f7d0895651 (diff) | |
download | chromium_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.cc | 43 | ||||
-rw-r--r-- | chrome/browser/notifications/balloon.h | 91 | ||||
-rw-r--r-- | chrome/browser/notifications/balloon_collection.cc | 172 | ||||
-rw-r--r-- | chrome/browser/notifications/balloon_collection.h | 151 | ||||
-rw-r--r-- | chrome/browser/notifications/balloon_collection_linux.cc | 21 | ||||
-rw-r--r-- | chrome/browser/notifications/balloon_collection_mac.mm | 22 | ||||
-rw-r--r-- | chrome/browser/notifications/balloon_collection_win.cc | 54 | ||||
-rw-r--r-- | chrome/browser/notifications/balloons.h | 200 | ||||
-rw-r--r-- | chrome/browser/views/notifications/balloon_view.cc | 354 | ||||
-rw-r--r-- | chrome/browser/views/notifications/balloon_view.h | 134 | ||||
-rw-r--r-- | chrome/browser/views/notifications/balloon_view_host.cc | 107 | ||||
-rw-r--r-- | chrome/browser/views/notifications/balloon_view_host.h | 92 | ||||
-rw-r--r-- | chrome/browser/views/notifications/balloon_view_host_gtk.cc | 12 |
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(); +} |