diff options
author | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-22 18:00:57 +0000 |
---|---|---|
committer | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-22 18:00:57 +0000 |
commit | 854dddc6b0f52545ab1008237630aa5472089080 (patch) | |
tree | 125bbb133628fdf6dde3a7ca5fac539b4d02a6b1 | |
parent | 9912cd8c8bb8e89df4b33ba91c6c533e50132dca (diff) | |
download | chromium_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.cc | 11 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_actions_toolbar_gtk.cc | 13 | ||||
-rw-r--r-- | chrome/browser/gtk/extension_popup_gtk.cc | 95 | ||||
-rw-r--r-- | chrome/browser/gtk/extension_popup_gtk.h | 63 | ||||
-rw-r--r-- | chrome/browser/gtk/extension_view_gtk.cc | 7 | ||||
-rw-r--r-- | chrome/browser/gtk/info_bubble_gtk.cc | 6 | ||||
-rw-r--r-- | chrome/browser/views/browser_actions_container.cc | 7 | ||||
-rwxr-xr-x | chrome/chrome.gyp | 2 | ||||
-rw-r--r-- | chrome/common/notification_type.h | 7 |
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, |