summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-07 21:00:33 +0000
committerestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-07 21:00:33 +0000
commitc4d6f87b0cf6ee6d8478a79875700600b049d1df (patch)
treee3fd77172b81c7d83ac495d96f973881946c7482 /chrome/browser
parent875f8f9b0757f2029b21cead7822db116ea525e0 (diff)
downloadchromium_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.cc19
-rw-r--r--chrome/browser/gtk/bookmark_bubble_gtk.h15
-rw-r--r--chrome/browser/gtk/browser_actions_toolbar_gtk.cc8
-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.cc10
-rw-r--r--chrome/browser/gtk/extension_popup_gtk.cc12
-rw-r--r--chrome/browser/gtk/extension_popup_gtk.h9
-rw-r--r--chrome/browser/gtk/first_run_bubble.cc16
-rw-r--r--chrome/browser/gtk/first_run_bubble.h9
-rw-r--r--chrome/browser/gtk/gtk_util.cc25
-rw-r--r--chrome/browser/gtk/gtk_util.h4
-rw-r--r--chrome/browser/gtk/info_bubble_gtk.cc59
-rw-r--r--chrome/browser/gtk/info_bubble_gtk.h19
-rw-r--r--chrome/browser/gtk/location_bar_view_gtk.cc32
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;
}