summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjohnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-15 23:58:34 +0000
committerjohnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-15 23:58:34 +0000
commitbfc815fb1b153c83822a60cce82792caaea80231 (patch)
tree7c47150d804d718753349ea0c21a02e8a300c685
parent3f21aecc705b7cd278794d86d338b9c5086be619 (diff)
downloadchromium_src-bfc815fb1b153c83822a60cce82792caaea80231.zip
chromium_src-bfc815fb1b153c83822a60cce82792caaea80231.tar.gz
chromium_src-bfc815fb1b153c83822a60cce82792caaea80231.tar.bz2
Port notifications to linux. BalloonView and BalloonViewHost should be equivalent to their counterparts under browser/views/notifications; CL also enables the exposure of notifications in WebKit on linux platform.
BUG=23954 TEST=none Review URL: http://codereview.chromium.org/525050 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36434 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/gtk/notifications/balloon_view_gtk.cc374
-rw-r--r--chrome/browser/gtk/notifications/balloon_view_gtk.h156
-rw-r--r--chrome/browser/gtk/notifications/balloon_view_host_gtk.cc143
-rw-r--r--chrome/browser/gtk/notifications/balloon_view_host_gtk.h133
-rw-r--r--chrome/browser/gtk/notifications/notification_options_menu_model.cc85
-rw-r--r--chrome/browser/gtk/notifications/notification_options_menu_model.h42
-rwxr-xr-xchrome/chrome_browser.gypi6
-rw-r--r--chrome/renderer/render_thread.cc4
8 files changed, 941 insertions, 2 deletions
diff --git a/chrome/browser/gtk/notifications/balloon_view_gtk.cc b/chrome/browser/gtk/notifications/balloon_view_gtk.cc
new file mode 100644
index 0000000..fb2d436
--- /dev/null
+++ b/chrome/browser/gtk/notifications/balloon_view_gtk.cc
@@ -0,0 +1,374 @@
+// Copyright (c) 2010 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/gtk/notifications/balloon_view_gtk.h"
+
+#include <string>
+#include <vector>
+
+#include "app/gfx/canvas.h"
+#include "app/gfx/insets.h"
+#include "app/gfx/native_widget_types.h"
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "app/slide_animation.h"
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "chrome/browser/browser_theme_provider.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_window.h"
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/gtk/gtk_chrome_button.h"
+#include "chrome/browser/gtk/gtk_theme_provider.h"
+#include "chrome/browser/gtk/info_bubble_gtk.h"
+#include "chrome/browser/gtk/menu_gtk.h"
+#include "chrome/browser/gtk/nine_box.h"
+#include "chrome/browser/gtk/notifications/balloon_view_host_gtk.h"
+#include "chrome/browser/gtk/notifications/notification_options_menu_model.h"
+#include "chrome/browser/notifications/balloon.h"
+#include "chrome/browser/notifications/desktop_notification_service.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"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/gtk_util.h"
+#include "chrome/common/notification_details.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_source.h"
+#include "chrome/common/notification_type.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+
+namespace {
+
+// Margin, in pixels, between the notification frame and the contents
+// of the notification.
+const int kTopMargin = 1;
+const int kBottomMargin = 1;
+const int kLeftMargin = 1;
+const int kRightMargin = 1;
+
+// How many pixels of overlap there is between the shelf top and the
+// balloon bottom.
+const int kShelfBorderTopOverlap = 3;
+
+// Properties of the dismiss button.
+const int kDismissButtonWidth = 60;
+const int kDismissButtonHeight = 20;
+
+// Properties of the options menu.
+const int kOptionsMenuWidth = 60;
+const int kOptionsMenuHeight = 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;
+
+// Space in pixels between text and icon on the buttons.
+const int kButtonIconSpacing = 3;
+
+// Number of characters to show in the origin label before ellipsis.
+const int kOriginLabelCharacters = 18;
+
+// The shelf height for the system default font size. It is scaled
+// with changes in the default font size.
+const int kDefaultShelfHeight = 24;
+
+} // namespace
+
+BalloonViewImpl::BalloonViewImpl()
+ : balloon_(NULL),
+ frame_container_(NULL),
+ html_container_(NULL),
+ html_contents_(NULL),
+ method_factory_(this),
+ close_button_(NULL),
+ animation_(NULL) {
+ // Load the sprites for the frames.
+ // Insets are such because the sprites have 3x3 corners.
+ shelf_background_.reset(new NineBox(IDR_BALLOON_SHELF, 3, 3, 3, 3));
+ balloon_background_.reset(new NineBox(IDR_BALLOON_BORDER, 3, 3, 3, 3));
+}
+
+BalloonViewImpl::~BalloonViewImpl() {
+}
+
+void BalloonViewImpl::Close(bool by_user) {
+ MessageLoop::current()->PostTask(FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &BalloonViewImpl::DelayedClose, by_user));
+}
+
+gfx::Size BalloonViewImpl::GetSize() const {
+ // BalloonView has no size if it hasn't been shown yet (which is when
+ // balloon_ is set).
+ if (!balloon_)
+ return gfx::Size();
+
+ // Although this may not be the instantaneous size of the balloon if
+ // called in the middle of an animation, it is the effective size that
+ // will result from the animation.
+ return gfx::Size(GetDesiredTotalWidth(), GetDesiredTotalHeight());
+}
+
+void BalloonViewImpl::DelayedClose(bool by_user) {
+ html_contents_->Shutdown();
+ gtk_widget_hide(frame_container_);
+ balloon_->OnClose(by_user);
+}
+
+void BalloonViewImpl::InitToolbarStyle() {
+ // This only needs to happen once.
+ static bool initialized = false;
+ if (!initialized) {
+ gtk_rc_parse_string(
+ "style \"chrome-notification-toolbar\" {"
+ " xthickness = 0\n"
+ " ythickness = 0\n"
+ " GtkWidget::focus-padding = 0\n"
+ " GtkContainer::border-width = 0\n"
+ " GtkToolBar::internal-padding = 2\n"
+ " GtkToolBar::shadow-type = GTK_SHADOW_NONE\n"
+ "}\n"
+ "widget \"*chrome-notification-toolbar\""
+ "style \"chrome-notification-toolbar\"");
+ initialized = true;
+ }
+}
+
+void BalloonViewImpl::RepositionToBalloon() {
+ DCHECK(frame_container_);
+ DCHECK(balloon_);
+
+ // Create an amination from the current position to the desired one.
+ int start_x;
+ int start_y;
+ int start_w;
+ int start_h;
+ gtk_window_get_position(GTK_WINDOW(frame_container_), &start_x, &start_y);
+ gtk_window_get_size(GTK_WINDOW(frame_container_), &start_w, &start_h);
+
+ int end_x = balloon_->position().x();
+ int end_y = balloon_->position().y();
+ int end_w = GetDesiredTotalWidth();
+ int end_h = GetDesiredTotalHeight();
+
+ anim_frame_start_ = gfx::Rect(start_x, start_y, start_w, start_h);
+ anim_frame_end_ = gfx::Rect(end_x, end_y, end_w, end_h);
+ animation_.reset(new SlideAnimation(this));
+ animation_->Show();
+}
+
+void BalloonViewImpl::AnimationProgressed(const Animation* animation) {
+ DCHECK_EQ(animation, animation_.get());
+
+ // Linear interpolation from start to end position.
+ double end = animation->GetCurrentValue();
+ double start = 1.0 - end;
+
+ gfx::Rect frame_position(
+ static_cast<int>(start * anim_frame_start_.x() +
+ end * anim_frame_end_.x()),
+ static_cast<int>(start * anim_frame_start_.y() +
+ end * anim_frame_end_.y()),
+ static_cast<int>(start * anim_frame_start_.width() +
+ end * anim_frame_end_.width()),
+ static_cast<int>(start * anim_frame_start_.height() +
+ end * anim_frame_end_.height()));
+ gtk_window_resize(GTK_WINDOW(frame_container_),
+ frame_position.width(), frame_position.height());
+ gtk_window_move(GTK_WINDOW(frame_container_),
+ frame_position.x(), frame_position.y());
+
+ gfx::Rect contents_rect = GetContentsRectangle();
+ html_contents_->UpdateActualSize(contents_rect.size());
+}
+
+void PrepareButtonWithIcon(GtkWidget* button,
+ const std::string& text_utf8, int icon_id) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ GdkPixbuf* pixbuf = rb.GetPixbufNamed(icon_id);
+ GtkWidget* image = gtk_image_new_from_pixbuf(pixbuf);
+ g_object_unref(pixbuf);
+
+ GtkWidget* box = gtk_hbox_new(FALSE, kButtonIconSpacing);
+
+ GtkWidget* label = gtk_label_new(text_utf8.c_str());
+ gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0);
+
+ GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 1, 1, 1, 1);
+ gtk_container_add(GTK_CONTAINER(alignment), box);
+ gtk_container_add(GTK_CONTAINER(button), alignment);
+
+ gtk_widget_show_all(alignment);
+}
+
+void BalloonViewImpl::Show(Balloon* balloon) {
+ GtkThemeProvider* theme_provider = GtkThemeProvider::GetFrom(
+ balloon->profile());
+
+ const std::string source_label_text = l10n_util::GetStringFUTF8(
+ IDS_NOTIFICATION_BALLOON_SOURCE_LABEL,
+ WideToUTF16(balloon->notification().display_source()));
+ const std::string options_text =
+ l10n_util::GetStringUTF8(IDS_NOTIFICATION_OPTIONS_MENU_LABEL);
+ const std::string dismiss_text =
+ l10n_util::GetStringUTF8(IDS_NOTIFICATION_BALLOON_DISMISS_LABEL);
+
+ balloon_ = balloon;
+ frame_container_ = gtk_window_new(GTK_WINDOW_POPUP);
+
+ // Construct the options menu.
+ options_menu_model_.reset(new NotificationOptionsMenuModel(balloon_));
+ options_menu_.reset(new MenuGtk(this, options_menu_model_.get()));
+
+ // Create a BalloonViewHost to host the HTML contents of this balloon.
+ html_contents_ = new BalloonViewHost(balloon);
+ html_contents_->Init();
+ gfx::NativeView contents = html_contents_->native_view();
+
+ gtk_widget_set_app_paintable(frame_container_, TRUE);
+ gtk_widget_realize(frame_container_);
+
+ // Divide the frame vertically into the content area and the shelf.
+ GtkWidget* vbox = gtk_vbox_new(0, 0);
+ gtk_container_add(GTK_CONTAINER(frame_container_), vbox);
+
+ GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
+ gtk_alignment_set_padding(
+ GTK_ALIGNMENT(alignment),
+ kTopMargin, kBottomMargin, kLeftMargin, kRightMargin);
+ gtk_widget_show_all(alignment);
+ gtk_container_add(GTK_CONTAINER(alignment), contents);
+ gtk_container_add(GTK_CONTAINER(vbox), alignment);
+
+ shelf_ = gtk_hbox_new(0, 0);
+ GtkWidget* alignment2 = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(alignment2), 0, 0, 10, 0);
+ gtk_container_add(GTK_CONTAINER(vbox), shelf_);
+
+ // Create a toolbar and add it to the shelf.
+ toolbar_ = gtk_toolbar_new();
+ gtk_widget_set_name(toolbar_, "chrome-notification-toolbar");
+ gtk_util::SuppressDefaultPainting(toolbar_);
+ gtk_widget_set_size_request(GTK_WIDGET(toolbar_), -1, GetShelfHeight());
+ gtk_container_add(GTK_CONTAINER(alignment2), toolbar_);
+ gtk_container_add(GTK_CONTAINER(shelf_), alignment2);
+ gtk_widget_show_all(vbox);
+
+ InitToolbarStyle();
+
+ g_signal_connect(frame_container_, "expose-event",
+ G_CALLBACK(HandleExposeThunk), this);
+
+ // Create a label for the source of the notification and add it to the
+ // toolbar.
+ GtkWidget* source_label_ = gtk_label_new(source_label_text.c_str());
+ gtk_label_set_max_width_chars(GTK_LABEL(source_label_),
+ kOriginLabelCharacters);
+ gtk_label_set_ellipsize(GTK_LABEL(source_label_), PANGO_ELLIPSIZE_END);
+ GtkToolItem* label_toolitem = gtk_tool_item_new();
+ gtk_container_add(GTK_CONTAINER(label_toolitem), source_label_);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar_), label_toolitem, 0);
+ gtk_widget_show_all(GTK_WIDGET(label_toolitem));
+
+ // Create a button for showing the options menu, and add it to the toolbar.
+ options_menu_button_ = theme_provider->BuildChromeButton();
+ g_signal_connect(G_OBJECT(options_menu_button_), "clicked",
+ G_CALLBACK(HandleOptionsMenuButtonThunk), this);
+ PrepareButtonWithIcon(options_menu_button_, options_text,
+ IDR_BALLOON_OPTIONS_ARROW_HOVER);
+ GtkToolItem* options_menu_toolitem = gtk_tool_item_new();
+ gtk_container_add(GTK_CONTAINER(options_menu_toolitem), options_menu_button_);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar_), options_menu_toolitem, 1);
+ gtk_widget_show_all(GTK_WIDGET(options_menu_toolitem));
+
+ // Create a button to dismiss the balloon and add it to the toolbar.
+ close_button_ = theme_provider->BuildChromeButton();
+ g_signal_connect(G_OBJECT(close_button_), "clicked",
+ G_CALLBACK(HandleCloseButtonThunk), this);
+ PrepareButtonWithIcon(close_button_, dismiss_text, IDR_BALLOON_CLOSE_HOVER);
+ GtkToolItem* close_button_toolitem = gtk_tool_item_new();
+ gtk_container_add(GTK_CONTAINER(close_button_toolitem), close_button_);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar_), close_button_toolitem, 2);
+ gtk_widget_show_all(GTK_WIDGET(close_button_toolitem));
+
+ // Position the view elements according to the balloon position and show.
+ RepositionToBalloon();
+ gtk_widget_show(frame_container_);
+
+ notification_registrar_.Add(this,
+ NotificationType::NOTIFY_BALLOON_DISCONNECTED, Source<Balloon>(balloon));
+}
+
+void BalloonViewImpl::RunOptionsMenu() {
+ options_menu_->PopupAsContext(gtk_get_current_event_time());
+}
+
+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::GetBalloonFrameHeight() const {
+ return GetDesiredTotalHeight() - GetShelfHeight();
+}
+
+int BalloonViewImpl::GetDesiredTotalWidth() const {
+ return balloon_->content_size().width() +
+ kLeftMargin + kRightMargin + kLeftShadowWidth + kRightShadowWidth;
+}
+
+int BalloonViewImpl::GetDesiredTotalHeight() const {
+ return balloon_->content_size().height() +
+ kTopMargin + kBottomMargin + kTopShadowWidth + kBottomShadowWidth +
+ GetShelfHeight();
+}
+
+gfx::Rect BalloonViewImpl::GetContentsRectangle() const {
+ if (!frame_container_)
+ return gfx::Rect();
+
+ gfx::Size content_size = balloon_->content_size();
+ gfx::Point offset = GetContentsOffset();
+ int x = 0, y = 0;
+ gtk_window_get_position(GTK_WINDOW(frame_container_), &x, &y);
+ return gfx::Rect(x + offset.x(), y + offset.y(),
+ content_size.width(), content_size.height());
+}
+
+gboolean BalloonViewImpl::HandleExpose() {
+ // Draw the background images.
+ balloon_background_->RenderToWidget(frame_container_);
+ shelf_background_->RenderToWidget(shelf_);
+ return FALSE;
+}
+
+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(false);
+}
diff --git a/chrome/browser/gtk/notifications/balloon_view_gtk.h b/chrome/browser/gtk/notifications/balloon_view_gtk.h
new file mode 100644
index 0000000..b0cf8ed
--- /dev/null
+++ b/chrome/browser/gtk/notifications/balloon_view_gtk.h
@@ -0,0 +1,156 @@
+// Copyright (c) 2010 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_GTK_NOTIFICATIONS_BALLOON_VIEW_GTK_H_
+#define CHROME_BROWSER_GTK_NOTIFICATIONS_BALLOON_VIEW_GTK_H_
+
+#include "app/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 "chrome/browser/gtk/menu_gtk.h"
+#include "chrome/browser/notifications/balloon.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+
+class BalloonViewHost;
+class MenuGtk;
+class NineBox;
+class NotificationDetails;
+class NotificationOptionsMenuModel;
+class NotificationSource;
+class SlideAnimation;
+
+// A balloon view is the UI component for desktop notification toasts.
+// It draws a border, and within the border an HTML renderer.
+class BalloonViewImpl : public BalloonView,
+ public MenuGtk::Delegate,
+ public NotificationObserver,
+ public AnimationDelegate {
+ public:
+ BalloonViewImpl();
+ ~BalloonViewImpl();
+
+ // BalloonView interface.
+ virtual void Show(Balloon* balloon);
+ virtual void RepositionToBalloon();
+ virtual void Close(bool by_user);
+ virtual gfx::Size GetSize() const;
+
+ private:
+ // MenuGtk::Delegate interface. These methods shouldn't actually be
+ // called because we are using a MenuModel which handles these callbacks.
+ virtual bool IsCommandEnabled(int command_id) const {
+ NOTIMPLEMENTED();
+ return true;
+ }
+ virtual void ExecuteCommand(int command_id) {
+ NOTIMPLEMENTED();
+ }
+
+ // Initializes the toolbar style with GTK.
+ void InitToolbarStyle();
+
+ // NotificationObserver interface.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // AnimationDelegate interface.
+ virtual void AnimationProgressed(const Animation* animation);
+
+ // Launches the options menu.
+ void RunOptionsMenu();
+
+ // Adjust the contents window size to be appropriate for the frame.
+ void SizeContentsWindow();
+
+ // Do the delayed close work.
+ void DelayedClose(bool by_user);
+
+ // The height of the balloon's shelf.
+ // The shelf is where is close button is located.
+ int GetShelfHeight() const;
+
+ // The height of the part of the frame around the balloon.
+ int GetBalloonFrameHeight() const;
+
+ // The width and height that the frame should be. If the balloon inside
+ // changes size, this will not be the same as the actual frame size until
+ // RepositionToBalloon() has been called and the animation completes.
+ int GetDesiredTotalWidth() const;
+ int GetDesiredTotalHeight() 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;
+
+ static gboolean HandleExposeThunk(GtkWidget* widget,
+ GdkEventExpose* event,
+ gpointer user_data) {
+ return reinterpret_cast<BalloonViewImpl*>(user_data)->HandleExpose();
+ }
+ gboolean HandleExpose();
+
+ static void HandleCloseButtonThunk(GtkWidget* widget, gpointer user_data) {
+ reinterpret_cast<BalloonViewImpl*>(user_data)->Close(true);
+ }
+
+ static void HandleOptionsMenuButtonThunk(GtkWidget* widget,
+ gpointer user_data) {
+ reinterpret_cast<BalloonViewImpl*>(user_data)->RunOptionsMenu();
+ }
+
+ // Non-owned pointer to the balloon which owns this object.
+ Balloon* balloon_;
+
+ // The window that contains the frame of the notification.
+ GtkWidget* frame_container_;
+
+ // The widget that contains the shelf.
+ GtkWidget* shelf_;
+
+ // The toolbar widget within the shelf that contains the buttons.
+ GtkWidget* toolbar_;
+
+ // The window that contains the contents of the notification.
+ GtkWidget* 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<NineBox> shelf_background_;
+ scoped_ptr<NineBox> balloon_background_;
+
+ // Pointer to sub-view is owned by the View sub-class.
+ GtkWidget* close_button_;
+
+ // 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_;
+
+ // The options menu.
+ scoped_ptr<MenuGtk> options_menu_;
+ scoped_ptr<NotificationOptionsMenuModel> options_menu_model_;
+ GtkWidget* options_menu_button_;
+
+ NotificationRegistrar notification_registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(BalloonViewImpl);
+};
+
+#endif // CHROME_BROWSER_GTK_NOTIFICATIONS_BALLOON_VIEW_GTK_H_
diff --git a/chrome/browser/gtk/notifications/balloon_view_host_gtk.cc b/chrome/browser/gtk/notifications/balloon_view_host_gtk.cc
new file mode 100644
index 0000000..d80b202
--- /dev/null
+++ b/chrome/browser/gtk/notifications/balloon_view_host_gtk.cc
@@ -0,0 +1,143 @@
+// Copyright (c) 2010 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/gtk/notifications/balloon_view_host_gtk.h"
+
+#include "base/string_util.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/in_process_webkit/dom_storage_context.h"
+#include "chrome/browser/in_process_webkit/webkit_context.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"
+#include "chrome/browser/renderer_host/render_widget_host_view_gtk.h"
+#include "chrome/browser/renderer_host/site_instance.h"
+#include "chrome/browser/renderer_preferences_util.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_type.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/common/renderer_preferences.h"
+
+BalloonViewHost::BalloonViewHost(Balloon* balloon)
+ : initialized_(false),
+ balloon_(balloon),
+ site_instance_(SiteInstance::CreateSiteInstance(balloon->profile())),
+ render_view_host_(NULL),
+ should_notify_on_disconnect_(false) {
+ DCHECK(balloon_);
+}
+
+void BalloonViewHost::Shutdown() {
+ if (render_view_host_) {
+ render_view_host_->Shutdown();
+ render_view_host_ = NULL;
+ }
+}
+
+WebPreferences BalloonViewHost::GetWebkitPrefs() {
+ WebPreferences prefs;
+ prefs.allow_scripts_to_close_windows = true;
+ return prefs;
+}
+
+RendererPreferences BalloonViewHost::GetRendererPrefs(Profile* profile) const {
+ RendererPreferences prefs;
+ renderer_preferences_util::UpdateFromSystemSettings(&prefs, profile);
+ // 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.
+ 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.
+ // TODO(johnnyg): this new tab should always be in the same workspace as the
+ // notification.
+ BrowserList::GetLastActive()->AddTabWithURL(url, referrer,
+ PageTransition::LINK, true, 0, 0, GetSiteInstance());
+}
+
+void BalloonViewHost::Close(RenderViewHost* render_view_host) {
+ balloon_->CloseByScript();
+}
+
+void BalloonViewHost::RenderViewCreated(RenderViewHost* render_view_host) {
+ render_view_host->Send(new ViewMsg_EnablePreferredSizeChangedMode(
+ render_view_host->routing_id()));
+}
+
+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());
+}
+
+// RenderViewHostDelegate::View methods implemented to allow links to
+// open pages in new tabs.
+void BalloonViewHost::CreateNewWindow(int route_id) {
+ delegate_view_helper_.CreateNewWindow(
+ route_id, balloon_->profile(), site_instance_.get(),
+ DOMUIFactory::GetDOMUIType(balloon_->notification().content_url()), NULL);
+}
+
+void BalloonViewHost::ShowCreatedWindow(int route_id,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_pos,
+ bool user_gesture,
+ const GURL& creator_url) {
+ // Don't allow pop-ups from notifications.
+ if (disposition == NEW_POPUP)
+ return;
+
+ TabContents* contents = delegate_view_helper_.GetCreatedWindow(route_id);
+ if (contents) {
+ Browser* browser = BrowserList::GetLastActive();
+ browser->AddTabContents(contents, disposition, initial_pos, user_gesture);
+ }
+}
+
+void BalloonViewHost::UpdatePreferredSize(const gfx::Size& new_size) {
+ balloon_->SetContentPreferredSize(new_size);
+}
+
+void BalloonViewHost::UpdateActualSize(const gfx::Size& new_size) {
+ render_widget_host_view_->SetSize(new_size);
+ // gfx::Size(new_size.width(), new_size.height()));
+ gtk_widget_set_size_request(
+ native_view(), new_size.width(), new_size.height());
+}
+
+void BalloonViewHost::Init() {
+ DCHECK(!render_view_host_) << "BalloonViewHost already initialized.";
+
+ int64 session_storage_namespace_id = balloon_->profile()->GetWebKitContext()->
+ dom_storage_context()->AllocateSessionStorageNamespaceId();
+
+ render_view_host_ = new RenderViewHost(site_instance_.get(),
+ this, MSG_ROUTING_NONE,
+ session_storage_namespace_id);
+
+ render_widget_host_view_ = new RenderWidgetHostViewGtk(render_view_host_);
+ render_widget_host_view_->InitAsChild();
+
+ render_view_host_->set_view(render_widget_host_view_);
+ render_view_host_->CreateRenderView(GetProfile()->GetRequestContext());
+ render_view_host_->NavigateToURL(balloon_->notification().content_url());
+ initialized_ = true;
+}
diff --git a/chrome/browser/gtk/notifications/balloon_view_host_gtk.h b/chrome/browser/gtk/notifications/balloon_view_host_gtk.h
new file mode 100644
index 0000000..957ef97
--- /dev/null
+++ b/chrome/browser/gtk/notifications/balloon_view_host_gtk.h
@@ -0,0 +1,133 @@
+// Copyright (c) 2010 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_GTK_NOTIFICATIONS_BALLOON_VIEW_HOST_GTK_H_
+#define CHROME_BROWSER_GTK_NOTIFICATIONS_BALLOON_VIEW_HOST_GTK_H_
+
+#include "app/gfx/native_widget_types.h"
+#include "chrome/browser/gtk/extension_view_gtk.h"
+#include "chrome/browser/notifications/balloon.h"
+#include "chrome/browser/renderer_host/render_view_host_delegate.h"
+#include "chrome/browser/renderer_host/render_widget_host_view_gtk.h"
+#include "chrome/browser/renderer_host/site_instance.h"
+#include "chrome/browser/tab_contents/render_view_host_delegate_helper.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 RenderViewHostDelegate,
+ public RenderViewHostDelegate::View {
+ public:
+ explicit BalloonViewHost(Balloon* balloon);
+
+ ~BalloonViewHost() {
+ Shutdown();
+ }
+
+ // Initialize the view.
+ void Init();
+
+ // Stops showing the balloon.
+ void Shutdown();
+
+ // RenderViewHostDelegate overrides.
+ virtual WebPreferences GetWebkitPrefs();
+ virtual RendererPreferences GetRendererPrefs(Profile* profile) 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 Close(RenderViewHost* render_view_host);
+ virtual void RenderViewCreated(RenderViewHost* render_view_host);
+ virtual void DidStopLoading() {}
+ 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;
+ }
+ virtual RenderViewHostDelegate::View* GetViewDelegate() {
+ return this;
+ }
+
+ void UpdateActualSize(const gfx::Size& new_size);
+
+ // RenderViewHostDelegate::View methods. Only the ones for opening new
+ // windows are currently implemented.
+ virtual void CreateNewWindow(int route_id);
+ virtual void CreateNewWidget(int route_id, bool activatable) {}
+ virtual void ShowCreatedWindow(int route_id,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_pos,
+ bool user_gesture,
+ const GURL& creator_url);
+ virtual void ShowCreatedWidget(int route_id,
+ const gfx::Rect& initial_pos) {}
+ virtual void ShowContextMenu(const ContextMenuParams& params) {}
+ virtual void StartDragging(const WebDropData& drop_data,
+ WebKit::WebDragOperationsMask allowed_ops) {}
+ virtual void UpdateDragCursor(WebKit::WebDragOperation operation) {}
+ virtual void GotFocus() {}
+ virtual void TakeFocus(bool reverse) {}
+ virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
+ bool* is_keyboard_shortcut) {
+ return false;
+ }
+ virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {}
+ virtual void HandleMouseEvent() {}
+ virtual void HandleMouseLeave() {}
+ virtual void UpdatePreferredSize(const gfx::Size& pref_size);
+
+ // Accessors.
+ RenderViewHost* render_view_host() const { return render_view_host_; }
+ gfx::NativeView native_view() const {
+ return render_widget_host_view_->native_view();
+ }
+ const std::wstring& title() const { return title_; }
+
+ private:
+ // 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_;
+
+ // The GTK-specific widget host view.
+ RenderWidgetHostViewGtk* render_widget_host_view_;
+
+ // Common implementations of some RenderViewHostDelegate::View methods.
+ RenderViewHostDelegateViewHelper delegate_view_helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(BalloonViewHost);
+};
+
+#endif // CHROME_BROWSER_GTK_NOTIFICATIONS_BALLOON_VIEW_HOST_GTK_H_
diff --git a/chrome/browser/gtk/notifications/notification_options_menu_model.cc b/chrome/browser/gtk/notifications/notification_options_menu_model.cc
new file mode 100644
index 0000000..0cbb81e
--- /dev/null
+++ b/chrome/browser/gtk/notifications/notification_options_menu_model.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2010 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 "app/l10n_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/gtk/notifications/notification_options_menu_model.h"
+#include "chrome/browser/notifications/balloon.h"
+#include "chrome/browser/notifications/desktop_notification_service.h"
+#include "chrome/browser/profile.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+
+using menus::MenuModel;
+
+NotificationOptionsMenuModel::NotificationOptionsMenuModel(Balloon* balloon)
+ : balloon_(balloon) {
+}
+
+NotificationOptionsMenuModel::~NotificationOptionsMenuModel() {
+}
+
+bool NotificationOptionsMenuModel::HasIcons() const {
+ return false;
+}
+
+int NotificationOptionsMenuModel::GetItemCount() const {
+ return 1;
+}
+
+MenuModel::ItemType NotificationOptionsMenuModel::GetTypeAt(int index) const {
+ return MenuModel::TYPE_COMMAND;
+}
+
+int NotificationOptionsMenuModel::GetCommandIdAt(int index) const {
+ return index;
+}
+
+string16 NotificationOptionsMenuModel::GetLabelAt(int index) const {
+ DCHECK_EQ(0, index);
+
+ return l10n_util::GetStringFUTF16(IDS_NOTIFICATION_BALLOON_REVOKE_MESSAGE,
+ WideToUTF16(balloon_->notification().display_source()));
+}
+
+bool NotificationOptionsMenuModel::IsLabelDynamicAt(int index) const {
+ return false;
+}
+
+bool NotificationOptionsMenuModel::GetAcceleratorAt(
+ int index, menus::Accelerator* accelerator) const {
+ return false;
+}
+
+bool NotificationOptionsMenuModel::IsItemCheckedAt(int index) const {
+ return false;
+}
+
+int NotificationOptionsMenuModel::GetGroupIdAt(int index) const {
+ return 0;
+}
+
+bool NotificationOptionsMenuModel::GetIconAt(int index, SkBitmap* icon) const {
+ return false;
+}
+
+bool NotificationOptionsMenuModel::IsEnabledAt(int index) const {
+ return true;
+}
+
+MenuModel* NotificationOptionsMenuModel::GetSubmenuModelAt(int index) const {
+ return NULL;
+}
+
+void NotificationOptionsMenuModel::HighlightChangedTo(int index) {
+}
+
+void NotificationOptionsMenuModel::ActivatedAt(int index) {
+ DCHECK_EQ(0, index);
+
+ DesktopNotificationService* service =
+ balloon_->profile()->GetDesktopNotificationService();
+
+ service->DenyPermission(balloon_->notification().origin_url());
+}
diff --git a/chrome/browser/gtk/notifications/notification_options_menu_model.h b/chrome/browser/gtk/notifications/notification_options_menu_model.h
new file mode 100644
index 0000000..f4b67f3
--- /dev/null
+++ b/chrome/browser/gtk/notifications/notification_options_menu_model.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2010 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_GTK_NOTIFICATIONS_NOTIFICATION_OPTIONS_MENU_MODEL_H_
+#define CHROME_BROWSER_GTK_NOTIFICATIONS_NOTIFICATION_OPTIONS_MENU_MODEL_H_
+
+#include "app/menus/menu_model.h"
+
+class Balloon;
+
+// Model for the options menu on the notification balloon.
+class NotificationOptionsMenuModel : public menus::MenuModel {
+ public:
+ explicit NotificationOptionsMenuModel(Balloon* balloon);
+ ~NotificationOptionsMenuModel();
+
+ // menus::MenuModel methods.
+ virtual bool HasIcons() const;
+ virtual int GetItemCount() const;
+ virtual ItemType GetTypeAt(int index) const;
+ virtual int GetCommandIdAt(int index) const;
+ virtual string16 GetLabelAt(int index) const;
+ virtual bool IsLabelDynamicAt(int index) const;
+ virtual bool GetAcceleratorAt(int index,
+ menus::Accelerator* accelerator) const;
+ virtual bool IsItemCheckedAt(int index) const;
+ virtual int GetGroupIdAt(int index) const;
+ virtual bool GetIconAt(int index, SkBitmap* icon) const;
+ virtual bool IsEnabledAt(int index) const;
+ virtual MenuModel* GetSubmenuModelAt(int index) const;
+ virtual void HighlightChangedTo(int index);
+ virtual void ActivatedAt(int index);
+
+ private:
+ // Non-owned pointer to the balloon involved.
+ Balloon* balloon_;
+
+ DISALLOW_COPY_AND_ASSIGN(NotificationOptionsMenuModel);
+};
+
+#endif // CHROME_BROWSER_GTK_NOTIFICATIONS_NOTIFICATION_OPTIONS_MENU_MODEL_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 9cbcc2f..804b539 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -934,6 +934,12 @@
'browser/gtk/menu_gtk.h',
'browser/gtk/nine_box.cc',
'browser/gtk/nine_box.h',
+ 'browser/gtk/notifications/balloon_view_gtk.cc',
+ 'browser/gtk/notifications/balloon_view_gtk.h',
+ 'browser/gtk/notifications/balloon_view_host_gtk.cc',
+ 'browser/gtk/notifications/balloon_view_host_gtk.h',
+ 'browser/gtk/notifications/notification_options_menu_model.cc',
+ 'browser/gtk/notifications/notification_options_menu_model.h',
'browser/gtk/options/advanced_contents_gtk.cc',
'browser/gtk/options/advanced_contents_gtk.h',
'browser/gtk/options/advanced_page_gtk.cc',
diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc
index 657e440..9df544a 100644
--- a/chrome/renderer/render_thread.cc
+++ b/chrome/renderer/render_thread.cc
@@ -617,8 +617,8 @@ void RenderThread::EnsureWebKitInitialized() {
WebRuntimeFeatures::enableApplicationCache(
command_line.HasSwitch(switches::kEnableApplicationCache));
-#if defined(OS_WIN)
- // We don't yet support notifications on non-Windows.
+#if defined(OS_WIN) || defined(OS_LINUX)
+ // Notifications are supported on Windows and Linux only.
WebRuntimeFeatures::enableNotifications(
!command_line.HasSwitch(switches::kDisableDesktopNotifications));
#endif