diff options
author | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-07 21:00:33 +0000 |
---|---|---|
committer | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-07 21:00:33 +0000 |
commit | c4d6f87b0cf6ee6d8478a79875700600b049d1df (patch) | |
tree | e3fd77172b81c7d83ac495d96f973881946c7482 /chrome/browser | |
parent | 875f8f9b0757f2029b21cead7822db116ea525e0 (diff) | |
download | chromium_src-c4d6f87b0cf6ee6d8478a79875700600b049d1df.zip chromium_src-c4d6f87b0cf6ee6d8478a79875700600b049d1df.tar.gz chromium_src-c4d6f87b0cf6ee6d8478a79875700600b049d1df.tar.bz2 |
GTK: position info bubbles relative to a subwidget, rather than the toplevel window.
(Client code can still use a toplevel widget as the anchor.)
BUG=40068
TEST=tried all popups in LTR and RTL
Review URL: http://codereview.chromium.org/1575019
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@43876 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/gtk/bookmark_bubble_gtk.cc | 19 | ||||
-rw-r--r-- | chrome/browser/gtk/bookmark_bubble_gtk.h | 15 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_actions_toolbar_gtk.cc | 8 | ||||
-rw-r--r-- | chrome/browser/gtk/content_setting_bubble_gtk.cc (renamed from chrome/browser/gtk/content_blocked_bubble_gtk.cc) | 13 | ||||
-rw-r--r-- | chrome/browser/gtk/content_setting_bubble_gtk.h (renamed from chrome/browser/gtk/content_blocked_bubble_gtk.h) | 18 | ||||
-rw-r--r-- | chrome/browser/gtk/extension_installed_bubble_gtk.cc | 10 | ||||
-rw-r--r-- | chrome/browser/gtk/extension_popup_gtk.cc | 12 | ||||
-rw-r--r-- | chrome/browser/gtk/extension_popup_gtk.h | 9 | ||||
-rw-r--r-- | chrome/browser/gtk/first_run_bubble.cc | 16 | ||||
-rw-r--r-- | chrome/browser/gtk/first_run_bubble.h | 9 | ||||
-rw-r--r-- | chrome/browser/gtk/gtk_util.cc | 25 | ||||
-rw-r--r-- | chrome/browser/gtk/gtk_util.h | 4 | ||||
-rw-r--r-- | chrome/browser/gtk/info_bubble_gtk.cc | 59 | ||||
-rw-r--r-- | chrome/browser/gtk/info_bubble_gtk.h | 19 | ||||
-rw-r--r-- | chrome/browser/gtk/location_bar_view_gtk.cc | 32 |
15 files changed, 138 insertions, 130 deletions
diff --git a/chrome/browser/gtk/bookmark_bubble_gtk.cc b/chrome/browser/gtk/bookmark_bubble_gtk.cc index 90e3849..2bf86e2 100644 --- a/chrome/browser/gtk/bookmark_bubble_gtk.cc +++ b/chrome/browser/gtk/bookmark_bubble_gtk.cc @@ -92,8 +92,7 @@ std::vector<const BookmarkNode*> PopulateFolderCombo(BookmarkModel* model, } // namespace // static -void BookmarkBubbleGtk::Show(GtkWindow* toplevel_window, - const gfx::Rect& rect, +void BookmarkBubbleGtk::Show(GtkWidget* anchor, Profile* profile, const GURL& url, bool newly_bookmarked) { @@ -103,8 +102,7 @@ void BookmarkBubbleGtk::Show(GtkWindow* toplevel_window, // think that closing the previous bubble and opening the new one would make // more sense, but I guess then you would commit the bubble's changes. DCHECK(!g_bubble); - g_bubble = new BookmarkBubbleGtk(toplevel_window, rect, profile, - url, newly_bookmarked); + g_bubble = new BookmarkBubbleGtk(anchor, profile, url, newly_bookmarked); } void BookmarkBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble, @@ -142,15 +140,14 @@ void BookmarkBubbleGtk::Observe(NotificationType type, } } -BookmarkBubbleGtk::BookmarkBubbleGtk(GtkWindow* toplevel_window, - const gfx::Rect& rect, +BookmarkBubbleGtk::BookmarkBubbleGtk(GtkWidget* anchor, Profile* profile, const GURL& url, bool newly_bookmarked) : url_(url), profile_(profile), theme_provider_(GtkThemeProvider::GetFrom(profile_)), - toplevel_window_(toplevel_window), + anchor_(anchor), content_(NULL), name_entry_(NULL), folder_combo_(NULL), @@ -225,8 +222,8 @@ BookmarkBubbleGtk::BookmarkBubbleGtk(GtkWindow* toplevel_window, base::i18n::IsRTL() ? InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT : InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT; - bubble_ = InfoBubbleGtk::Show(toplevel_window_, - rect, + bubble_ = InfoBubbleGtk::Show(anchor_, + NULL, content, arrow_location, true, // match_system_theme @@ -382,9 +379,9 @@ void BookmarkBubbleGtk::ShowEditor() { // Commit any edits now. ApplyEdits(); - // Closing might delete us, so we'll cache what we want we need on the stack. + // Closing might delete us, so we'll cache what we need on the stack. Profile* profile = profile_; - GtkWindow* toplevel = toplevel_window_; + GtkWindow* toplevel = GTK_WINDOW(gtk_widget_get_toplevel(anchor_)); // Close the bubble, deleting the C++ objects, etc. bubble_->Close(); diff --git a/chrome/browser/gtk/bookmark_bubble_gtk.h b/chrome/browser/gtk/bookmark_bubble_gtk.h index 6d26e16..683457d 100644 --- a/chrome/browser/gtk/bookmark_bubble_gtk.h +++ b/chrome/browser/gtk/bookmark_bubble_gtk.h @@ -27,16 +27,12 @@ class BookmarkNode; class Profile; -namespace gfx { -class Rect; -} class BookmarkBubbleGtk : public InfoBubbleGtkDelegate, public NotificationObserver { public: - // Shows the bookmark bubble, pointing at |rect|. - static void Show(GtkWindow* toplevel_window, - const gfx::Rect& rect, + // Shows the bookmark bubble, pointing at |anchor_widget|. + static void Show(GtkWidget* anchor_widget, Profile* profile, const GURL& url, bool newly_bookmarked); @@ -53,8 +49,7 @@ class BookmarkBubbleGtk : public InfoBubbleGtkDelegate, const NotificationDetails& details); private: - BookmarkBubbleGtk(GtkWindow* toplevel_window, - const gfx::Rect& rect, + BookmarkBubbleGtk(GtkWidget* anchor, Profile* profile, const GURL& url, bool newly_bookmarked); @@ -87,8 +82,8 @@ class BookmarkBubbleGtk : public InfoBubbleGtkDelegate, // Provides colors and stuff. GtkThemeProvider* theme_provider_; - // The toplevel window our dialogs should be transient for. - GtkWindow* toplevel_window_; + // The widget relative to which we are positioned. + GtkWidget* anchor_; // We let the InfoBubble own our content, and then we delete ourself // when the widget is destroyed (when the InfoBubble is destroyed). diff --git a/chrome/browser/gtk/browser_actions_toolbar_gtk.cc b/chrome/browser/gtk/browser_actions_toolbar_gtk.cc index 9087793..96a467e 100644 --- a/chrome/browser/gtk/browser_actions_toolbar_gtk.cc +++ b/chrome/browser/gtk/browser_actions_toolbar_gtk.cc @@ -220,10 +220,8 @@ class BrowserActionButton : public NotificationObserver, if (browser_action->HasPopup(tab_id)) { ExtensionPopupGtk::Show( - browser_action->GetPopupUrl(tab_id), - toolbar_->browser(), - gtk_util::GetWidgetRectRelativeToToplevel(widget()), - devtools); + browser_action->GetPopupUrl(tab_id), toolbar_->browser(), + widget(), devtools); return true; } @@ -592,7 +590,7 @@ void BrowserActionsToolbarGtk::ExecuteCommandById(int command_id) { if (browser_action->HasPopup(tab_id)) { ExtensionPopupGtk::Show( browser_action->GetPopupUrl(tab_id), browser(), - gtk_util::GetWidgetRectRelativeToToplevel(overflow_button_.widget()), + overflow_button_.widget(), false); } else { ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted( diff --git a/chrome/browser/gtk/content_blocked_bubble_gtk.cc b/chrome/browser/gtk/content_setting_bubble_gtk.cc index 46f6e6a..05e170e 100644 --- a/chrome/browser/gtk/content_blocked_bubble_gtk.cc +++ b/chrome/browser/gtk/content_setting_bubble_gtk.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/gtk/content_blocked_bubble_gtk.h" +#include "chrome/browser/gtk/content_setting_bubble_gtk.h" #include "app/l10n_util.h" #include "base/i18n/rtl.h" @@ -26,14 +26,12 @@ static const int kContentBorder = 7; ContentSettingBubbleGtk::ContentSettingBubbleGtk( - GtkWindow* toplevel_window, - const gfx::Rect& bounds, + GtkWidget* anchor, InfoBubbleGtkDelegate* delegate, ContentSettingBubbleModel* content_setting_bubble_model, Profile* profile, TabContents* tab_contents) - : toplevel_window_(toplevel_window), - bounds_(bounds), + : anchor_(anchor), profile_(profile), tab_contents_(tab_contents), delegate_(delegate), @@ -210,8 +208,8 @@ void ContentSettingBubbleGtk::BuildBubble() { InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT : InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT; info_bubble_ = InfoBubbleGtk::Show( - toplevel_window_, - bounds_, + anchor_, + NULL, bubble_content, arrow_location, true, // match_system_theme @@ -231,7 +229,6 @@ void ContentSettingBubbleGtk::OnPopupIconButtonPress( // The views interface implicitly closes because of the launching of a new // window; we need to do that explicitly. bubble->Close(); - } // static diff --git a/chrome/browser/gtk/content_blocked_bubble_gtk.h b/chrome/browser/gtk/content_setting_bubble_gtk.h index 9f551f1..813f170 100644 --- a/chrome/browser/gtk/content_blocked_bubble_gtk.h +++ b/chrome/browser/gtk/content_setting_bubble_gtk.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_GTK_CONTENT_BLOCKED_BUBBLE_GTK_H_ -#define CHROME_BROWSER_GTK_CONTENT_BLOCKED_BUBBLE_GTK_H_ +#ifndef CHROME_BROWSER_GTK_CONTENT_SETTING_BUBBLE_GTK_H_ +#define CHROME_BROWSER_GTK_CONTENT_SETTING_BUBBLE_GTK_H_ #include <map> #include <string> @@ -21,13 +21,11 @@ class TabContents; // content blocking (e.g. "block images"). An icon appears in the location bar, // and when clicked, an instance of this class is created specialized for the // type of content being blocked. -// TODO(bulach): rename this file. class ContentSettingBubbleGtk : public InfoBubbleGtkDelegate, public NotificationObserver { public: ContentSettingBubbleGtk( - GtkWindow* toplevel_window, - const gfx::Rect& bounds, + GtkWidget* anchor, InfoBubbleGtkDelegate* delegate, ContentSettingBubbleModel* content_setting_bubble_model, Profile* profile, TabContents* tab_contents); @@ -66,12 +64,8 @@ class ContentSettingBubbleGtk : public InfoBubbleGtkDelegate, static void OnClearLinkClicked(GtkButton* button, ContentSettingBubbleGtk* bubble); - // A reference to the toplevel browser window, which we pass to the - // InfoBubbleGtk implementation so it can tell the WM that it's a subwindow. - GtkWindow* toplevel_window_; - - // Positioning information for the info bubble. - gfx::Rect bounds_; + // We position the bubble near this widget. + GtkWidget* anchor_; // The active profile. Profile* profile_; @@ -99,4 +93,4 @@ class ContentSettingBubbleGtk : public InfoBubbleGtkDelegate, std::vector<RadioGroupGtk> radio_groups_gtk_; }; -#endif // CHROME_BROWSER_GTK_CONTENT_BLOCKED_BUBBLE_GTK_H_ +#endif // CHROME_BROWSER_GTK_CONTENT_SETTING_BUBBLE_GTK_H_ diff --git a/chrome/browser/gtk/extension_installed_bubble_gtk.cc b/chrome/browser/gtk/extension_installed_bubble_gtk.cc index 24b579a..7e208c4 100644 --- a/chrome/browser/gtk/extension_installed_bubble_gtk.cc +++ b/chrome/browser/gtk/extension_installed_bubble_gtk.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. @@ -35,7 +35,7 @@ const int kContentBorder = 7; } // namespace -void ExtensionInstalledBubbleGtk::Show(Extension *extension, Browser *browser, +void ExtensionInstalledBubbleGtk::Show(Extension* extension, Browser* browser, SkBitmap icon) { new ExtensionInstalledBubbleGtk(extension, browser, icon); } @@ -116,8 +116,6 @@ void ExtensionInstalledBubbleGtk::ShowInternal() { if (reference_widget == NULL) reference_widget = browser_window->GetToolbar()->GetAppMenuButton(); - gfx::Rect bounds = gtk_util::GetWidgetRectRelativeToToplevel( - reference_widget); GtkThemeProvider* theme_provider = GtkThemeProvider::GetFrom( browser_->profile()); @@ -207,8 +205,8 @@ void ExtensionInstalledBubbleGtk::ShowInternal() { !base::i18n::IsRTL() ? InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT : InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT; - info_bubble_ = InfoBubbleGtk::Show(browser_window->window(), - bounds, + info_bubble_ = InfoBubbleGtk::Show(reference_widget, + NULL, bubble_content, arrow_location, true, // match_system_theme diff --git a/chrome/browser/gtk/extension_popup_gtk.cc b/chrome/browser/gtk/extension_popup_gtk.cc index fad0c0b..c2a68ec 100644 --- a/chrome/browser/gtk/extension_popup_gtk.cc +++ b/chrome/browser/gtk/extension_popup_gtk.cc @@ -22,12 +22,12 @@ ExtensionPopupGtk* ExtensionPopupGtk::current_extension_popup_ = NULL; ExtensionPopupGtk::ExtensionPopupGtk(Browser* browser, ExtensionHost* host, - const gfx::Rect& relative_to, + GtkWidget* anchor, bool inspect) : browser_(browser), bubble_(NULL), host_(host), - relative_to_(relative_to), + anchor_(anchor), being_inspected_(inspect), method_factory_(this) { // If the host had somehow finished loading, then we'd miss the notification @@ -103,8 +103,8 @@ void ExtensionPopupGtk::ShowPopup() { !base::i18n::IsRTL() ? InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT : InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT; - bubble_ = InfoBubbleGtk::Show(browser_->window()->GetNativeHandle(), - relative_to_, + bubble_ = InfoBubbleGtk::Show(anchor_, + NULL, host_->view()->native_view(), arrow_location, false, // match_system_theme @@ -131,7 +131,7 @@ void ExtensionPopupGtk::InfoBubbleClosing(InfoBubbleGtk* bubble, // static void ExtensionPopupGtk::Show(const GURL& url, Browser* browser, - const gfx::Rect& relative_to, bool inspect) { + GtkWidget* anchor, bool inspect) { ExtensionProcessManager* manager = browser->profile()->GetExtensionProcessManager(); DCHECK(manager); @@ -140,7 +140,7 @@ void ExtensionPopupGtk::Show(const GURL& url, Browser* browser, ExtensionHost* host = manager->CreatePopup(url, browser); // This object will delete itself when the info bubble is closed. - new ExtensionPopupGtk(browser, host, relative_to, inspect); + new ExtensionPopupGtk(browser, host, anchor, inspect); } gfx::Rect ExtensionPopupGtk::GetViewBounds() { diff --git a/chrome/browser/gtk/extension_popup_gtk.h b/chrome/browser/gtk/extension_popup_gtk.h index 9cced80..846f4dc 100644 --- a/chrome/browser/gtk/extension_popup_gtk.h +++ b/chrome/browser/gtk/extension_popup_gtk.h @@ -21,13 +21,13 @@ class ExtensionPopupGtk : public NotificationObserver, public: ExtensionPopupGtk(Browser* browser, ExtensionHost* host, - const gfx::Rect& relative_to, + GtkWidget* anchor, bool inspect); virtual ~ExtensionPopupGtk(); static void Show(const GURL& url, Browser* browser, - const gfx::Rect& relative_to, + GtkWidget* anchor, bool inspect); // NotificationObserver implementation. @@ -64,9 +64,8 @@ class ExtensionPopupGtk : public NotificationObserver, // 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_; + // The widget for anchoring the position of the info bubble. + GtkWidget* anchor_; NotificationRegistrar registrar_; diff --git a/chrome/browser/gtk/first_run_bubble.cc b/chrome/browser/gtk/first_run_bubble.cc index f2a8433..e33ef4e 100644 --- a/chrome/browser/gtk/first_run_bubble.cc +++ b/chrome/browser/gtk/first_run_bubble.cc @@ -45,10 +45,10 @@ string16 GetDefaultSearchEngineName(Profile* profile) { // static void FirstRunBubble::Show(Profile* profile, - GtkWindow* parent, + GtkWidget* anchor, const gfx::Rect& rect, bool use_OEM_bubble) { - new FirstRunBubble(profile, parent, rect); + new FirstRunBubble(profile, anchor, rect); } void FirstRunBubble::InfoBubbleClosing(InfoBubbleGtk* info_bubble, @@ -75,11 +75,11 @@ void FirstRunBubble::Observe(NotificationType type, } FirstRunBubble::FirstRunBubble(Profile* profile, - GtkWindow* parent, + GtkWidget* anchor, const gfx::Rect& rect) : profile_(profile), theme_provider_(GtkThemeProvider::GetFrom(profile_)), - parent_(parent), + anchor_(anchor), content_(NULL), bubble_(NULL) { GtkWidget* label1 = gtk_label_new(NULL); @@ -115,11 +115,11 @@ FirstRunBubble::FirstRunBubble(Profile* profile, content_ = gtk_vbox_new(FALSE, 5); gtk_container_set_border_width(GTK_CONTAINER(content_), kContentBorder); - // We compute the widget's size using the parent window -- |content_| is + // We compute the widget's size using the anchor widget -- |content_| is // unrealized at this point. int width = -1, height = -1; gtk_util::GetWidgetSizeFromResources( - GTK_WIDGET(parent_), + anchor_, IDS_FIRSTRUNBUBBLE_DIALOG_WIDTH_CHARS, IDS_FIRSTRUNBUBBLE_DIALOG_HEIGHT_LINES, &width, &height); @@ -152,8 +152,8 @@ FirstRunBubble::FirstRunBubble(Profile* profile, !base::i18n::IsRTL() ? InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT : InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT; - bubble_ = InfoBubbleGtk::Show(parent_, - rect, + bubble_ = InfoBubbleGtk::Show(anchor_, + &rect, content_, arrow_location, true, // match_system_theme diff --git a/chrome/browser/gtk/first_run_bubble.h b/chrome/browser/gtk/first_run_bubble.h index b52dc98..efc9924 100644 --- a/chrome/browser/gtk/first_run_bubble.h +++ b/chrome/browser/gtk/first_run_bubble.h @@ -24,7 +24,7 @@ class FirstRunBubble : public InfoBubbleGtkDelegate, public: // Shows the first run bubble, pointing at |rect|. static void Show(Profile* profile, - GtkWindow* parent, + GtkWidget* anchor, const gfx::Rect& rect, bool use_OEM_bubble); @@ -41,7 +41,7 @@ class FirstRunBubble : public InfoBubbleGtkDelegate, private: FirstRunBubble(Profile* profile, - GtkWindow* parent, + GtkWidget* anchor, const gfx::Rect& rect); ~FirstRunBubble() { } @@ -66,8 +66,9 @@ class FirstRunBubble : public InfoBubbleGtkDelegate, // Provides colors and stuff. GtkThemeProvider* theme_provider_; - // The toplevel window our dialogs should be transient for. - GtkWindow* parent_; + // The widget we anchor to, and a descendant of the toplevel window we + // are transient for. + GtkWidget* anchor_; // We let the InfoBubble own our content, and then we delete ourself // when the widget is destroyed (when the InfoBubble is destroyed). diff --git a/chrome/browser/gtk/gtk_util.cc b/chrome/browser/gtk/gtk_util.cc index 72f392e..15941cc 100644 --- a/chrome/browser/gtk/gtk_util.cc +++ b/chrome/browser/gtk/gtk_util.cc @@ -515,18 +515,7 @@ bool WidgetContainsCursor(GtkWidget* widget) { gint x = 0; gint y = 0; gtk_widget_get_pointer(widget, &x, &y); - - // To quote the gtk docs: - // - // Widget coordinates are a bit odd; for historical reasons, they are - // defined as widget->window coordinates for widgets that are not - // GTK_NO_WINDOW widgets, and are relative to widget->allocation.x, - // widget->allocation.y for widgets that are GTK_NO_WINDOW widgets. - // - // So the base is always (0,0). - gfx::Rect widget_allocation(0, 0, widget->allocation.width, - widget->allocation.height); - return widget_allocation.Contains(x, y); + return WidgetBounds(widget).Contains(x, y); } void SetWindowIcon(GtkWindow* window) { @@ -858,4 +847,16 @@ bool GrabAllInput(GtkWidget* widget) { return true; } +gfx::Rect WidgetBounds(GtkWidget* widget) { + // To quote the gtk docs: + // + // Widget coordinates are a bit odd; for historical reasons, they are + // defined as widget->window coordinates for widgets that are not + // GTK_NO_WINDOW widgets, and are relative to widget->allocation.x, + // widget->allocation.y for widgets that are GTK_NO_WINDOW widgets. + // + // So the base is always (0,0). + return gfx::Rect(0, 0, widget->allocation.width, widget->allocation.height); +} + } // namespace gtk_util diff --git a/chrome/browser/gtk/gtk_util.h b/chrome/browser/gtk/gtk_util.h index 9a65193..b100b1d 100644 --- a/chrome/browser/gtk/gtk_util.h +++ b/chrome/browser/gtk/gtk_util.h @@ -256,6 +256,10 @@ WindowOpenDisposition DispositionForCurrentButtonPressEvent(); // for success. bool GrabAllInput(GtkWidget* widget); +// Returns a rectangle that represents the widget's bounds. The rectangle it +// returns is the same as widget->allocation, but anchored at (0, 0). +gfx::Rect WidgetBounds(GtkWidget* widget); + } // namespace gtk_util #endif // CHROME_BROWSER_GTK_GTK_UTIL_H_ diff --git a/chrome/browser/gtk/info_bubble_gtk.cc b/chrome/browser/gtk/info_bubble_gtk.cc index abbaf5c..12eef6f 100644 --- a/chrome/browser/gtk/info_bubble_gtk.cc +++ b/chrome/browser/gtk/info_bubble_gtk.cc @@ -44,8 +44,8 @@ const GdkColor kFrameColor = GDK_COLOR_RGB(0x63, 0x63, 0x63); } // namespace // static -InfoBubbleGtk* InfoBubbleGtk::Show(GtkWindow* toplevel_window, - const gfx::Rect& rect, +InfoBubbleGtk* InfoBubbleGtk::Show(GtkWidget* anchor_widget, + const gfx::Rect* rect, GtkWidget* content, ArrowLocationGtk arrow_location, bool match_system_theme, @@ -53,7 +53,7 @@ InfoBubbleGtk* InfoBubbleGtk::Show(GtkWindow* toplevel_window, GtkThemeProvider* provider, InfoBubbleGtkDelegate* delegate) { InfoBubbleGtk* bubble = new InfoBubbleGtk(provider, match_system_theme); - bubble->Init(toplevel_window, rect, content, arrow_location, grab_input); + bubble->Init(anchor_widget, rect, content, arrow_location, grab_input); bubble->set_delegate(delegate); return bubble; } @@ -85,6 +85,14 @@ InfoBubbleGtk::~InfoBubbleGtk() { mask_region_ = NULL; } + if (anchor_widget_) { + g_signal_handlers_disconnect_by_func( + anchor_widget_, + reinterpret_cast<gpointer>(OnAnchorAllocateThunk), + this); + } + anchor_widget_ = NULL; + if (toplevel_window_) { g_signal_handlers_disconnect_by_func( toplevel_window_, @@ -98,8 +106,8 @@ InfoBubbleGtk::~InfoBubbleGtk() { toplevel_window_ = NULL; } -void InfoBubbleGtk::Init(GtkWindow* toplevel_window, - const gfx::Rect& rect, +void InfoBubbleGtk::Init(GtkWidget* anchor_widget, + const gfx::Rect* rect, GtkWidget* content, ArrowLocationGtk arrow_location, bool grab_input) { @@ -109,9 +117,10 @@ void InfoBubbleGtk::Init(GtkWindow* toplevel_window, gtk_widget_hide(current_grab_widget); DCHECK(!window_); - toplevel_window_ = toplevel_window; - DCHECK(toplevel_window_); - rect_ = rect; + anchor_widget_ = anchor_widget; + toplevel_window_ = GTK_WINDOW(gtk_widget_get_toplevel(anchor_widget_)); + DCHECK(GTK_WIDGET_TOPLEVEL(toplevel_window_)); + rect_ = rect ? *rect : gtk_util::WidgetBounds(anchor_widget); preferred_arrow_location_ = arrow_location; grab_input_ = grab_input; @@ -158,6 +167,15 @@ void InfoBubbleGtk::Init(GtkWindow* toplevel_window, g_signal_connect(window_, "hide", G_CALLBACK(OnHideThunk), this); + // If the toplevel window is being used as the anchor, then the signals below + // are enough to keep us positioned correctly. + if (anchor_widget_ != GTK_WIDGET(toplevel_window_)) { + g_signal_connect(anchor_widget_, "size-allocate", + G_CALLBACK(OnAnchorAllocateThunk), this); + g_signal_connect(anchor_widget_, "destroy", + G_CALLBACK(gtk_widget_destroyed), &anchor_widget_); + } + g_signal_connect(toplevel_window_, "configure-event", G_CALLBACK(OnToplevelConfigureThunk), this); g_signal_connect(toplevel_window_, "unmap-event", @@ -259,17 +277,20 @@ InfoBubbleGtk::ArrowLocationGtk InfoBubbleGtk::GetArrowLocation( } bool InfoBubbleGtk::UpdateArrowLocation(bool force_move_and_reshape) { - if (!toplevel_window_) + if (!toplevel_window_ || !anchor_widget_) return false; gint toplevel_x = 0, toplevel_y = 0; gdk_window_get_position( GTK_WIDGET(toplevel_window_)->window, &toplevel_x, &toplevel_y); + int offset_x, offset_y; + gtk_widget_translate_coordinates(anchor_widget_, GTK_WIDGET(toplevel_window_), + rect_.x(), rect_.y(), &offset_x, &offset_y); ArrowLocationGtk old_location = current_arrow_location_; current_arrow_location_ = GetArrowLocation( preferred_arrow_location_, - toplevel_x + rect_.x() + (rect_.width() / 2), // arrow_x + toplevel_x + offset_x + (rect_.width() / 2), // arrow_x window_->allocation.width); if (force_move_and_reshape || current_arrow_location_ != old_location) { @@ -298,24 +319,28 @@ void InfoBubbleGtk::UpdateWindowShape() { } void InfoBubbleGtk::MoveWindow() { - if (!toplevel_window_) + if (!toplevel_window_ || !anchor_widget_) return; gint toplevel_x = 0, toplevel_y = 0; gdk_window_get_position( GTK_WIDGET(toplevel_window_)->window, &toplevel_x, &toplevel_y); + int offset_x, offset_y; + gtk_widget_translate_coordinates(anchor_widget_, GTK_WIDGET(toplevel_window_), + rect_.x(), rect_.y(), &offset_x, &offset_y); + gint screen_x = 0; if (current_arrow_location_ == ARROW_LOCATION_TOP_LEFT) { - screen_x = toplevel_x + rect_.x() + (rect_.width() / 2) - kArrowX; + screen_x = toplevel_x + offset_x + (rect_.width() / 2) - kArrowX; } else if (current_arrow_location_ == ARROW_LOCATION_TOP_RIGHT) { - screen_x = toplevel_x + rect_.x() + (rect_.width() / 2) - + screen_x = toplevel_x + offset_x + (rect_.width() / 2) - window_->allocation.width + kArrowX; } else { NOTREACHED(); } - gint screen_y = toplevel_y + rect_.y() + rect_.height() + + gint screen_y = toplevel_y + offset_y + rect_.height() + kArrowToContentPadding; gtk_window_move(GTK_WINDOW(window_), screen_x, screen_y); @@ -461,3 +486,9 @@ gboolean InfoBubbleGtk::OnToplevelUnmap(GtkWidget* widget, GdkEvent* event) { Close(); return FALSE; } + +void InfoBubbleGtk::OnAnchorAllocate(GtkWidget* widget, + GtkAllocation* allocation) { + if (!UpdateArrowLocation(false)) + MoveWindow(); +} diff --git a/chrome/browser/gtk/info_bubble_gtk.h b/chrome/browser/gtk/info_bubble_gtk.h index e5601fd..65515d6 100644 --- a/chrome/browser/gtk/info_bubble_gtk.h +++ b/chrome/browser/gtk/info_bubble_gtk.h @@ -51,14 +51,15 @@ class InfoBubbleGtk : public NotificationObserver { }; // Show an InfoBubble, pointing at the area |rect| (in coordinates relative to - // |toplevel_window|'s origin). An info bubble will try to fit on the screen, - // so it can point to any edge of |rect|. The bubble will host the |content| + // |anchor_widget|'s origin). An info bubble will try to fit on the screen, + // so it can point to any edge of |rect|. If |rect| is NULL, the widget's + // entire area will be used. The bubble will host the |content| // widget. Its arrow will be drawn at |arrow_location| if possible. The // |delegate| will be notified when the bubble is closed. The bubble will // perform an X grab of the pointer and keyboard, and will close itself if a // click is received outside of the bubble. - static InfoBubbleGtk* Show(GtkWindow* toplevel_window, - const gfx::Rect& rect, + static InfoBubbleGtk* Show(GtkWidget* anchor_widget, + const gfx::Rect* rect, GtkWidget* content, ArrowLocationGtk arrow_location, bool match_system_theme, @@ -95,8 +96,8 @@ class InfoBubbleGtk : public NotificationObserver { virtual ~InfoBubbleGtk(); // Creates the InfoBubble. - void Init(GtkWindow* toplevel_window, - const gfx::Rect& rect, + void Init(GtkWidget* anchor_widget, + const gfx::Rect* rect, GtkWidget* content, ArrowLocationGtk arrow_location, bool grab_input); @@ -157,6 +158,7 @@ class InfoBubbleGtk : public NotificationObserver { CHROMEGTK_CALLBACK_1(InfoBubbleGtk, gboolean, OnToplevelConfigure, GdkEventConfigure*); CHROMEGTK_CALLBACK_1(InfoBubbleGtk, gboolean, OnToplevelUnmap, GdkEvent*); + CHROMEGTK_CALLBACK_1(InfoBubbleGtk, void, OnAnchorAllocate, GtkAllocation*); // The caller supplied delegate, can be NULL. InfoBubbleGtkDelegate* delegate_; @@ -177,7 +179,10 @@ class InfoBubbleGtk : public NotificationObserver { // to check for that case. GtkWindow* toplevel_window_; - // Provides an offset from |toplevel_window_|'s origin for MoveWindow() to + // The widget that we use to relatively position the popup window. + GtkWidget* anchor_widget_; + + // Provides an offset from |anchor_widget_|'s origin for MoveWindow() to // use. gfx::Rect rect_; diff --git a/chrome/browser/gtk/location_bar_view_gtk.cc b/chrome/browser/gtk/location_bar_view_gtk.cc index f167651..27ea366 100644 --- a/chrome/browser/gtk/location_bar_view_gtk.cc +++ b/chrome/browser/gtk/location_bar_view_gtk.cc @@ -29,7 +29,7 @@ #include "chrome/browser/extensions/extensions_service.h" #include "chrome/browser/gtk/bookmark_bubble_gtk.h" #include "chrome/browser/gtk/cairo_cached_surface.h" -#include "chrome/browser/gtk/content_blocked_bubble_gtk.h" +#include "chrome/browser/gtk/content_setting_bubble_gtk.h" #include "chrome/browser/gtk/extension_popup_gtk.h" #include "chrome/browser/gtk/first_run_bubble.h" #include "chrome/browser/gtk/gtk_theme_provider.h" @@ -65,7 +65,7 @@ const int kBorderThickness = 1; // Left margin of first run bubble. const int kFirstRunBubbleLeftMargin = 8; // Extra vertical spacing for first run bubble. -const int kFirstRunBubbleTopMargin = 1; +const int kFirstRunBubbleTopMargin = 5; // The padding around the top, bottom, and sides of the location bar hbox. // We don't want to edit control's text to be right against the edge, @@ -863,24 +863,19 @@ void LocationBarViewGtk::ShowFirstRunBubbleInternal(bool use_OEM_bubble) { if (!location_entry_.get() || !widget()->window) return; - gfx::Rect rect = gtk_util::GetWidgetRectRelativeToToplevel(widget()); - rect.set_width(0); - rect.set_height(0); + GtkWidget* anchor = location_entry_->GetNativeView(); // The bubble needs to be just below the Omnibox and slightly to the right // of star button, so shift x and y co-ordinates. - int y_offset = widget()->allocation.height + kFirstRunBubbleTopMargin; + int y_offset = anchor->allocation.height + kFirstRunBubbleTopMargin; int x_offset = 0; if (!base::i18n::IsRTL()) x_offset = kFirstRunBubbleLeftMargin; else - x_offset = widget()->allocation.width - kFirstRunBubbleLeftMargin; - rect.Offset(x_offset, y_offset); + x_offset = anchor->allocation.width - kFirstRunBubbleLeftMargin; + gfx::Rect rect(x_offset, y_offset, 0, 0); - FirstRunBubble::Show(profile_, - GTK_WINDOW(gtk_widget_get_toplevel(widget())), - rect, - use_OEM_bubble); + FirstRunBubble::Show(profile_, anchor, rect, use_OEM_bubble); } gboolean LocationBarViewGtk::OnIconReleased(GtkWidget* sender, @@ -926,9 +921,7 @@ gboolean LocationBarViewGtk::OnStarButtonPress(GtkWidget* widget, void LocationBarViewGtk::ShowStarBubble(const GURL& url, bool newly_bookmarked) { - BookmarkBubbleGtk::Show(GTK_WINDOW(gtk_widget_get_toplevel(star_.get())), - gtk_util::GetWidgetRectRelativeToToplevel(star_.get()), - profile_, url, newly_bookmarked); + BookmarkBubbleGtk::Show(star_.get(), profile_, url, newly_bookmarked); } void LocationBarViewGtk::SetStarred(bool starred) { @@ -1073,9 +1066,6 @@ void LocationBarViewGtk::ContentSettingImageViewGtk::UpdateFromTabContents( gboolean LocationBarViewGtk::ContentSettingImageViewGtk::OnButtonPressed( GtkWidget* sender, GdkEvent* event) { - gfx::Rect bounds = - gtk_util::GetWidgetRectRelativeToToplevel(sender); - TabContents* tab_contents = parent_->GetTabContents(); if (!tab_contents) return true; @@ -1085,10 +1075,8 @@ gboolean LocationBarViewGtk::ContentSettingImageViewGtk::OnButtonPressed( profile_->GetPrefs()->GetString(prefs::kAcceptLanguages), &display_host, NULL, NULL); - GtkWindow* toplevel = GTK_WINDOW(gtk_widget_get_toplevel(sender)); - info_bubble_ = new ContentSettingBubbleGtk( - toplevel, bounds, this, + sender, this, ContentSettingBubbleModel::CreateContentSettingBubbleModel( tab_contents, profile_, content_setting_image_model_->get_content_settings_type()), @@ -1271,7 +1259,7 @@ bool LocationBarViewGtk::PageActionViewGtk::ShowPopup(bool devtools) { ExtensionPopupGtk::Show( page_action_->GetPopupUrl(current_tab_id_), owner_->browser_, - gtk_util::GetWidgetRectRelativeToToplevel(event_box_.get()), + event_box_.get(), devtools); return true; } |