summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-22 18:00:57 +0000
committerestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-22 18:00:57 +0000
commit854dddc6b0f52545ab1008237630aa5472089080 (patch)
tree125bbb133628fdf6dde3a7ca5fac539b4d02a6b1
parent9912cd8c8bb8e89df4b33ba91c6c533e50132dca (diff)
downloadchromium_src-854dddc6b0f52545ab1008237630aa5472089080.zip
chromium_src-854dddc6b0f52545ab1008237630aa5472089080.tar.gz
chromium_src-854dddc6b0f52545ab1008237630aa5472089080.tar.bz2
GTK: add browser actions popups.
Also add a new notification that tells the popup to close. BUG=23897 TEST=--load-extension=chrome/test/data/extensions/samples/buildbot TEST=--load-extension=chrome/test/data/extensions/samples/set_page_color Review URL: http://codereview.chromium.org/314008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29785 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/extension_host.cc11
-rw-r--r--chrome/browser/gtk/browser_actions_toolbar_gtk.cc13
-rw-r--r--chrome/browser/gtk/extension_popup_gtk.cc95
-rw-r--r--chrome/browser/gtk/extension_popup_gtk.h63
-rw-r--r--chrome/browser/gtk/extension_view_gtk.cc7
-rw-r--r--chrome/browser/gtk/info_bubble_gtk.cc6
-rw-r--r--chrome/browser/views/browser_actions_container.cc7
-rwxr-xr-xchrome/chrome.gyp2
-rw-r--r--chrome/common/notification_type.h7
9 files changed, 198 insertions, 13 deletions
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index 5413cd7..2f76e41 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -341,13 +341,10 @@ void ExtensionHost::RunJavaScriptMessage(const std::wstring& message,
void ExtensionHost::Close(RenderViewHost* render_view_host) {
if (extension_host_type_ == ViewType::EXTENSION_POPUP) {
-#if defined(TOOLKIT_VIEWS)
- // TODO(erikkay) This is a bit of a hack. By hiding the widget, we trigger
- // a deactivation which will then bubble into ExtensionPopup and actually
- // close the popup. Perhaps we should have a more explicit delegate to
- // ExtensionHost.
- view_->GetWidget()->Hide();
-#endif
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
+ Source<Profile>(profile_),
+ Details<ExtensionHost>(this));
}
}
diff --git a/chrome/browser/gtk/browser_actions_toolbar_gtk.cc b/chrome/browser/gtk/browser_actions_toolbar_gtk.cc
index 2e23629..53e27e9 100644
--- a/chrome/browser/gtk/browser_actions_toolbar_gtk.cc
+++ b/chrome/browser/gtk/browser_actions_toolbar_gtk.cc
@@ -13,6 +13,7 @@
#include "chrome/browser/extensions/extension_browser_event_router.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/image_loading_tracker.h"
+#include "chrome/browser/gtk/extension_popup_gtk.h"
#include "chrome/browser/gtk/gtk_chrome_button.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/profile.h"
@@ -117,9 +118,15 @@ class BrowserActionButton : public NotificationObserver,
}
static void OnButtonClicked(GtkWidget* widget, BrowserActionButton* action) {
- ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted(
- action->browser_->profile(), action->extension_->id(),
- action->browser_);
+ if (action->extension_->browser_action()->is_popup()) {
+ ExtensionPopupGtk::Show(action->extension_->browser_action()->popup_url(),
+ action->browser_, gfx::Rect(widget->allocation));
+
+ } else {
+ ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted(
+ action->browser_->profile(), action->extension_->id(),
+ action->browser_);
+ }
}
static gboolean OnExposeEvent(GtkWidget* widget,
diff --git a/chrome/browser/gtk/extension_popup_gtk.cc b/chrome/browser/gtk/extension_popup_gtk.cc
new file mode 100644
index 0000000..7f2a913
--- /dev/null
+++ b/chrome/browser/gtk/extension_popup_gtk.cc
@@ -0,0 +1,95 @@
+// 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/gtk/extension_popup_gtk.h"
+
+#include <gtk/gtk.h>
+
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_window.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/gtk/gtk_theme_provider.h"
+#include "chrome/common/notification_service.h"
+#include "googleurl/src/gurl.h"
+
+ExtensionPopupGtk::ExtensionPopupGtk(Browser* browser,
+ ExtensionHost* host,
+ const gfx::Rect& relative_to)
+ : browser_(browser),
+ bubble_(NULL),
+ host_(host),
+ relative_to_(relative_to) {
+
+ // If the host had somehow finished loading, then we'd miss the notification
+ // and not show. This seems to happen in single-process mode.
+ if (host->did_stop_loading()) {
+ ShowPopup();
+ } else {
+ registrar_.Add(this, NotificationType::EXTENSION_HOST_DID_STOP_LOADING,
+ Source<Profile>(host->profile()));
+ }
+
+ registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
+ Source<Profile>(host->profile()));
+}
+
+ExtensionPopupGtk::~ExtensionPopupGtk() {
+}
+
+void ExtensionPopupGtk::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (Details<ExtensionHost>(host_.get()) != details)
+ return;
+
+ if (type == NotificationType::EXTENSION_HOST_DID_STOP_LOADING) {
+ ShowPopup();
+ } else if (type == NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE) {
+ DestroyPopup();
+ } else {
+ NOTREACHED() << "Received unexpected notification";
+ }
+}
+
+void ExtensionPopupGtk::ShowPopup() {
+ if (bubble_) {
+ NOTREACHED();
+ return;
+ }
+
+ bubble_ = InfoBubbleGtk::Show(browser_->window()->GetNativeHandle(),
+ relative_to_, host_->view()->native_view(),
+ GtkThemeProvider::GetFrom(browser_->profile()),
+ this);
+}
+
+void ExtensionPopupGtk::DestroyPopup() {
+ if (!bubble_) {
+ NOTREACHED();
+ return;
+ }
+
+ bubble_->Close();
+}
+
+void ExtensionPopupGtk::InfoBubbleClosing(InfoBubbleGtk* bubble,
+ bool closed_by_escape) {
+ delete this;
+}
+
+// static
+void ExtensionPopupGtk::Show(const GURL& url, Browser* browser,
+ const gfx::Rect& relative_to) {
+ ExtensionProcessManager* manager =
+ browser->profile()->GetExtensionProcessManager();
+ DCHECK(manager);
+ if (!manager)
+ return;
+
+ ExtensionHost* host = manager->CreatePopup(url, browser);
+ // This object will delete itself when the info bubble is closed.
+ new ExtensionPopupGtk(browser, host, relative_to);
+}
diff --git a/chrome/browser/gtk/extension_popup_gtk.h b/chrome/browser/gtk/extension_popup_gtk.h
new file mode 100644
index 0000000..58578c8
--- /dev/null
+++ b/chrome/browser/gtk/extension_popup_gtk.h
@@ -0,0 +1,63 @@
+// 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_GTK_EXTENSION_POPUP_GTK_H_
+#define CHROME_BROWSER_GTK_EXTENSION_POPUP_GTK_H_
+
+#include "base/gfx/rect.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/gtk/info_bubble_gtk.h"
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+
+class Browser;
+class ExtensionHost;
+class GURL;
+
+class ExtensionPopupGtk : public NotificationObserver,
+ public InfoBubbleGtkDelegate {
+ public:
+ ExtensionPopupGtk(Browser* browser,
+ ExtensionHost* host,
+ const gfx::Rect& relative_to);
+ virtual ~ExtensionPopupGtk();
+
+ static void Show(const GURL& url,
+ Browser* browser,
+ const gfx::Rect& relative_to);
+
+ // NotificationObserver implementation.
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // InfoBubbleGtkDelegate implementation.
+ virtual void InfoBubbleClosing(InfoBubbleGtk* bubble,
+ bool closed_by_escape);
+
+ private:
+ // Shows the popup widget. Called after loading completes.
+ void ShowPopup();
+
+ // Destroys the popup widget. This will in turn destroy us since we delete
+ // ourselves when the info bubble closes.
+ void DestroyPopup();
+
+ Browser* browser_;
+
+ InfoBubbleGtk* bubble_;
+
+ // We take ownership of the popup ExtensionHost.
+ scoped_ptr<ExtensionHost> host_;
+
+ // The rect that we use to position the popup. It is the bounds of the
+ // browser action button.
+ gfx::Rect relative_to_;
+
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionPopupGtk);
+};
+
+#endif // CHROME_BROWSER_GTK_EXTENSION_POPUP_GTK_H_
diff --git a/chrome/browser/gtk/extension_view_gtk.cc b/chrome/browser/gtk/extension_view_gtk.cc
index d7a4fca..fbb8bf0 100644
--- a/chrome/browser/gtk/extension_view_gtk.cc
+++ b/chrome/browser/gtk/extension_view_gtk.cc
@@ -10,7 +10,7 @@
ExtensionViewGtk::ExtensionViewGtk(ExtensionHost* extension_host,
Browser* browser)
- : is_toolstrip_(true),
+ : is_toolstrip_(false),
browser_(browser),
extension_host_(extension_host),
render_widget_host_view_(NULL) {
@@ -37,7 +37,10 @@ void ExtensionViewGtk::SetBackground(const SkBitmap& background) {
}
void ExtensionViewGtk::UpdatePreferredSize(const gfx::Size& new_size) {
- gtk_widget_set_size_request(native_view(), new_size.width(), -1);
+ // If we are showing in a shelf, then the shelf sets our height.
+ int height = is_toolstrip() ? -1 : new_size.height();
+
+ gtk_widget_set_size_request(native_view(), new_size.width(), height);
}
void ExtensionViewGtk::CreateWidgetHostView() {
diff --git a/chrome/browser/gtk/info_bubble_gtk.cc b/chrome/browser/gtk/info_bubble_gtk.cc
index 6ee8e45..1072fb2 100644
--- a/chrome/browser/gtk/info_bubble_gtk.cc
+++ b/chrome/browser/gtk/info_bubble_gtk.cc
@@ -354,6 +354,12 @@ gboolean InfoBubbleGtk::HandleButtonPress(GdkEventButton* event) {
return FALSE; // Propagate.
}
+ // Our content widget got a click.
+ if (event->window != window_->window &&
+ gdk_window_get_toplevel(event->window) == window_->window) {
+ return FALSE;
+ }
+
// Otherwise we had a click outside of our window, close ourself.
Close();
return TRUE;
diff --git a/chrome/browser/views/browser_actions_container.cc b/chrome/browser/views/browser_actions_container.cc
index 52cc137..5dbf6ad 100644
--- a/chrome/browser/views/browser_actions_container.cc
+++ b/chrome/browser/views/browser_actions_container.cc
@@ -225,6 +225,8 @@ BrowserActionsContainer::BrowserActionsContainer(
Source<ExtensionsService>(extension_service));
registrar_.Add(this, NotificationType::EXTENSION_UNLOADED_DISABLED,
Source<ExtensionsService>(extension_service));
+ registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
+ Source<Profile>(profile_));
RefreshBrowserActionViews();
SetID(VIEW_ID_BROWSER_ACTION_TOOLBAR);
@@ -364,6 +366,11 @@ void BrowserActionsContainer::Observe(NotificationType type,
// All these actions may change visibility of BrowserActions.
OnBrowserActionVisibilityChanged();
+ } else if (type == NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE) {
+ if (Details<ExtensionHost>(popup_->host()) != details)
+ return;
+
+ HidePopup();
} else {
NOTREACHED() << L"Received unexpected notification";
}
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index e8ca848..37aab3b 100755
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -1463,6 +1463,8 @@
'browser/gtk/extension_install_prompt_gtk.cc',
'browser/gtk/extension_view_gtk.cc',
'browser/gtk/extension_view_gtk.h',
+ 'browser/gtk/extension_popup_gtk.cc',
+ 'browser/gtk/extension_popup_gtk.h',
'browser/gtk/external_protocol_dialog_gtk.cc',
'browser/gtk/external_protocol_dialog_gtk.h',
'browser/gtk/find_bar_gtk.cc',
diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h
index a6b8eab..fddbeb6 100644
--- a/chrome/common/notification_type.h
+++ b/chrome/common/notification_type.h
@@ -682,10 +682,15 @@ class NotificationType {
// an ExtensionHost* and the source is a Profile*.
EXTENSION_HOST_DESTROYED,
- // Send by an ExtensionHost when it finished its initial page load.
+ // Sent by an ExtensionHost when it finished its initial page load.
// The details are an ExtensionHost* and the source is a Profile*.
EXTENSION_HOST_DID_STOP_LOADING,
+ // Sent by an ExtensionHost when its render view requests closing through
+ // window.close(). The details are an ExtensionHost* and the source is a
+ // Profile*.
+ EXTENSION_HOST_VIEW_SHOULD_CLOSE,
+
// Sent after an extension render process is created and fully functional.
// The details are an ExtensionHost*.
EXTENSION_PROCESS_CREATED,