From 85131ae72bee932e59cfcec442109a568c6cc8b8 Mon Sep 17 00:00:00 2001 From: "tfarina@chromium.org" Date: Thu, 21 Apr 2011 22:50:26 +0000 Subject: gtk: Move bubble related files into ui/gtk/bubble directory. Rename InfoBubbleGtk to BubbleGtk. Rename InfoBubbleGtkDelegate to BubbleDelegateGtk. Rename InfoBubbleAcceleratorsGtk To BubbleAcceleratorsGtk. This is a follow up to Ben's patch in http://codereview.chromium.org/6840026. BUG=72040 TEST=None R=estade@chromium.org Review URL: http://codereview.chromium.org/6865048 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@82570 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/speech/speech_input_bubble_gtk.cc | 77 ++- .../ui/gtk/bookmarks/bookmark_bubble_gtk.cc | 36 +- .../browser/ui/gtk/bookmarks/bookmark_bubble_gtk.h | 22 +- chrome/browser/ui/gtk/browser_window_gtk.cc | 1 - .../ui/gtk/bubble/bubble_accelerators_gtk.cc | 34 ++ .../ui/gtk/bubble/bubble_accelerators_gtk.h | 39 ++ chrome/browser/ui/gtk/bubble/bubble_gtk.cc | 536 +++++++++++++++++++++ chrome/browser/ui/gtk/bubble/bubble_gtk.h | 216 +++++++++ .../browser/ui/gtk/content_setting_bubble_gtk.cc | 39 +- chrome/browser/ui/gtk/content_setting_bubble_gtk.h | 22 +- .../extensions/extension_installed_bubble_gtk.cc | 43 +- .../extensions/extension_installed_bubble_gtk.h | 24 +- .../ui/gtk/extensions/extension_popup_gtk.cc | 28 +- .../ui/gtk/extensions/extension_popup_gtk.h | 21 +- chrome/browser/ui/gtk/first_run_bubble.cc | 32 +- chrome/browser/ui/gtk/first_run_bubble.h | 20 +- .../browser/ui/gtk/info_bubble_accelerators_gtk.cc | 34 -- .../browser/ui/gtk/info_bubble_accelerators_gtk.h | 39 -- chrome/browser/ui/gtk/info_bubble_gtk.cc | 536 --------------------- chrome/browser/ui/gtk/info_bubble_gtk.h | 215 --------- chrome/browser/ui/gtk/location_bar_view_gtk.cc | 14 +- chrome/browser/ui/gtk/location_bar_view_gtk.h | 17 +- .../ui/gtk/notifications/balloon_view_gtk.cc | 1 - chrome/browser/ui/gtk/page_info_bubble_gtk.cc | 57 ++- chrome/chrome_browser.gypi | 8 +- 25 files changed, 1048 insertions(+), 1063 deletions(-) create mode 100644 chrome/browser/ui/gtk/bubble/bubble_accelerators_gtk.cc create mode 100644 chrome/browser/ui/gtk/bubble/bubble_accelerators_gtk.h create mode 100644 chrome/browser/ui/gtk/bubble/bubble_gtk.cc create mode 100644 chrome/browser/ui/gtk/bubble/bubble_gtk.h delete mode 100644 chrome/browser/ui/gtk/info_bubble_accelerators_gtk.cc delete mode 100644 chrome/browser/ui/gtk/info_bubble_accelerators_gtk.h delete mode 100644 chrome/browser/ui/gtk/info_bubble_gtk.cc delete mode 100644 chrome/browser/ui/gtk/info_bubble_gtk.h diff --git a/chrome/browser/speech/speech_input_bubble_gtk.cc b/chrome/browser/speech/speech_input_bubble_gtk.cc index 0fab31d..d1004b2 100644 --- a/chrome/browser/speech/speech_input_bubble_gtk.cc +++ b/chrome/browser/speech/speech_input_bubble_gtk.cc @@ -5,10 +5,10 @@ #include "chrome/browser/speech/speech_input_bubble.h" #include "base/utf_string_conversions.h" +#include "chrome/browser/ui/gtk/bubble/bubble_gtk.h" #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h" #include "chrome/browser/ui/gtk/gtk_theme_service.h" #include "chrome/browser/ui/gtk/gtk_util.h" -#include "chrome/browser/ui/gtk/info_bubble_gtk.h" #include "chrome/browser/ui/gtk/owned_widget_gtk.h" #include "content/browser/tab_contents/tab_contents.h" #include "grit/generated_resources.h" @@ -29,11 +29,10 @@ const int kButtonBarHorizontalSpacing = 10; // Use black for text labels since the bubble has white background. const GdkColor kLabelTextColor = gtk_util::kGdkBlack; -// Implementation of SpeechInputBubble for GTK. This shows a speech input -// info bubble on screen. -class SpeechInputBubbleGtk - : public SpeechInputBubbleBase, - public InfoBubbleGtkDelegate { +// Implementation of SpeechInputBubble for GTK. This shows a speech input bubble +// on screen. +class SpeechInputBubbleGtk : public SpeechInputBubbleBase, + public BubbleDelegateGtk { public: SpeechInputBubbleGtk(TabContents* tab_contents, Delegate* delegate, @@ -41,22 +40,21 @@ class SpeechInputBubbleGtk ~SpeechInputBubbleGtk(); private: - // InfoBubbleDelegate methods. - virtual void InfoBubbleClosing(InfoBubbleGtk* info_bubble, - bool closed_by_escape); + // SpeechInputBubbleBase: + virtual void Show() OVERRIDE; + virtual void Hide() OVERRIDE; + virtual void UpdateLayout() OVERRIDE; + virtual void UpdateImage() OVERRIDE; - // SpeechInputBubble methods. - virtual void Show(); - virtual void Hide(); - virtual void UpdateLayout(); - virtual void UpdateImage(); + // BubbleDelegateGtk: + virtual void BubbleClosing(BubbleGtk* bubble, bool closed_by_escape) OVERRIDE; CHROMEGTK_CALLBACK_0(SpeechInputBubbleGtk, void, OnCancelClicked); CHROMEGTK_CALLBACK_0(SpeechInputBubbleGtk, void, OnTryAgainClicked); CHROMEGTK_CALLBACK_0(SpeechInputBubbleGtk, void, OnMicSettingsClicked); Delegate* delegate_; - InfoBubbleGtk* info_bubble_; + BubbleGtk* bubble_; gfx::Rect element_rect_; bool did_invoke_close_; @@ -75,7 +73,7 @@ SpeechInputBubbleGtk::SpeechInputBubbleGtk(TabContents* tab_contents, const gfx::Rect& element_rect) : SpeechInputBubbleBase(tab_contents), delegate_(delegate), - info_bubble_(NULL), + bubble_(NULL), element_rect_(element_rect), did_invoke_close_(false), label_(NULL), @@ -87,20 +85,13 @@ SpeechInputBubbleGtk::SpeechInputBubbleGtk(TabContents* tab_contents, } SpeechInputBubbleGtk::~SpeechInputBubbleGtk() { - // The |Close| call below invokes our |InfoBubbleClosing| method. Since we - // were destroyed by the caller we don't need to call them back, hence set - // this flag here. + // The |Close| call below invokes our |BubbleClosing| method. Since we were + // destroyed by the caller we don't need to call them back, hence set this + // flag here. did_invoke_close_ = true; Hide(); } -void SpeechInputBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble, - bool closed_by_escape) { - info_bubble_ = NULL; - if (!did_invoke_close_) - delegate_->InfoBubbleFocusChanged(); -} - void SpeechInputBubbleGtk::OnCancelClicked(GtkWidget* widget) { delegate_->InfoBubbleButtonClicked(BUTTON_CANCEL); } @@ -114,7 +105,7 @@ void SpeechInputBubbleGtk::OnMicSettingsClicked(GtkWidget* widget) { } void SpeechInputBubbleGtk::Show() { - if (info_bubble_) + if (bubble_) return; // Nothing further to do since the bubble is already visible. // We use a vbox to arrange the controls (label, image, button bar) vertically @@ -171,25 +162,25 @@ void SpeechInputBubbleGtk::Show() { gfx::Rect rect( element_rect_.x() + element_rect_.width() - kBubbleTargetOffsetX, element_rect_.y() + element_rect_.height(), 1, 1); - info_bubble_ = InfoBubbleGtk::Show(tab_contents()->GetNativeView(), - &rect, - content, - InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT, - false, // match_system_theme - true, // grab_input - theme_provider, - this); + bubble_ = BubbleGtk::Show(tab_contents()->GetNativeView(), + &rect, + content, + BubbleGtk::ARROW_LOCATION_TOP_LEFT, + false, // match_system_theme + true, // grab_input + theme_provider, + this); UpdateLayout(); } void SpeechInputBubbleGtk::Hide() { - if (info_bubble_) - info_bubble_->Close(); + if (bubble_) + bubble_->Close(); } void SpeechInputBubbleGtk::UpdateLayout() { - if (!info_bubble_) + if (!bubble_) return; if (display_mode() == DISPLAY_MODE_MESSAGE) { @@ -252,7 +243,7 @@ void SpeechInputBubbleGtk::UpdateLayout() { void SpeechInputBubbleGtk::UpdateImage() { SkBitmap image = icon_image(); - if (image.isNull() || !info_bubble_) + if (image.isNull() || !bubble_) return; GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&image); @@ -260,6 +251,13 @@ void SpeechInputBubbleGtk::UpdateImage() { g_object_unref(pixbuf); } +void SpeechInputBubbleGtk::BubbleClosing(BubbleGtk* bubble, + bool closed_by_escape) { + bubble_ = NULL; + if (!did_invoke_close_) + delegate_->InfoBubbleFocusChanged(); +} + } // namespace SpeechInputBubble* SpeechInputBubble::CreateNativeBubble( @@ -268,4 +266,3 @@ SpeechInputBubble* SpeechInputBubble::CreateNativeBubble( const gfx::Rect& element_rect) { return new SpeechInputBubbleGtk(tab_contents, delegate, element_rect); } - diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.cc b/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.cc index 4248f43..229ef43 100644 --- a/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.cc @@ -21,7 +21,6 @@ #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h" #include "chrome/browser/ui/gtk/gtk_theme_service.h" #include "chrome/browser/ui/gtk/gtk_util.h" -#include "chrome/browser/ui/gtk/info_bubble_gtk.h" #include "content/common/notification_service.h" #include "grit/generated_resources.h" #include "ui/base/l10n/l10n_util.h" @@ -32,10 +31,9 @@ namespace { // keeps track of the currently open bubble, or NULL if none is open. BookmarkBubbleGtk* g_bubble = NULL; -// Padding between content and edge of info bubble. +// Padding between content and edge of bubble. const int kContentBorder = 7; - } // namespace // static @@ -47,8 +45,8 @@ void BookmarkBubbleGtk::Show(GtkWidget* anchor, g_bubble = new BookmarkBubbleGtk(anchor, profile, url, newly_bookmarked); } -void BookmarkBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble, - bool closed_by_escape) { +void BookmarkBubbleGtk::BubbleClosing(BubbleGtk* bubble, + bool closed_by_escape) { if (closed_by_escape) { remove_bookmark_ = newly_bookmarked_; apply_edits_ = false; @@ -156,18 +154,18 @@ BookmarkBubbleGtk::BookmarkBubbleGtk(GtkWidget* anchor, // We want the focus to start on the entry, not on the remove button. gtk_container_set_focus_child(GTK_CONTAINER(content), table); - InfoBubbleGtk::ArrowLocationGtk arrow_location = + BubbleGtk::ArrowLocationGtk arrow_location = base::i18n::IsRTL() ? - InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT : - InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT; - bubble_ = InfoBubbleGtk::Show(anchor_, - NULL, - content, - arrow_location, - true, // match_system_theme - true, // grab_input - theme_service_, - this); // delegate + BubbleGtk::ARROW_LOCATION_TOP_LEFT : + BubbleGtk::ARROW_LOCATION_TOP_RIGHT; + bubble_ = BubbleGtk::Show(anchor_, + NULL, + content, + arrow_location, + true, // match_system_theme + true, // grab_input + theme_service_, + this); // delegate if (!bubble_) { NOTREACHED(); return; @@ -211,7 +209,7 @@ BookmarkBubbleGtk::~BookmarkBubbleGtk() { void BookmarkBubbleGtk::OnDestroy(GtkWidget* widget) { // We are self deleting, we have a destroy signal setup to catch when we - // destroyed (via the InfoBubble being destroyed), and delete ourself. + // destroyed (via the BubbleGtk being destroyed), and delete ourself. content_ = NULL; // We are being destroyed. delete this; } @@ -237,8 +235,8 @@ void BookmarkBubbleGtk::OnFolderChanged(GtkWidget* widget) { void BookmarkBubbleGtk::OnFolderPopupShown(GtkWidget* widget, GParamSpec* property) { // GtkComboBox grabs the keyboard and pointer when it displays its popup, - // which steals the grabs that InfoBubbleGtk had installed. When the popup is - // hidden, we notify InfoBubbleGtk so it can try to reacquire the grabs + // which steals the grabs that BubbleGtk had installed. When the popup is + // hidden, we notify BubbleGtk so it can try to reacquire the grabs // (otherwise, GTK won't activate our widgets when the user clicks in them). gboolean popup_shown = FALSE; g_object_get(G_OBJECT(folder_combo_), "popup-shown", &popup_shown, NULL); diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.h b/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.h index 95d9aa7..99831be 100644 --- a/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.h +++ b/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.h @@ -17,9 +17,10 @@ #include #include "base/basictypes.h" +#include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" #include "base/task.h" -#include "chrome/browser/ui/gtk/info_bubble_gtk.h" +#include "chrome/browser/ui/gtk/bubble/bubble_gtk.h" #include "content/common/notification_observer.h" #include "content/common/notification_registrar.h" #include "googleurl/src/gurl.h" @@ -32,7 +33,7 @@ class RecentlyUsedFoldersComboModel; typedef struct _GtkWidget GtkWidget; typedef struct _GParamSpec GParamSpec; -class BookmarkBubbleGtk : public InfoBubbleGtkDelegate, +class BookmarkBubbleGtk : public BubbleDelegateGtk, public NotificationObserver { public: // Shows the bookmark bubble, pointing at |anchor_widget|. @@ -41,16 +42,13 @@ class BookmarkBubbleGtk : public InfoBubbleGtkDelegate, const GURL& url, bool newly_bookmarked); - // Implements the InfoBubbleGtkDelegate. We are notified when the bubble - // is about to be closed, so we have a chance to save any state / input in - // our widgets before they are destroyed. - virtual void InfoBubbleClosing(InfoBubbleGtk* info_bubble, - bool closed_by_escape); + // BubbleDelegateGtk: + virtual void BubbleClosing(BubbleGtk* bubble, bool closed_by_escape) OVERRIDE; - // Overridden from NotificationObserver: + // NotificationObserver: virtual void Observe(NotificationType type, const NotificationSource& source, - const NotificationDetails& details); + const NotificationDetails& details) OVERRIDE; private: BookmarkBubbleGtk(GtkWidget* anchor, @@ -91,8 +89,8 @@ class BookmarkBubbleGtk : public InfoBubbleGtkDelegate, // 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). + // We let the BubbleGtk own our content, and then we delete ourself + // when the widget is destroyed (when the BubbleGtk is destroyed). GtkWidget* content_; // The button that removes the bookmark. @@ -109,7 +107,7 @@ class BookmarkBubbleGtk : public InfoBubbleGtkDelegate, GtkWidget* folder_combo_; scoped_ptr folder_combo_model_; - InfoBubbleGtk* bubble_; + BubbleGtk* bubble_; // We need to push some things on the back of the message loop, so we have // a factory attached to our instance to manage task lifetimes. diff --git a/chrome/browser/ui/gtk/browser_window_gtk.cc b/chrome/browser/ui/gtk/browser_window_gtk.cc index ac24d2c..d0994e31 100644 --- a/chrome/browser/ui/gtk/browser_window_gtk.cc +++ b/chrome/browser/ui/gtk/browser_window_gtk.cc @@ -56,7 +56,6 @@ #include "chrome/browser/ui/gtk/gtk_floating_container.h" #include "chrome/browser/ui/gtk/gtk_theme_service.h" #include "chrome/browser/ui/gtk/gtk_util.h" -#include "chrome/browser/ui/gtk/info_bubble_gtk.h" #include "chrome/browser/ui/gtk/infobars/infobar_container_gtk.h" #include "chrome/browser/ui/gtk/infobars/infobar_gtk.h" #include "chrome/browser/ui/gtk/location_bar_view_gtk.h" diff --git a/chrome/browser/ui/gtk/bubble/bubble_accelerators_gtk.cc b/chrome/browser/ui/gtk/bubble/bubble_accelerators_gtk.cc new file mode 100644 index 0000000..4413686 --- /dev/null +++ b/chrome/browser/ui/gtk/bubble/bubble_accelerators_gtk.cc @@ -0,0 +1,34 @@ +// Copyright (c) 2011 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/ui/gtk/bubble/bubble_accelerators_gtk.h" + +#include +#include + +namespace { + +// Listing of the accelerators that are either handled or forwarded by +// bubbles. Any accelerators that are not explicitly listed here +// are ignored and silently dropped. This table is expected to change +// after discussion over which accelerators should be addressed in +// bubbles. For a complete listing of accelerators that are used +// in chrome consult accelerators_gtk.cc +struct BubbleAcceleratorGtk BubbleAcceleratorGtkTable[] = { + // Tab/window controls. + { GDK_w, GDK_CONTROL_MASK }, + + // Navigation / toolbar buttons. + { GDK_Escape, GdkModifierType(0) } +}; + +} // namespace + +BubbleAcceleratorGtkList BubbleAcceleratorsGtk::GetList() { + BubbleAcceleratorGtkList accelerators; + for (size_t i = 0; i < arraysize(BubbleAcceleratorGtkTable); ++i) + accelerators.push_back(BubbleAcceleratorGtkTable[i]); + + return accelerators; +} diff --git a/chrome/browser/ui/gtk/bubble/bubble_accelerators_gtk.h b/chrome/browser/ui/gtk/bubble/bubble_accelerators_gtk.h new file mode 100644 index 0000000..158e242 --- /dev/null +++ b/chrome/browser/ui/gtk/bubble/bubble_accelerators_gtk.h @@ -0,0 +1,39 @@ +// Copyright (c) 2011 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_UI_GTK_BUBBLE_BUBBLE_ACCELERATORS_GTK_H_ +#define CHROME_BROWSER_UI_GTK_BUBBLE_BUBBLE_ACCELERATORS_GTK_H_ +#pragma once + +#include +#include + +#include + +#include "base/basictypes.h" + +struct BubbleAcceleratorGtk { + guint keyval; + GdkModifierType modifier_type; +}; + +typedef std::vector + BubbleAcceleratorGtkList; + +// This class contains a list of accelerators that a BubbleGtk is expected to +// either catch and respond to or catch and forward to the root browser window. +// This list is expected to be a subset of the accelerators that are handled by +// the root browser window, but the specific accelerators to be handled has not +// yet been fully specified. The common use case for this class has code that +// uses it needing the entire list and not needing extra processing, so the only +// get method gives you the entire list. +class BubbleAcceleratorsGtk { + public: + static BubbleAcceleratorGtkList GetList(); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(BubbleAcceleratorsGtk); +}; + +#endif // CHROME_BROWSER_UI_GTK_BUBBLE_BUBBLE_ACCELERATORS_GTK_H_ diff --git a/chrome/browser/ui/gtk/bubble/bubble_gtk.cc b/chrome/browser/ui/gtk/bubble/bubble_gtk.cc new file mode 100644 index 0000000..95155ad --- /dev/null +++ b/chrome/browser/ui/gtk/bubble/bubble_gtk.cc @@ -0,0 +1,536 @@ +// Copyright (c) 2011 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/ui/gtk/bubble/bubble_gtk.h" + +#include + +#include "base/logging.h" +#include "chrome/browser/ui/gtk/bubble/bubble_accelerators_gtk.h" +#include "chrome/browser/ui/gtk/gtk_theme_service.h" +#include "chrome/browser/ui/gtk/gtk_util.h" +#include "content/common/notification_service.h" +#include "ui/base/gtk/gtk_windowing.h" +#include "ui/gfx/gtk_util.h" +#include "ui/gfx/path.h" +#include "ui/gfx/rect.h" + +namespace { + +// The height of the arrow, and the width will be about twice the height. +const int kArrowSize = 8; + +// Number of pixels to the middle of the arrow from the close edge of the +// window. +const int kArrowX = 18; + +// Number of pixels between the tip of the arrow and the region we're +// pointing to. +const int kArrowToContentPadding = -4; + +// We draw flat diagonal corners, each corner is an NxN square. +const int kCornerSize = 3; + +// Margins around the content. +const int kTopMargin = kArrowSize + kCornerSize - 1; +const int kBottomMargin = kCornerSize - 1; +const int kLeftMargin = kCornerSize - 1; +const int kRightMargin = kCornerSize - 1; + +const GdkColor kBackgroundColor = GDK_COLOR_RGB(0xff, 0xff, 0xff); +const GdkColor kFrameColor = GDK_COLOR_RGB(0x63, 0x63, 0x63); + +} // namespace + +// static +BubbleGtk* BubbleGtk::Show(GtkWidget* anchor_widget, + const gfx::Rect* rect, + GtkWidget* content, + ArrowLocationGtk arrow_location, + bool match_system_theme, + bool grab_input, + GtkThemeService* provider, + BubbleDelegateGtk* delegate) { + BubbleGtk* bubble = new BubbleGtk(provider, match_system_theme); + bubble->Init(anchor_widget, rect, content, arrow_location, grab_input); + bubble->set_delegate(delegate); + return bubble; +} + +BubbleGtk::BubbleGtk(GtkThemeService* provider, + bool match_system_theme) + : delegate_(NULL), + window_(NULL), + theme_service_(provider), + accel_group_(gtk_accel_group_new()), + toplevel_window_(NULL), + anchor_widget_(NULL), + mask_region_(NULL), + preferred_arrow_location_(ARROW_LOCATION_TOP_LEFT), + current_arrow_location_(ARROW_LOCATION_TOP_LEFT), + match_system_theme_(match_system_theme), + grab_input_(true), + closed_by_escape_(false) { +} + +BubbleGtk::~BubbleGtk() { + // Notify the delegate that we're about to close. This gives the chance + // to save state / etc from the hosted widget before it's destroyed. + if (delegate_) + delegate_->BubbleClosing(this, closed_by_escape_); + + g_object_unref(accel_group_); + if (mask_region_) + gdk_region_destroy(mask_region_); +} + +void BubbleGtk::Init(GtkWidget* anchor_widget, + const gfx::Rect* rect, + GtkWidget* content, + ArrowLocationGtk arrow_location, + bool grab_input) { + // If there is a current grab widget (menu, other bubble, etc.), hide it. + GtkWidget* current_grab_widget = gtk_grab_get_current(); + if (current_grab_widget) + gtk_widget_hide(current_grab_widget); + + DCHECK(!window_); + 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; + // Using a TOPLEVEL window may cause placement issues with certain WMs but it + // is necessary to be able to focus the window. + window_ = gtk_window_new(grab_input ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL); + + gtk_widget_set_app_paintable(window_, TRUE); + // Resizing is handled by the program, not user. + gtk_window_set_resizable(GTK_WINDOW(window_), FALSE); + + // Attach all of the accelerators to the bubble. + BubbleAcceleratorGtkList acceleratorList = + BubbleAcceleratorsGtk::GetList(); + for (BubbleAcceleratorGtkList::const_iterator iter = + acceleratorList.begin(); + iter != acceleratorList.end(); + ++iter) { + gtk_accel_group_connect(accel_group_, + iter->keyval, + iter->modifier_type, + GtkAccelFlags(0), + g_cclosure_new(G_CALLBACK(&OnGtkAcceleratorThunk), + this, + NULL)); + } + + gtk_window_add_accel_group(GTK_WINDOW(window_), accel_group_); + + 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_container_add(GTK_CONTAINER(alignment), content); + gtk_container_add(GTK_CONTAINER(window_), alignment); + + // GtkWidget only exposes the bitmap mask interface. Use GDK to more + // efficently mask a GdkRegion. Make sure the window is realized during + // OnSizeAllocate, so the mask can be applied to the GdkWindow. + gtk_widget_realize(window_); + + UpdateArrowLocation(true); // Force move and reshape. + StackWindow(); + + gtk_widget_add_events(window_, GDK_BUTTON_PRESS_MASK); + + signals_.Connect(window_, "expose-event", G_CALLBACK(OnExposeThunk), this); + signals_.Connect(window_, "size-allocate", G_CALLBACK(OnSizeAllocateThunk), + this); + signals_.Connect(window_, "button-press-event", + G_CALLBACK(OnButtonPressThunk), this); + signals_.Connect(window_, "destroy", G_CALLBACK(OnDestroyThunk), this); + signals_.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_)) { + signals_.Connect(anchor_widget_, "size-allocate", + G_CALLBACK(OnAnchorAllocateThunk), this); + signals_.Connect(anchor_widget_, "destroy", + G_CALLBACK(gtk_widget_destroyed), &anchor_widget_); + } + + signals_.Connect(toplevel_window_, "configure-event", + G_CALLBACK(OnToplevelConfigureThunk), this); + signals_.Connect(toplevel_window_, "unmap-event", + G_CALLBACK(OnToplevelUnmapThunk), this); + // Set |toplevel_window_| to NULL if it gets destroyed. + signals_.Connect(toplevel_window_, "destroy", + G_CALLBACK(gtk_widget_destroyed), &toplevel_window_); + + gtk_widget_show_all(window_); + + if (grab_input_) { + gtk_grab_add(window_); + GrabPointerAndKeyboard(); + } + + registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, + NotificationService::AllSources()); + theme_service_->InitThemesFor(this); +} + +// NOTE: This seems a bit overcomplicated, but it requires a bunch of careful +// fudging to get the pixels rasterized exactly where we want them, the arrow to +// have a 1 pixel point, etc. +// TODO(deanm): Windows draws with Skia and uses some PNG images for the +// corners. This is a lot more work, but they get anti-aliasing. +// static +std::vector BubbleGtk::MakeFramePolygonPoints( + ArrowLocationGtk arrow_location, + int width, + int height, + FrameType type) { + using gtk_util::MakeBidiGdkPoint; + std::vector points; + + bool on_left = (arrow_location == ARROW_LOCATION_TOP_LEFT); + + // If we're stroking the frame, we need to offset some of our points by 1 + // pixel. We do this when we draw horizontal lines that are on the bottom or + // when we draw vertical lines that are closer to the end (where "end" is the + // right side for ARROW_LOCATION_TOP_LEFT). + int y_off = (type == FRAME_MASK) ? 0 : -1; + // We use this one for arrows located on the left. + int x_off_l = on_left ? y_off : 0; + // We use this one for RTL. + int x_off_r = !on_left ? -y_off : 0; + + // Top left corner. + points.push_back(MakeBidiGdkPoint( + x_off_r, kArrowSize + kCornerSize - 1, width, on_left)); + points.push_back(MakeBidiGdkPoint( + kCornerSize + x_off_r - 1, kArrowSize, width, on_left)); + + // The arrow. + points.push_back(MakeBidiGdkPoint( + kArrowX - kArrowSize + x_off_r, kArrowSize, width, on_left)); + points.push_back(MakeBidiGdkPoint( + kArrowX + x_off_r, 0, width, on_left)); + points.push_back(MakeBidiGdkPoint( + kArrowX + 1 + x_off_l, 0, width, on_left)); + points.push_back(MakeBidiGdkPoint( + kArrowX + kArrowSize + 1 + x_off_l, kArrowSize, width, on_left)); + + // Top right corner. + points.push_back(MakeBidiGdkPoint( + width - kCornerSize + 1 + x_off_l, kArrowSize, width, on_left)); + points.push_back(MakeBidiGdkPoint( + width + x_off_l, kArrowSize + kCornerSize - 1, width, on_left)); + + // Bottom right corner. + points.push_back(MakeBidiGdkPoint( + width + x_off_l, height - kCornerSize, width, on_left)); + points.push_back(MakeBidiGdkPoint( + width - kCornerSize + x_off_r, height + y_off, width, on_left)); + + // Bottom left corner. + points.push_back(MakeBidiGdkPoint( + kCornerSize + x_off_l, height + y_off, width, on_left)); + points.push_back(MakeBidiGdkPoint( + x_off_r, height - kCornerSize, width, on_left)); + + return points; +} + +BubbleGtk::ArrowLocationGtk BubbleGtk::GetArrowLocation( + ArrowLocationGtk preferred_location, + int arrow_x, + int width) { + bool wants_left = (preferred_location == ARROW_LOCATION_TOP_LEFT); + int screen_width = gdk_screen_get_width(gdk_screen_get_default()); + + bool left_is_onscreen = (arrow_x - kArrowX + width < screen_width); + bool right_is_onscreen = (arrow_x + kArrowX - width >= 0); + + // Use the requested location if it fits onscreen, use whatever fits + // otherwise, and use the requested location if neither fits. + if (left_is_onscreen && (wants_left || !right_is_onscreen)) + return ARROW_LOCATION_TOP_LEFT; + if (right_is_onscreen && (!wants_left || !left_is_onscreen)) + return ARROW_LOCATION_TOP_RIGHT; + return (wants_left ? ARROW_LOCATION_TOP_LEFT : ARROW_LOCATION_TOP_RIGHT); +} + +bool BubbleGtk::UpdateArrowLocation(bool force_move_and_reshape) { + 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 + offset_x + (rect_.width() / 2), // arrow_x + window_->allocation.width); + + if (force_move_and_reshape || current_arrow_location_ != old_location) { + UpdateWindowShape(); + MoveWindow(); + // We need to redraw the entire window to repaint its border. + gtk_widget_queue_draw(window_); + return true; + } + return false; +} + +void BubbleGtk::UpdateWindowShape() { + if (mask_region_) { + gdk_region_destroy(mask_region_); + mask_region_ = NULL; + } + std::vector points = MakeFramePolygonPoints( + current_arrow_location_, + window_->allocation.width, window_->allocation.height, + FRAME_MASK); + mask_region_ = gdk_region_polygon(&points[0], + points.size(), + GDK_EVEN_ODD_RULE); + gdk_window_shape_combine_region(window_->window, NULL, 0, 0); + gdk_window_shape_combine_region(window_->window, mask_region_, 0, 0); +} + +void BubbleGtk::MoveWindow() { + 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 + offset_x + (rect_.width() / 2) - kArrowX; + } else if (current_arrow_location_ == ARROW_LOCATION_TOP_RIGHT) { + screen_x = toplevel_x + offset_x + (rect_.width() / 2) - + window_->allocation.width + kArrowX; + } else { + NOTREACHED(); + } + + gint screen_y = toplevel_y + offset_y + rect_.height() + + kArrowToContentPadding; + + gtk_window_move(GTK_WINDOW(window_), screen_x, screen_y); +} + +void BubbleGtk::StackWindow() { + // Stack our window directly above the toplevel window. + if (toplevel_window_) + ui::StackPopupWindow(window_, GTK_WIDGET(toplevel_window_)); +} + +void BubbleGtk::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + DCHECK_EQ(type.value, NotificationType::BROWSER_THEME_CHANGED); + if (theme_service_->UseGtkTheme() && match_system_theme_) { + gtk_widget_modify_bg(window_, GTK_STATE_NORMAL, NULL); + } else { + // Set the background color, so we don't need to paint it manually. + gtk_widget_modify_bg(window_, GTK_STATE_NORMAL, &kBackgroundColor); + } +} + +void BubbleGtk::HandlePointerAndKeyboardUngrabbedByContent() { + if (grab_input_) + GrabPointerAndKeyboard(); +} + +void BubbleGtk::Close() { + // We don't need to ungrab the pointer or keyboard here; the X server will + // automatically do that when we destroy our window. + DCHECK(window_); + gtk_widget_destroy(window_); + // |this| has been deleted, see OnDestroy. +} + +void BubbleGtk::GrabPointerAndKeyboard() { + // Install X pointer and keyboard grabs to make sure that we have the focus + // and get all mouse and keyboard events until we're closed. + GdkGrabStatus pointer_grab_status = + gdk_pointer_grab(window_->window, + TRUE, // owner_events + GDK_BUTTON_PRESS_MASK, // event_mask + NULL, // confine_to + NULL, // cursor + GDK_CURRENT_TIME); + if (pointer_grab_status != GDK_GRAB_SUCCESS) { + // This will fail if someone else already has the pointer grabbed, but + // there's not really anything we can do about that. + DLOG(ERROR) << "Unable to grab pointer (status=" + << pointer_grab_status << ")"; + } + GdkGrabStatus keyboard_grab_status = + gdk_keyboard_grab(window_->window, + FALSE, // owner_events + GDK_CURRENT_TIME); + if (keyboard_grab_status != GDK_GRAB_SUCCESS) { + DLOG(ERROR) << "Unable to grab keyboard (status=" + << keyboard_grab_status << ")"; + } +} + +gboolean BubbleGtk::OnGtkAccelerator(GtkAccelGroup* group, + GObject* acceleratable, + guint keyval, + GdkModifierType modifier) { + GdkEventKey msg; + GdkKeymapKey* keys; + gint n_keys; + + switch (keyval) { + case GDK_Escape: + // Close on Esc and trap the accelerator + closed_by_escape_ = true; + Close(); + return TRUE; + case GDK_w: + // Close on C-w and forward the accelerator + if (modifier & GDK_CONTROL_MASK) { + Close(); + } + break; + default: + return FALSE; + } + + gdk_keymap_get_entries_for_keyval(NULL, + keyval, + &keys, + &n_keys); + if (n_keys) { + // Forward the accelerator to root window the bubble is anchored + // to for further processing + msg.type = GDK_KEY_PRESS; + msg.window = GTK_WIDGET(toplevel_window_)->window; + msg.send_event = TRUE; + msg.time = GDK_CURRENT_TIME; + msg.state = modifier | GDK_MOD2_MASK; + msg.keyval = keyval; + // length and string are deprecated and thus zeroed out + msg.length = 0; + msg.string = NULL; + msg.hardware_keycode = keys[0].keycode; + msg.group = keys[0].group; + msg.is_modifier = 0; + + g_free(keys); + + gtk_main_do_event(reinterpret_cast(&msg)); + } else { + // This means that there isn't a h/w code for the keyval in the + // current keymap, which is weird but possible if the keymap just + // changed. This isn't a critical error, but might be indicative + // of something off if it happens regularly. + DLOG(WARNING) << "Found no keys for value " << keyval; + } + return TRUE; +} + +gboolean BubbleGtk::OnExpose(GtkWidget* widget, GdkEventExpose* expose) { + GdkDrawable* drawable = GDK_DRAWABLE(window_->window); + GdkGC* gc = gdk_gc_new(drawable); + gdk_gc_set_rgb_fg_color(gc, &kFrameColor); + + // Stroke the frame border. + std::vector points = MakeFramePolygonPoints( + current_arrow_location_, + window_->allocation.width, window_->allocation.height, + FRAME_STROKE); + gdk_draw_polygon(drawable, gc, FALSE, &points[0], points.size()); + + g_object_unref(gc); + return FALSE; // Propagate so our children paint, etc. +} + +// When our size is initially allocated or changed, we need to recompute +// and apply our shape mask region. +void BubbleGtk::OnSizeAllocate(GtkWidget* widget, + GtkAllocation* allocation) { + if (!UpdateArrowLocation(false)) { + UpdateWindowShape(); + if (current_arrow_location_ == ARROW_LOCATION_TOP_RIGHT) + MoveWindow(); + } +} + +gboolean BubbleGtk::OnButtonPress(GtkWidget* widget, + GdkEventButton* event) { + // If we got a click in our own window, that's okay (we need to additionally + // check that it falls within our bounds, since we've grabbed the pointer and + // some events that actually occurred in other windows will be reported with + // respect to our window). + if (event->window == window_->window && + (mask_region_ && gdk_region_point_in(mask_region_, event->x, event->y))) { + return FALSE; // Propagate. + } + + // Our content widget got a click. + if (event->window != window_->window && + gdk_window_get_toplevel(event->window) == window_->window) { + return FALSE; + } + + if (grab_input_) { + // Otherwise we had a click outside of our window, close ourself. + Close(); + return TRUE; + } + + return FALSE; +} + +gboolean BubbleGtk::OnDestroy(GtkWidget* widget) { + // We are self deleting, we have a destroy signal setup to catch when we + // destroy the widget manually, or the window was closed via X. This will + // delete the BubbleGtk object. + delete this; + return FALSE; // Propagate. +} + +void BubbleGtk::OnHide(GtkWidget* widget) { + gtk_widget_destroy(widget); +} + +gboolean BubbleGtk::OnToplevelConfigure(GtkWidget* widget, + GdkEventConfigure* event) { + if (!UpdateArrowLocation(false)) + MoveWindow(); + StackWindow(); + return FALSE; +} + +gboolean BubbleGtk::OnToplevelUnmap(GtkWidget* widget, GdkEvent* event) { + Close(); + return FALSE; +} + +void BubbleGtk::OnAnchorAllocate(GtkWidget* widget, + GtkAllocation* allocation) { + if (!UpdateArrowLocation(false)) + MoveWindow(); +} diff --git a/chrome/browser/ui/gtk/bubble/bubble_gtk.h b/chrome/browser/ui/gtk/bubble/bubble_gtk.h new file mode 100644 index 0000000..dc7c5a5 --- /dev/null +++ b/chrome/browser/ui/gtk/bubble/bubble_gtk.h @@ -0,0 +1,216 @@ +// Copyright (c) 2011 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_UI_GTK_BUBBLE_BUBBLE_GTK_H_ +#define CHROME_BROWSER_UI_GTK_BUBBLE_BUBBLE_GTK_H_ +#pragma once + +#include + +#include + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "content/common/notification_observer.h" +#include "content/common/notification_registrar.h" +#include "ui/base/gtk/gtk_signal.h" +#include "ui/base/gtk/gtk_signal_registrar.h" +#include "ui/gfx/point.h" +#include "ui/gfx/rect.h" + +class BubbleGtk; +class GtkThemeService; + +namespace gfx { +class Rect; +} + +class BubbleDelegateGtk { + public: + // Called when the bubble is closing and is about to be deleted. + // |closed_by_escape| is true if the close is the result of pressing escape. + virtual void BubbleClosing(BubbleGtk* bubble, bool closed_by_escape) = 0; + + // NOTE: The Views interface has CloseOnEscape, except I can't find a place + // where it ever returns false, so we always allow you to close via escape. + + protected: + virtual ~BubbleDelegateGtk() {} +}; + +// This is the GTK implementation of Bubbles. Bubbles are like dialogs, but they +// point to a given element on the screen. You should call BubbleGtk::Show, +// which will create and display a bubble. The object is self deleting, when the +// bubble is closed, you will be notified via +// BubbleDelegateGtk::BubbleClosing(). Then the widgets and the underlying +// object will be destroyed. You can also close and destroy the bubble by +// calling Close(). +class BubbleGtk : public NotificationObserver { + public: + // Where should the arrow be placed relative to the bubble? + enum ArrowLocationGtk { + // TODO(derat): Support placing arrows on the bottoms of the bubbles. + ARROW_LOCATION_TOP_LEFT, + ARROW_LOCATION_TOP_RIGHT, + }; + + // Show a bubble, pointing at the area |rect| (in coordinates relative to + // |anchor_widget|'s origin). A 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 BubbleGtk* Show(GtkWidget* anchor_widget, + const gfx::Rect* rect, + GtkWidget* content, + ArrowLocationGtk arrow_location, + bool match_system_theme, + bool grab_input, + GtkThemeService* provider, + BubbleDelegateGtk* delegate); + + // Close the bubble if it's open. This will delete the widgets and object, + // so you shouldn't hold a BubbleGtk pointer after calling Close(). + void Close(); + + // NotificationObserver implementation. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) OVERRIDE; + + // If the content contains widgets that can steal our pointer and keyboard + // grabs (e.g. GtkComboBox), this method should be called after a widget + // releases the grabs so we can reacquire them. Note that this causes a race + // condition; another client could grab them before we do (ideally, GDK would + // transfer the grabs back to us when the widget releases them). The window + // is small, though, and the worst-case scenario for this seems to just be + // that the content's widgets will appear inactive even after the user clicks + // in them. + void HandlePointerAndKeyboardUngrabbedByContent(); + + private: + enum FrameType { + FRAME_MASK, + FRAME_STROKE, + }; + + explicit BubbleGtk(GtkThemeService* provider, bool match_system_theme); + virtual ~BubbleGtk(); + + // Creates the Bubble. + void Init(GtkWidget* anchor_widget, + const gfx::Rect* rect, + GtkWidget* content, + ArrowLocationGtk arrow_location, + bool grab_input); + + // Make the points for our polygon frame, either for fill (the mask), or for + // when we stroke the border. + static std::vector MakeFramePolygonPoints( + ArrowLocationGtk arrow_location, + int width, + int height, + FrameType type); + + // Get the location where the arrow should be placed (which is a function of + // the preferred location and of the direction that the bubble should be + // facing to fit onscreen). |arrow_x| is the X component in screen + // coordinates of the point at which the bubble's arrow should be aimed, and + // |width| is the bubble's width. + static ArrowLocationGtk GetArrowLocation( + ArrowLocationGtk preferred_location, int arrow_x, int width); + + // Updates |arrow_location_| based on the toplevel window's current position + // and the bubble's size. If the |force_move_and_reshape| is true or the + // location changes, moves and reshapes the window and returns true. + bool UpdateArrowLocation(bool force_move_and_reshape); + + // Reshapes the window and updates |mask_region_|. + void UpdateWindowShape(); + + // Calculate the current screen position for the bubble's window (per + // |toplevel_window_|'s position as of its most-recent ConfigureNotify event + // and |rect_|) and move it there. + void MoveWindow(); + + // Restack the bubble's window directly above |toplevel_window_|. + void StackWindow(); + + // Sets the delegate. + void set_delegate(BubbleDelegateGtk* delegate) { delegate_ = delegate; } + + // Grab (in the X sense) the pointer and keyboard. This is needed to make + // sure that we have the input focus. + void GrabPointerAndKeyboard(); + + CHROMEG_CALLBACK_3(BubbleGtk, gboolean, OnGtkAccelerator, GtkAccelGroup*, + GObject*, guint, GdkModifierType); + + CHROMEGTK_CALLBACK_1(BubbleGtk, gboolean, OnExpose, GdkEventExpose*); + CHROMEGTK_CALLBACK_1(BubbleGtk, void, OnSizeAllocate, GtkAllocation*); + CHROMEGTK_CALLBACK_1(BubbleGtk, gboolean, OnButtonPress, GdkEventButton*); + CHROMEGTK_CALLBACK_0(BubbleGtk, gboolean, OnDestroy); + CHROMEGTK_CALLBACK_0(BubbleGtk, void, OnHide); + CHROMEGTK_CALLBACK_1(BubbleGtk, gboolean, OnToplevelConfigure, + GdkEventConfigure*); + CHROMEGTK_CALLBACK_1(BubbleGtk, gboolean, OnToplevelUnmap, GdkEvent*); + CHROMEGTK_CALLBACK_1(BubbleGtk, void, OnAnchorAllocate, GtkAllocation*); + + // The caller supplied delegate, can be NULL. + BubbleDelegateGtk* delegate_; + + // Our GtkWindow popup window, we don't technically "own" the widget, since + // it deletes us when it is destroyed. + GtkWidget* window_; + + // Provides colors and stuff. + GtkThemeService* theme_service_; + + // The accel group attached to |window_|, to handle closing with escape. + GtkAccelGroup* accel_group_; + + // The window for which we're being shown (and to which |rect_| is relative). + // Note that it's possible for |toplevel_window_| to be NULL if the + // window is destroyed before this object is destroyed, so it's important + // to check for that case. + GtkWindow* toplevel_window_; + + // 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_; + + // The current shape of |window_| (used to test whether clicks fall in it or + // not). + GdkRegion* mask_region_; + + // Where would we prefer for the arrow be drawn relative to the bubble, and + // where is it currently drawn? + ArrowLocationGtk preferred_arrow_location_; + ArrowLocationGtk current_arrow_location_; + + // Whether the background should match the system theme, when the system theme + // is being used. For example, the bookmark bubble does, but extension popups + // do not. + bool match_system_theme_; + + // If true, the popup owns all X input for the duration of its existence. + // This will usually be true, the exception being when inspecting extension + // popups with dev tools. + bool grab_input_; + + bool closed_by_escape_; + + NotificationRegistrar registrar_; + + ui::GtkSignalRegistrar signals_; + + DISALLOW_COPY_AND_ASSIGN(BubbleGtk); +}; + +#endif // CHROME_BROWSER_UI_GTK_BUBBLE_BUBBLE_GTK_H_ diff --git a/chrome/browser/ui/gtk/content_setting_bubble_gtk.cc b/chrome/browser/ui/gtk/content_setting_bubble_gtk.cc index c26e345..a134e80 100644 --- a/chrome/browser/ui/gtk/content_setting_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/content_setting_bubble_gtk.cc @@ -30,7 +30,7 @@ namespace { -// Padding between content and edge of info bubble. +// Padding between content and edge of bubble. const int kContentBorder = 7; // The maximum width of a title entry in the content box. We elide anything @@ -49,7 +49,7 @@ std::string BuildElidedText(const std::string& input) { ContentSettingBubbleGtk::ContentSettingBubbleGtk( GtkWidget* anchor, - InfoBubbleGtkDelegate* delegate, + BubbleDelegateGtk* delegate, ContentSettingBubbleModel* content_setting_bubble_model, Profile* profile, TabContents* tab_contents) @@ -58,7 +58,7 @@ ContentSettingBubbleGtk::ContentSettingBubbleGtk( tab_contents_(tab_contents), delegate_(delegate), content_setting_bubble_model_(content_setting_bubble_model), - info_bubble_(NULL) { + bubble_(NULL) { registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED, Source(tab_contents)); BuildBubble(); @@ -68,13 +68,13 @@ ContentSettingBubbleGtk::~ContentSettingBubbleGtk() { } void ContentSettingBubbleGtk::Close() { - if (info_bubble_) - info_bubble_->Close(); + if (bubble_) + bubble_->Close(); } -void ContentSettingBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble, - bool closed_by_escape) { - delegate_->InfoBubbleClosing(info_bubble, closed_by_escape); +void ContentSettingBubbleGtk::BubbleClosing(BubbleGtk* bubble, + bool closed_by_escape) { + delegate_->BubbleClosing(bubble, closed_by_escape); delete this; } @@ -252,19 +252,18 @@ void ContentSettingBubbleGtk::BuildBubble() { gtk_widget_grab_focus(bottom_box); gtk_widget_grab_focus(button); - InfoBubbleGtk::ArrowLocationGtk arrow_location = + BubbleGtk::ArrowLocationGtk arrow_location = !base::i18n::IsRTL() ? - InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT : - InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT; - info_bubble_ = InfoBubbleGtk::Show( - anchor_, - NULL, - bubble_content, - arrow_location, - true, // match_system_theme - true, // grab_input - theme_provider, - this); + BubbleGtk::ARROW_LOCATION_TOP_RIGHT : + BubbleGtk::ARROW_LOCATION_TOP_LEFT; + bubble_ = BubbleGtk::Show(anchor_, + NULL, + bubble_content, + arrow_location, + true, // match_system_theme + true, // grab_input + theme_provider, + this); } void ContentSettingBubbleGtk::OnPopupIconButtonPress( diff --git a/chrome/browser/ui/gtk/content_setting_bubble_gtk.h b/chrome/browser/ui/gtk/content_setting_bubble_gtk.h index b400590..e8b8f19 100644 --- a/chrome/browser/ui/gtk/content_setting_bubble_gtk.h +++ b/chrome/browser/ui/gtk/content_setting_bubble_gtk.h @@ -8,8 +8,9 @@ #include +#include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" -#include "chrome/browser/ui/gtk/info_bubble_gtk.h" +#include "chrome/browser/ui/gtk/bubble/bubble_gtk.h" #include "chrome/common/content_settings_types.h" #include "content/common/notification_observer.h" #include "content/common/notification_registrar.h" @@ -23,32 +24,31 @@ 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. -class ContentSettingBubbleGtk : public InfoBubbleGtkDelegate, +class ContentSettingBubbleGtk : public BubbleDelegateGtk, public NotificationObserver { public: ContentSettingBubbleGtk( GtkWidget* anchor, - InfoBubbleGtkDelegate* delegate, + BubbleDelegateGtk* delegate, ContentSettingBubbleModel* content_setting_bubble_model, Profile* profile, TabContents* tab_contents); virtual ~ContentSettingBubbleGtk(); - // Dismisses the infobubble. + // Dismisses the bubble. void Close(); private: typedef std::map PopupMap; - // InfoBubbleGtkDelegate: - virtual void InfoBubbleClosing(InfoBubbleGtk* info_bubble, - bool closed_by_escape); + // BubbleDelegateGtk: + virtual void BubbleClosing(BubbleGtk* bubble, bool closed_by_escape) OVERRIDE; // NotificationObserver: virtual void Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details); - // Builds the info bubble and all the widgets that it displays. + // Builds the bubble and all the widgets that it displays. void BuildBubble(); // Widget callback methods. @@ -73,13 +73,13 @@ class ContentSettingBubbleGtk : public InfoBubbleGtkDelegate, NotificationRegistrar registrar_; // Pass on delegate messages to this. - InfoBubbleGtkDelegate* delegate_; + BubbleDelegateGtk* delegate_; // Provides data for this bubble. scoped_ptr content_setting_bubble_model_; - // The info bubble. - InfoBubbleGtk* info_bubble_; + // The bubble. + BubbleGtk* bubble_; // Stored controls so we can figure out what was clicked. PopupMap popup_links_; diff --git a/chrome/browser/ui/gtk/extensions/extension_installed_bubble_gtk.cc b/chrome/browser/ui/gtk/extensions/extension_installed_bubble_gtk.cc index 1892a0d..767e4a8 100644 --- a/chrome/browser/ui/gtk/extensions/extension_installed_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/extensions/extension_installed_bubble_gtk.cc @@ -42,7 +42,7 @@ const int kTextColumnWidth = 350; const int kAnimationWaitRetries = 10; const int kAnimationWaitMS = 50; -// Padding between content and edge of info bubble. +// Padding between content and edge of bubble. const int kContentBorder = 7; } // namespace @@ -174,7 +174,7 @@ void ExtensionInstalledBubbleGtk::ShowInternal() { GtkThemeService* theme_provider = GtkThemeService::GetFrom( browser_->profile()); - // Setup the InfoBubble content. + // Setup the BubbleGtk content. GtkWidget* bubble_content = gtk_hbox_new(FALSE, kHorizontalColumnSpacing); gtk_container_set_border_width(GTK_CONTAINER(bubble_content), kContentBorder); @@ -199,7 +199,7 @@ void ExtensionInstalledBubbleGtk::ShowInternal() { // Put Icon in top of the left column. GtkWidget* icon_column = gtk_vbox_new(FALSE, 0); - // Use 3 pixel padding to get visual balance with InfoBubble border on the + // Use 3 pixel padding to get visual balance with BubbleGtk border on the // left. gtk_box_pack_start(GTK_BOX(bubble_content), icon_column, FALSE, FALSE, kIconPadding); @@ -258,10 +258,10 @@ void ExtensionInstalledBubbleGtk::ShowInternal() { gtk_box_pack_start(GTK_BOX(close_column), close_button_->widget(), FALSE, FALSE, 0); - InfoBubbleGtk::ArrowLocationGtk arrow_location = + BubbleGtk::ArrowLocationGtk arrow_location = !base::i18n::IsRTL() ? - InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT : - InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT; + BubbleGtk::ARROW_LOCATION_TOP_RIGHT : + BubbleGtk::ARROW_LOCATION_TOP_LEFT; gfx::Rect bounds = gtk_util::WidgetBounds(reference_widget); if (type_ == OMNIBOX_KEYWORD) { @@ -270,35 +270,34 @@ void ExtensionInstalledBubbleGtk::ShowInternal() { // the popup on the URL bar. arrow_location = !base::i18n::IsRTL() ? - InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT : - InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT; + BubbleGtk::ARROW_LOCATION_TOP_LEFT : + BubbleGtk::ARROW_LOCATION_TOP_RIGHT; if (base::i18n::IsRTL()) bounds.Offset(bounds.width(), 0); bounds.set_width(0); } - info_bubble_ = InfoBubbleGtk::Show(reference_widget, - &bounds, - bubble_content, - arrow_location, - true, // match_system_theme - true, // grab_input - theme_provider, - this); + bubble_ = BubbleGtk::Show(reference_widget, + &bounds, + bubble_content, + arrow_location, + true, // match_system_theme + true, // grab_input + theme_provider, + this); } // static void ExtensionInstalledBubbleGtk::OnButtonClick(GtkWidget* button, ExtensionInstalledBubbleGtk* bubble) { if (button == bubble->close_button_->widget()) { - bubble->info_bubble_->Close(); + bubble->bubble_->Close(); } else { NOTREACHED(); } } -// InfoBubbleDelegate -void ExtensionInstalledBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble, - bool closed_by_escape) { +void ExtensionInstalledBubbleGtk::BubbleClosing(BubbleGtk* bubble, + bool closed_by_escape) { if (extension_ && type_ == PAGE_ACTION) { // Turn the page action preview off. BrowserWindowGtk* browser_window = @@ -310,7 +309,7 @@ void ExtensionInstalledBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble, false); // preview_enabled } - // We need to allow the info bubble to close and remove the widgets from + // We need to allow the bubble to close and remove the widgets from // the window before we call Release() because close_button_ depends // on all references being cleared before it is destroyed. MessageLoopForUI::current()->PostTask(FROM_HERE, NewRunnableMethod(this, @@ -319,5 +318,5 @@ void ExtensionInstalledBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble, void ExtensionInstalledBubbleGtk::Close() { Release(); // Balanced in ctor. - info_bubble_ = NULL; + bubble_ = NULL; } diff --git a/chrome/browser/ui/gtk/extensions/extension_installed_bubble_gtk.h b/chrome/browser/ui/gtk/extensions/extension_installed_bubble_gtk.h index 1b83e68..fa943be 100644 --- a/chrome/browser/ui/gtk/extensions/extension_installed_bubble_gtk.h +++ b/chrome/browser/ui/gtk/extensions/extension_installed_bubble_gtk.h @@ -6,10 +6,11 @@ #define CHROME_BROWSER_UI_GTK_EXTENSIONS_EXTENSION_INSTALLED_BUBBLE_GTK_H_ #pragma once +#include "base/compiler_specific.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "chrome/browser/ui/gtk/bubble/bubble_gtk.h" #include "chrome/browser/ui/gtk/custom_button.h" -#include "chrome/browser/ui/gtk/info_bubble_gtk.h" #include "content/common/notification_observer.h" #include "content/common/notification_registrar.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -20,22 +21,22 @@ class Extension; class SkBitmap; // Provides feedback to the user upon successful installation of an -// extension. Depending on the type of extension, the InfoBubble will +// extension. Depending on the type of extension, the BubbleGtk will // point to: // OMNIBOX_KEYWORD-> The omnibox. // BROWSER_ACTION -> The browserAction icon in the toolbar. // PAGE_ACTION -> A preview of the page action icon in the location -// bar which is shown while the InfoBubble is shown. +// bar which is shown while the BubbleGtk is shown. // GENERIC -> The wrench menu. This case includes page actions that // don't specify a default icon. // // ExtensionInstallBubble manages its own lifetime. class ExtensionInstalledBubbleGtk - : public InfoBubbleGtkDelegate, + : public BubbleDelegateGtk, public NotificationObserver, public base::RefCountedThreadSafe { public: - // The behavior and content of this InfoBubble comes in three varieties. + // The behavior and content of this BubbleGtk comes in three varieties. enum BubbleType { OMNIBOX_KEYWORD, BROWSER_ACTION, @@ -62,14 +63,13 @@ class ExtensionInstalledBubbleGtk // Shows the bubble. Called internally via PostTask. void ShowInternal(); - // NotificationObserver + // NotificationObserver: virtual void Observe(NotificationType type, const NotificationSource& source, - const NotificationDetails& details); + const NotificationDetails& details) OVERRIDE; - // InfoBubbleDelegate - virtual void InfoBubbleClosing(InfoBubbleGtk* info_bubble, - bool closed_by_escape); + // BubbleDelegateGtk: + virtual void BubbleClosing(BubbleGtk* bubble, bool closed_by_escape) OVERRIDE; // Calls Release() internally. Called internally via PostTask. void Close(); @@ -87,10 +87,10 @@ class ExtensionInstalledBubbleGtk // toolbar is animating. int animation_wait_retries_; - // The 'x' that the user can press to hide the info bubble shelf. + // The 'x' that the user can press to hide the bubble shelf. scoped_ptr close_button_; - InfoBubbleGtk* info_bubble_; + BubbleGtk* bubble_; DISALLOW_COPY_AND_ASSIGN(ExtensionInstalledBubbleGtk); }; diff --git a/chrome/browser/ui/gtk/extensions/extension_popup_gtk.cc b/chrome/browser/ui/gtk/extensions/extension_popup_gtk.cc index 6214a63..ccd4979 100644 --- a/chrome/browser/ui/gtk/extensions/extension_popup_gtk.cc +++ b/chrome/browser/ui/gtk/extensions/extension_popup_gtk.cc @@ -114,18 +114,18 @@ void ExtensionPopupGtk::ShowPopup() { // We'll be in the upper-right corner of the window for LTR languages, so we // want to put the arrow at the upper-right corner of the bubble to match the // page and app menus. - InfoBubbleGtk::ArrowLocationGtk arrow_location = + BubbleGtk::ArrowLocationGtk arrow_location = !base::i18n::IsRTL() ? - InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT : - InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT; - bubble_ = InfoBubbleGtk::Show(anchor_, - NULL, - host_->view()->native_view(), - arrow_location, - false, // match_system_theme - !being_inspected_, // grab_input - GtkThemeService::GetFrom(browser_->profile()), - this); + BubbleGtk::ARROW_LOCATION_TOP_RIGHT : + BubbleGtk::ARROW_LOCATION_TOP_LEFT; + bubble_ = BubbleGtk::Show(anchor_, + NULL, + host_->view()->native_view(), + arrow_location, + false, // match_system_theme + !being_inspected_, // grab_input + GtkThemeService::GetFrom(browser_->profile()), + this); } bool ExtensionPopupGtk::DestroyPopup() { @@ -138,8 +138,8 @@ bool ExtensionPopupGtk::DestroyPopup() { return true; } -void ExtensionPopupGtk::InfoBubbleClosing(InfoBubbleGtk* bubble, - bool closed_by_escape) { +void ExtensionPopupGtk::BubbleClosing(BubbleGtk* bubble, + bool closed_by_escape) { current_extension_popup_ = NULL; delete this; } @@ -164,7 +164,7 @@ void ExtensionPopupGtk::Show(const GURL& url, Browser* browser, return; ExtensionHost* host = manager->CreatePopup(url, browser); - // This object will delete itself when the info bubble is closed. + // This object will delete itself when the bubble is closed. new ExtensionPopupGtk(browser, host, anchor, inspect); } diff --git a/chrome/browser/ui/gtk/extensions/extension_popup_gtk.h b/chrome/browser/ui/gtk/extensions/extension_popup_gtk.h index fa0d0c9..926bb2e 100644 --- a/chrome/browser/ui/gtk/extensions/extension_popup_gtk.h +++ b/chrome/browser/ui/gtk/extensions/extension_popup_gtk.h @@ -6,10 +6,11 @@ #define CHROME_BROWSER_UI_GTK_EXTENSIONS_EXTENSION_POPUP_GTK_H_ #pragma once +#include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" #include "base/task.h" +#include "chrome/browser/ui/gtk/bubble/bubble_gtk.h" #include "chrome/browser/ui/gtk/extensions/extension_view_gtk.h" -#include "chrome/browser/ui/gtk/info_bubble_gtk.h" #include "content/common/notification_observer.h" #include "content/common/notification_registrar.h" #include "ui/gfx/rect.h" @@ -19,7 +20,7 @@ class ExtensionHost; class GURL; class ExtensionPopupGtk : public NotificationObserver, - public InfoBubbleGtkDelegate, + public BubbleDelegateGtk, public ExtensionViewGtk::Container { public: ExtensionPopupGtk(Browser* browser, @@ -36,18 +37,18 @@ class ExtensionPopupGtk : public NotificationObserver, // NotificationObserver implementation. virtual void Observe(NotificationType type, const NotificationSource& source, - const NotificationDetails& details); + const NotificationDetails& details) OVERRIDE; - // InfoBubbleGtkDelegate implementation. - virtual void InfoBubbleClosing(InfoBubbleGtk* bubble, - bool closed_by_escape); + // BubbleDelegateGtk implementation. + virtual void BubbleClosing(BubbleGtk* bubble, + bool closed_by_escape) OVERRIDE; - // ExtensionViewGtk::Container implementation + // ExtensionViewGtk::Container implementation. virtual void OnExtensionPreferredSizeChanged(ExtensionViewGtk* view, const gfx::Size& new_size); // Destroys the popup widget. This will in turn destroy us since we delete - // ourselves when the info bubble closes. Returns true if we successfully + // ourselves when the bubble closes. Returns true if we successfully // closed the bubble. bool DestroyPopup(); @@ -72,12 +73,12 @@ class ExtensionPopupGtk : public NotificationObserver, Browser* browser_; - InfoBubbleGtk* bubble_; + BubbleGtk* bubble_; // We take ownership of the popup ExtensionHost. scoped_ptr host_; - // The widget for anchoring the position of the info bubble. + // The widget for anchoring the position of the bubble. GtkWidget* anchor_; NotificationRegistrar registrar_; diff --git a/chrome/browser/ui/gtk/first_run_bubble.cc b/chrome/browser/ui/gtk/first_run_bubble.cc index cf86e44..d00824b 100644 --- a/chrome/browser/ui/gtk/first_run_bubble.cc +++ b/chrome/browser/ui/gtk/first_run_bubble.cc @@ -27,7 +27,7 @@ const char kSearchLabelMarkup[] = "%s"; // Padding for the buttons on first run bubble. const int kButtonPadding = 4; -// Padding between content and edge of info bubble. +// Padding between content and edge of bubble. const int kContentBorder = 7; // Vertical spacing between labels. @@ -43,15 +43,11 @@ void FirstRunBubble::Show(Profile* profile, new FirstRunBubble(profile, anchor, rect, bubble_type); } -void FirstRunBubble::InfoBubbleClosing(InfoBubbleGtk* info_bubble, - bool closed_by_escape) { +void FirstRunBubble::BubbleClosing(BubbleGtk* bubble, + bool closed_by_escape) { // TODO(port): Enable parent window } -bool FirstRunBubble::CloseOnEscape() { - return true; -} - void FirstRunBubble::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { @@ -100,18 +96,18 @@ FirstRunBubble::FirstRunBubble(Profile* profile, InitializeLabels(width_resource); - InfoBubbleGtk::ArrowLocationGtk arrow_location = + BubbleGtk::ArrowLocationGtk arrow_location = !base::i18n::IsRTL() ? - InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT : - InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT; - bubble_ = InfoBubbleGtk::Show(anchor_, - &rect, - content_, - arrow_location, - true, // match_system_theme - true, // grab_input - theme_service_, - this); // delegate + BubbleGtk::ARROW_LOCATION_TOP_LEFT : + BubbleGtk::ARROW_LOCATION_TOP_RIGHT; + bubble_ = BubbleGtk::Show(anchor_, + &rect, + content_, + arrow_location, + true, // match_system_theme + true, // grab_input + theme_service_, + this); // delegate if (!bubble_) { NOTREACHED(); return; diff --git a/chrome/browser/ui/gtk/first_run_bubble.h b/chrome/browser/ui/gtk/first_run_bubble.h index 7e774de..bfd1754 100644 --- a/chrome/browser/ui/gtk/first_run_bubble.h +++ b/chrome/browser/ui/gtk/first_run_bubble.h @@ -15,14 +15,15 @@ #include #include "base/basictypes.h" +#include "base/compiler_specific.h" #include "chrome/browser/first_run/first_run.h" -#include "chrome/browser/ui/gtk/info_bubble_gtk.h" +#include "chrome/browser/ui/gtk/bubble/bubble_gtk.h" #include "content/common/notification_observer.h" #include "content/common/notification_registrar.h" class Profile; -class FirstRunBubble : public InfoBubbleGtkDelegate, +class FirstRunBubble : public BubbleDelegateGtk, public NotificationObserver { public: // Shows the first run bubble, pointing at |rect|. @@ -31,16 +32,13 @@ class FirstRunBubble : public InfoBubbleGtkDelegate, const gfx::Rect& rect, FirstRun::BubbleType bubble_type); - // Implements the InfoBubbleGtkDelegate. We are notified when the bubble - // is about to be closed. - virtual void InfoBubbleClosing(InfoBubbleGtk* info_bubble, - bool closed_by_escape); - virtual bool CloseOnEscape(); + // Overridden from BubbleDelegateGtk: + virtual void BubbleClosing(BubbleGtk* bubble, bool closed_by_escape) OVERRIDE; // Overridden from NotificationObserver: virtual void Observe(NotificationType type, const NotificationSource& source, - const NotificationDetails& details); + const NotificationDetails& details) OVERRIDE; private: FirstRunBubble(Profile* profile, @@ -72,15 +70,15 @@ class FirstRunBubble : public InfoBubbleGtkDelegate, // 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). + // We let the BubbleGtk own our content, and then we delete ourself when the + // widget is destroyed (when the BubbleGtk is destroyed). GtkWidget* content_; // The various labels in the interface. We keep track of them for theme // changes. std::vector labels_; - InfoBubbleGtk* bubble_; + BubbleGtk* bubble_; NotificationRegistrar registrar_; diff --git a/chrome/browser/ui/gtk/info_bubble_accelerators_gtk.cc b/chrome/browser/ui/gtk/info_bubble_accelerators_gtk.cc deleted file mode 100644 index a0a1fb1..0000000 --- a/chrome/browser/ui/gtk/info_bubble_accelerators_gtk.cc +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2011 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/ui/gtk/info_bubble_accelerators_gtk.h" - -#include -#include - -namespace { -// Listing of the accelerators that are either handled or forwarded by -// info bubbles. Any accelerators that are not explicitly listed here -// are ignored and silently dropped. This table is expected to change -// after discussion over which accelerators should be addressed in -// info bubbles. For a complete listing of accelerators that are used -// in chrome consult accelerators_gtk.cc -struct InfoBubbleAcceleratorGtk InfoBubbleAcceleratorGtkTable[] = { - // Tab/window controls. - { GDK_w, GDK_CONTROL_MASK}, - - // Navigation / toolbar buttons. - { GDK_Escape, GdkModifierType(0)} -}; - -} // namespace - -InfoBubbleAcceleratorGtkList InfoBubbleAcceleratorsGtk::GetList() { - InfoBubbleAcceleratorGtkList accelerators; - for (size_t i = 0; i < arraysize(InfoBubbleAcceleratorGtkTable); ++i) { - accelerators.push_back(InfoBubbleAcceleratorGtkTable[i]); - } - - return accelerators; -} diff --git a/chrome/browser/ui/gtk/info_bubble_accelerators_gtk.h b/chrome/browser/ui/gtk/info_bubble_accelerators_gtk.h deleted file mode 100644 index 92c66ef..0000000 --- a/chrome/browser/ui/gtk/info_bubble_accelerators_gtk.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2011 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_UI_GTK_INFO_BUBBLE_ACCELERATORS_GTK_H_ -#define CHROME_BROWSER_UI_GTK_INFO_BUBBLE_ACCELERATORS_GTK_H_ -#pragma once - -#include -#include -#include - -#include "base/basictypes.h" - -struct InfoBubbleAcceleratorGtk { - guint keyval; - GdkModifierType modifier_type; -}; - -typedef std::vector - InfoBubbleAcceleratorGtkList; - -// This class contains a list of accelerators that an InfoBubbleGtk -// is expected to either catch and respond to or catch and forward to the -// root browser window. This list is expected to be a subset of the -// accelerators that are handled by the root browser window, but the -// specific accelerators to be handled has not yet been fully specified. The -// common use case for this class has code that uses it needing the entire -// list and not needing extra processing, so the only get method gives you the -// entire list. -class InfoBubbleAcceleratorsGtk { - public: - static InfoBubbleAcceleratorGtkList GetList(); - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(InfoBubbleAcceleratorsGtk); -}; - -#endif // CHROME_BROWSER_UI_GTK_INFO_BUBBLE_ACCELERATORS_GTK_H_ diff --git a/chrome/browser/ui/gtk/info_bubble_gtk.cc b/chrome/browser/ui/gtk/info_bubble_gtk.cc deleted file mode 100644 index e76d351..0000000 --- a/chrome/browser/ui/gtk/info_bubble_gtk.cc +++ /dev/null @@ -1,536 +0,0 @@ -// Copyright (c) 2011 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/ui/gtk/info_bubble_gtk.h" - -#include -#include - -#include "base/basictypes.h" -#include "base/logging.h" -#include "chrome/browser/ui/gtk/gtk_theme_service.h" -#include "chrome/browser/ui/gtk/gtk_util.h" -#include "chrome/browser/ui/gtk/info_bubble_accelerators_gtk.h" -#include "content/common/notification_service.h" -#include "ui/base/gtk/gtk_windowing.h" -#include "ui/gfx/gtk_util.h" -#include "ui/gfx/path.h" -#include "ui/gfx/rect.h" - -namespace { - -// The height of the arrow, and the width will be about twice the height. -const int kArrowSize = 8; - -// Number of pixels to the middle of the arrow from the close edge of the -// window. -const int kArrowX = 18; - -// Number of pixels between the tip of the arrow and the region we're -// pointing to. -const int kArrowToContentPadding = -4; - -// We draw flat diagonal corners, each corner is an NxN square. -const int kCornerSize = 3; - -// Margins around the content. -const int kTopMargin = kArrowSize + kCornerSize - 1; -const int kBottomMargin = kCornerSize - 1; -const int kLeftMargin = kCornerSize - 1; -const int kRightMargin = kCornerSize - 1; - -const GdkColor kBackgroundColor = GDK_COLOR_RGB(0xff, 0xff, 0xff); -const GdkColor kFrameColor = GDK_COLOR_RGB(0x63, 0x63, 0x63); - -} // namespace - -// static -InfoBubbleGtk* InfoBubbleGtk::Show(GtkWidget* anchor_widget, - const gfx::Rect* rect, - GtkWidget* content, - ArrowLocationGtk arrow_location, - bool match_system_theme, - bool grab_input, - GtkThemeService* provider, - InfoBubbleGtkDelegate* delegate) { - InfoBubbleGtk* bubble = new InfoBubbleGtk(provider, match_system_theme); - bubble->Init(anchor_widget, rect, content, arrow_location, grab_input); - bubble->set_delegate(delegate); - return bubble; -} - -InfoBubbleGtk::InfoBubbleGtk(GtkThemeService* provider, - bool match_system_theme) - : delegate_(NULL), - window_(NULL), - theme_service_(provider), - accel_group_(gtk_accel_group_new()), - toplevel_window_(NULL), - anchor_widget_(NULL), - mask_region_(NULL), - preferred_arrow_location_(ARROW_LOCATION_TOP_LEFT), - current_arrow_location_(ARROW_LOCATION_TOP_LEFT), - match_system_theme_(match_system_theme), - grab_input_(true), - closed_by_escape_(false) { -} - -InfoBubbleGtk::~InfoBubbleGtk() { - // Notify the delegate that we're about to close. This gives the chance - // to save state / etc from the hosted widget before it's destroyed. - if (delegate_) - delegate_->InfoBubbleClosing(this, closed_by_escape_); - - g_object_unref(accel_group_); - if (mask_region_) - gdk_region_destroy(mask_region_); -} - -void InfoBubbleGtk::Init(GtkWidget* anchor_widget, - const gfx::Rect* rect, - GtkWidget* content, - ArrowLocationGtk arrow_location, - bool grab_input) { - // If there is a current grab widget (menu, other info bubble, etc.), hide it. - GtkWidget* current_grab_widget = gtk_grab_get_current(); - if (current_grab_widget) - gtk_widget_hide(current_grab_widget); - - DCHECK(!window_); - 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; - // Using a TOPLEVEL window may cause placement issues with certain WMs but it - // is necessary to be able to focus the window. - window_ = gtk_window_new(grab_input ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL); - - gtk_widget_set_app_paintable(window_, TRUE); - // Resizing is handled by the program, not user. - gtk_window_set_resizable(GTK_WINDOW(window_), FALSE); - - // Attach all of the accelerators to the bubble. - InfoBubbleAcceleratorGtkList acceleratorList = - InfoBubbleAcceleratorsGtk::GetList(); - for (InfoBubbleAcceleratorGtkList::const_iterator iter = - acceleratorList.begin(); - iter != acceleratorList.end(); - ++iter) { - gtk_accel_group_connect(accel_group_, - iter->keyval, - iter->modifier_type, - GtkAccelFlags(0), - g_cclosure_new(G_CALLBACK(&OnGtkAcceleratorThunk), - this, - NULL)); - } - - gtk_window_add_accel_group(GTK_WINDOW(window_), accel_group_); - - 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_container_add(GTK_CONTAINER(alignment), content); - gtk_container_add(GTK_CONTAINER(window_), alignment); - - // GtkWidget only exposes the bitmap mask interface. Use GDK to more - // efficently mask a GdkRegion. Make sure the window is realized during - // OnSizeAllocate, so the mask can be applied to the GdkWindow. - gtk_widget_realize(window_); - - UpdateArrowLocation(true); // Force move and reshape. - StackWindow(); - - gtk_widget_add_events(window_, GDK_BUTTON_PRESS_MASK); - - signals_.Connect(window_, "expose-event", G_CALLBACK(OnExposeThunk), this); - signals_.Connect(window_, "size-allocate", G_CALLBACK(OnSizeAllocateThunk), - this); - signals_.Connect(window_, "button-press-event", - G_CALLBACK(OnButtonPressThunk), this); - signals_.Connect(window_, "destroy", G_CALLBACK(OnDestroyThunk), this); - signals_.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_)) { - signals_.Connect(anchor_widget_, "size-allocate", - G_CALLBACK(OnAnchorAllocateThunk), this); - signals_.Connect(anchor_widget_, "destroy", - G_CALLBACK(gtk_widget_destroyed), &anchor_widget_); - } - - signals_.Connect(toplevel_window_, "configure-event", - G_CALLBACK(OnToplevelConfigureThunk), this); - signals_.Connect(toplevel_window_, "unmap-event", - G_CALLBACK(OnToplevelUnmapThunk), this); - // Set |toplevel_window_| to NULL if it gets destroyed. - signals_.Connect(toplevel_window_, "destroy", - G_CALLBACK(gtk_widget_destroyed), &toplevel_window_); - - gtk_widget_show_all(window_); - - if (grab_input_) { - gtk_grab_add(window_); - GrabPointerAndKeyboard(); - } - - registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, - NotificationService::AllSources()); - theme_service_->InitThemesFor(this); -} - -// NOTE: This seems a bit overcomplicated, but it requires a bunch of careful -// fudging to get the pixels rasterized exactly where we want them, the arrow to -// have a 1 pixel point, etc. -// TODO(deanm): Windows draws with Skia and uses some PNG images for the -// corners. This is a lot more work, but they get anti-aliasing. -// static -std::vector InfoBubbleGtk::MakeFramePolygonPoints( - ArrowLocationGtk arrow_location, - int width, - int height, - FrameType type) { - using gtk_util::MakeBidiGdkPoint; - std::vector points; - - bool on_left = (arrow_location == ARROW_LOCATION_TOP_LEFT); - - // If we're stroking the frame, we need to offset some of our points by 1 - // pixel. We do this when we draw horizontal lines that are on the bottom or - // when we draw vertical lines that are closer to the end (where "end" is the - // right side for ARROW_LOCATION_TOP_LEFT). - int y_off = (type == FRAME_MASK) ? 0 : -1; - // We use this one for arrows located on the left. - int x_off_l = on_left ? y_off : 0; - // We use this one for RTL. - int x_off_r = !on_left ? -y_off : 0; - - // Top left corner. - points.push_back(MakeBidiGdkPoint( - x_off_r, kArrowSize + kCornerSize - 1, width, on_left)); - points.push_back(MakeBidiGdkPoint( - kCornerSize + x_off_r - 1, kArrowSize, width, on_left)); - - // The arrow. - points.push_back(MakeBidiGdkPoint( - kArrowX - kArrowSize + x_off_r, kArrowSize, width, on_left)); - points.push_back(MakeBidiGdkPoint( - kArrowX + x_off_r, 0, width, on_left)); - points.push_back(MakeBidiGdkPoint( - kArrowX + 1 + x_off_l, 0, width, on_left)); - points.push_back(MakeBidiGdkPoint( - kArrowX + kArrowSize + 1 + x_off_l, kArrowSize, width, on_left)); - - // Top right corner. - points.push_back(MakeBidiGdkPoint( - width - kCornerSize + 1 + x_off_l, kArrowSize, width, on_left)); - points.push_back(MakeBidiGdkPoint( - width + x_off_l, kArrowSize + kCornerSize - 1, width, on_left)); - - // Bottom right corner. - points.push_back(MakeBidiGdkPoint( - width + x_off_l, height - kCornerSize, width, on_left)); - points.push_back(MakeBidiGdkPoint( - width - kCornerSize + x_off_r, height + y_off, width, on_left)); - - // Bottom left corner. - points.push_back(MakeBidiGdkPoint( - kCornerSize + x_off_l, height + y_off, width, on_left)); - points.push_back(MakeBidiGdkPoint( - x_off_r, height - kCornerSize, width, on_left)); - - return points; -} - -InfoBubbleGtk::ArrowLocationGtk InfoBubbleGtk::GetArrowLocation( - ArrowLocationGtk preferred_location, int arrow_x, int width) { - bool wants_left = (preferred_location == ARROW_LOCATION_TOP_LEFT); - int screen_width = gdk_screen_get_width(gdk_screen_get_default()); - - bool left_is_onscreen = (arrow_x - kArrowX + width < screen_width); - bool right_is_onscreen = (arrow_x + kArrowX - width >= 0); - - // Use the requested location if it fits onscreen, use whatever fits - // otherwise, and use the requested location if neither fits. - if (left_is_onscreen && (wants_left || !right_is_onscreen)) - return ARROW_LOCATION_TOP_LEFT; - if (right_is_onscreen && (!wants_left || !left_is_onscreen)) - return ARROW_LOCATION_TOP_RIGHT; - return (wants_left ? ARROW_LOCATION_TOP_LEFT : ARROW_LOCATION_TOP_RIGHT); -} - -bool InfoBubbleGtk::UpdateArrowLocation(bool force_move_and_reshape) { - 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 + offset_x + (rect_.width() / 2), // arrow_x - window_->allocation.width); - - if (force_move_and_reshape || current_arrow_location_ != old_location) { - UpdateWindowShape(); - MoveWindow(); - // We need to redraw the entire window to repaint its border. - gtk_widget_queue_draw(window_); - return true; - } - return false; -} - -void InfoBubbleGtk::UpdateWindowShape() { - if (mask_region_) { - gdk_region_destroy(mask_region_); - mask_region_ = NULL; - } - std::vector points = MakeFramePolygonPoints( - current_arrow_location_, - window_->allocation.width, window_->allocation.height, - FRAME_MASK); - mask_region_ = gdk_region_polygon(&points[0], - points.size(), - GDK_EVEN_ODD_RULE); - gdk_window_shape_combine_region(window_->window, NULL, 0, 0); - gdk_window_shape_combine_region(window_->window, mask_region_, 0, 0); -} - -void InfoBubbleGtk::MoveWindow() { - 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 + offset_x + (rect_.width() / 2) - kArrowX; - } else if (current_arrow_location_ == ARROW_LOCATION_TOP_RIGHT) { - screen_x = toplevel_x + offset_x + (rect_.width() / 2) - - window_->allocation.width + kArrowX; - } else { - NOTREACHED(); - } - - gint screen_y = toplevel_y + offset_y + rect_.height() + - kArrowToContentPadding; - - gtk_window_move(GTK_WINDOW(window_), screen_x, screen_y); -} - -void InfoBubbleGtk::StackWindow() { - // Stack our window directly above the toplevel window. - if (toplevel_window_) - ui::StackPopupWindow(window_, GTK_WIDGET(toplevel_window_)); -} - -void InfoBubbleGtk::Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - DCHECK_EQ(type.value, NotificationType::BROWSER_THEME_CHANGED); - if (theme_service_->UseGtkTheme() && match_system_theme_) { - gtk_widget_modify_bg(window_, GTK_STATE_NORMAL, NULL); - } else { - // Set the background color, so we don't need to paint it manually. - gtk_widget_modify_bg(window_, GTK_STATE_NORMAL, &kBackgroundColor); - } -} - -void InfoBubbleGtk::HandlePointerAndKeyboardUngrabbedByContent() { - if (grab_input_) - GrabPointerAndKeyboard(); -} - -void InfoBubbleGtk::Close() { - // We don't need to ungrab the pointer or keyboard here; the X server will - // automatically do that when we destroy our window. - DCHECK(window_); - gtk_widget_destroy(window_); - // |this| has been deleted, see OnDestroy. -} - -void InfoBubbleGtk::GrabPointerAndKeyboard() { - // Install X pointer and keyboard grabs to make sure that we have the focus - // and get all mouse and keyboard events until we're closed. - GdkGrabStatus pointer_grab_status = - gdk_pointer_grab(window_->window, - TRUE, // owner_events - GDK_BUTTON_PRESS_MASK, // event_mask - NULL, // confine_to - NULL, // cursor - GDK_CURRENT_TIME); - if (pointer_grab_status != GDK_GRAB_SUCCESS) { - // This will fail if someone else already has the pointer grabbed, but - // there's not really anything we can do about that. - DLOG(ERROR) << "Unable to grab pointer (status=" - << pointer_grab_status << ")"; - } - GdkGrabStatus keyboard_grab_status = - gdk_keyboard_grab(window_->window, - FALSE, // owner_events - GDK_CURRENT_TIME); - if (keyboard_grab_status != GDK_GRAB_SUCCESS) { - DLOG(ERROR) << "Unable to grab keyboard (status=" - << keyboard_grab_status << ")"; - } -} - -gboolean InfoBubbleGtk::OnGtkAccelerator(GtkAccelGroup* group, - GObject* acceleratable, - guint keyval, - GdkModifierType modifier) { - GdkEventKey msg; - GdkKeymapKey* keys; - gint n_keys; - - switch (keyval) { - case GDK_Escape: - // Close on Esc and trap the accelerator - closed_by_escape_ = true; - Close(); - return TRUE; - case GDK_w: - // Close on C-w and forward the accelerator - if (modifier & GDK_CONTROL_MASK) { - Close(); - } - break; - default: - return FALSE; - } - - gdk_keymap_get_entries_for_keyval(NULL, - keyval, - &keys, - &n_keys); - if (n_keys) { - // Forward the accelerator to root window the bubble is anchored - // to for further processing - msg.type = GDK_KEY_PRESS; - msg.window = GTK_WIDGET(toplevel_window_)->window; - msg.send_event = TRUE; - msg.time = GDK_CURRENT_TIME; - msg.state = modifier | GDK_MOD2_MASK; - msg.keyval = keyval; - // length and string are deprecated and thus zeroed out - msg.length = 0; - msg.string = NULL; - msg.hardware_keycode = keys[0].keycode; - msg.group = keys[0].group; - msg.is_modifier = 0; - - g_free(keys); - - gtk_main_do_event(reinterpret_cast(&msg)); - } else { - // This means that there isn't a h/w code for the keyval in the - // current keymap, which is weird but possible if the keymap just - // changed. This isn't a critical error, but might be indicative - // of something off if it happens regularly. - DLOG(WARNING) << "Found no keys for value " << keyval; - } - return TRUE; -} - -gboolean InfoBubbleGtk::OnExpose(GtkWidget* widget, GdkEventExpose* expose) { - GdkDrawable* drawable = GDK_DRAWABLE(window_->window); - GdkGC* gc = gdk_gc_new(drawable); - gdk_gc_set_rgb_fg_color(gc, &kFrameColor); - - // Stroke the frame border. - std::vector points = MakeFramePolygonPoints( - current_arrow_location_, - window_->allocation.width, window_->allocation.height, - FRAME_STROKE); - gdk_draw_polygon(drawable, gc, FALSE, &points[0], points.size()); - - g_object_unref(gc); - return FALSE; // Propagate so our children paint, etc. -} - -// When our size is initially allocated or changed, we need to recompute -// and apply our shape mask region. -void InfoBubbleGtk::OnSizeAllocate(GtkWidget* widget, - GtkAllocation* allocation) { - if (!UpdateArrowLocation(false)) { - UpdateWindowShape(); - if (current_arrow_location_ == ARROW_LOCATION_TOP_RIGHT) - MoveWindow(); - } -} - -gboolean InfoBubbleGtk::OnButtonPress(GtkWidget* widget, - GdkEventButton* event) { - // If we got a click in our own window, that's okay (we need to additionally - // check that it falls within our bounds, since we've grabbed the pointer and - // some events that actually occurred in other windows will be reported with - // respect to our window). - if (event->window == window_->window && - (mask_region_ && gdk_region_point_in(mask_region_, event->x, event->y))) { - return FALSE; // Propagate. - } - - // Our content widget got a click. - if (event->window != window_->window && - gdk_window_get_toplevel(event->window) == window_->window) { - return FALSE; - } - - if (grab_input_) { - // Otherwise we had a click outside of our window, close ourself. - Close(); - return TRUE; - } - - return FALSE; -} - -gboolean InfoBubbleGtk::OnDestroy(GtkWidget* widget) { - // We are self deleting, we have a destroy signal setup to catch when we - // destroy the widget manually, or the window was closed via X. This will - // delete the InfoBubbleGtk object. - delete this; - return FALSE; // Propagate. -} - -void InfoBubbleGtk::OnHide(GtkWidget* widget) { - gtk_widget_destroy(widget); -} - -gboolean InfoBubbleGtk::OnToplevelConfigure(GtkWidget* widget, - GdkEventConfigure* event) { - if (!UpdateArrowLocation(false)) - MoveWindow(); - StackWindow(); - return FALSE; -} - -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/ui/gtk/info_bubble_gtk.h b/chrome/browser/ui/gtk/info_bubble_gtk.h deleted file mode 100644 index 891b27d..0000000 --- a/chrome/browser/ui/gtk/info_bubble_gtk.h +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright (c) 2011 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. - -// This is the GTK implementation of InfoBubbles. InfoBubbles are like -// dialogs, but they point to a given element on the screen. You should call -// InfoBubbleGtk::Show, which will create and display a bubble. The object is -// self deleting, when the bubble is closed, you will be notified via -// InfoBubbleGtkDelegate::InfoBubbleClosing(). Then the widgets and the -// underlying object will be destroyed. You can also close and destroy the -// bubble by calling Close(). - -#ifndef CHROME_BROWSER_UI_GTK_INFO_BUBBLE_GTK_H_ -#define CHROME_BROWSER_UI_GTK_INFO_BUBBLE_GTK_H_ -#pragma once - -#include -#include - -#include "base/basictypes.h" -#include "content/common/notification_observer.h" -#include "content/common/notification_registrar.h" -#include "ui/base/gtk/gtk_signal.h" -#include "ui/base/gtk/gtk_signal_registrar.h" -#include "ui/gfx/point.h" -#include "ui/gfx/rect.h" - -class GtkThemeService; -class InfoBubbleGtk; -namespace gfx { -class Rect; -} - -class InfoBubbleGtkDelegate { - public: - // Called when the InfoBubble is closing and is about to be deleted. - // |closed_by_escape| is true if the close is the result of pressing escape. - virtual void InfoBubbleClosing(InfoBubbleGtk* info_bubble, - bool closed_by_escape) = 0; - - // NOTE: The Views interface has CloseOnEscape, except I can't find a place - // where it ever returns false, so we always allow you to close via escape. - - protected: - virtual ~InfoBubbleGtkDelegate() {} -}; - -class InfoBubbleGtk : public NotificationObserver { - public: - // Where should the arrow be placed relative to the bubble? - enum ArrowLocationGtk { - // TODO(derat): Support placing arrows on the bottoms of the bubbles. - ARROW_LOCATION_TOP_LEFT, - ARROW_LOCATION_TOP_RIGHT, - }; - - // Show an InfoBubble, pointing at the area |rect| (in coordinates relative to - // |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(GtkWidget* anchor_widget, - const gfx::Rect* rect, - GtkWidget* content, - ArrowLocationGtk arrow_location, - bool match_system_theme, - bool grab_input, - GtkThemeService* provider, - InfoBubbleGtkDelegate* delegate); - - // Close the bubble if it's open. This will delete the widgets and object, - // so you shouldn't hold a InfoBubbleGtk pointer after calling Close(). - void Close(); - - // NotificationObserver implementation. - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details); - - // If the content contains widgets that can steal our pointer and keyboard - // grabs (e.g. GtkComboBox), this method should be called after a widget - // releases the grabs so we can reacquire them. Note that this causes a race - // condition; another client could grab them before we do (ideally, GDK would - // transfer the grabs back to us when the widget releases them). The window - // is small, though, and the worst-case scenario for this seems to just be - // that the content's widgets will appear inactive even after the user clicks - // in them. - void HandlePointerAndKeyboardUngrabbedByContent(); - - private: - enum FrameType { - FRAME_MASK, - FRAME_STROKE, - }; - - explicit InfoBubbleGtk(GtkThemeService* provider, bool match_system_theme); - virtual ~InfoBubbleGtk(); - - // Creates the InfoBubble. - void Init(GtkWidget* anchor_widget, - const gfx::Rect* rect, - GtkWidget* content, - ArrowLocationGtk arrow_location, - bool grab_input); - - // Make the points for our polygon frame, either for fill (the mask), or for - // when we stroke the border. - static std::vector MakeFramePolygonPoints( - ArrowLocationGtk arrow_location, - int width, - int height, - FrameType type); - - // Get the location where the arrow should be placed (which is a function of - // the preferred location and of the direction that the bubble should be - // facing to fit onscreen). |arrow_x| is the X component in screen - // coordinates of the point at which the bubble's arrow should be aimed, and - // |width| is the bubble's width. - static ArrowLocationGtk GetArrowLocation( - ArrowLocationGtk preferred_location, int arrow_x, int width); - - // Updates |arrow_location_| based on the toplevel window's current position - // and the bubble's size. If the |force_move_and_reshape| is true or the - // location changes, moves and reshapes the window and returns true. - bool UpdateArrowLocation(bool force_move_and_reshape); - - // Reshapes the window and updates |mask_region_|. - void UpdateWindowShape(); - - // Calculate the current screen position for the bubble's window (per - // |toplevel_window_|'s position as of its most-recent ConfigureNotify event - // and |rect_|) and move it there. - void MoveWindow(); - - // Restack the bubble's window directly above |toplevel_window_|. - void StackWindow(); - - // Sets the delegate. - void set_delegate(InfoBubbleGtkDelegate* delegate) { delegate_ = delegate; } - - // Grab (in the X sense) the pointer and keyboard. This is needed to make - // sure that we have the input focus. - void GrabPointerAndKeyboard(); - - CHROMEG_CALLBACK_3(InfoBubbleGtk, gboolean, OnGtkAccelerator, GtkAccelGroup*, - GObject*, guint, GdkModifierType); - - CHROMEGTK_CALLBACK_1(InfoBubbleGtk, gboolean, OnExpose, GdkEventExpose*); - CHROMEGTK_CALLBACK_1(InfoBubbleGtk, void, OnSizeAllocate, GtkAllocation*); - CHROMEGTK_CALLBACK_1(InfoBubbleGtk, gboolean, OnButtonPress, GdkEventButton*); - CHROMEGTK_CALLBACK_0(InfoBubbleGtk, gboolean, OnDestroy); - CHROMEGTK_CALLBACK_0(InfoBubbleGtk, void, OnHide); - 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_; - - // Our GtkWindow popup window, we don't technically "own" the widget, since - // it deletes us when it is destroyed. - GtkWidget* window_; - - // Provides colors and stuff. - GtkThemeService* theme_service_; - - // The accel group attached to |window_|, to handle closing with escape. - GtkAccelGroup* accel_group_; - - // The window for which we're being shown (and to which |rect_| is relative). - // Note that it's possible for |toplevel_window_| to be NULL if the - // window is destroyed before this object is destroyed, so it's important - // to check for that case. - GtkWindow* toplevel_window_; - - // 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_; - - // The current shape of |window_| (used to test whether clicks fall in it or - // not). - GdkRegion* mask_region_; - - // Where would we prefer for the arrow be drawn relative to the bubble, and - // where is it currently drawn? - ArrowLocationGtk preferred_arrow_location_; - ArrowLocationGtk current_arrow_location_; - - // Whether the background should match the system theme, when the system theme - // is being used. For example, the bookmark bubble does, but extension popups - // do not. - bool match_system_theme_; - - // If true, the popup owns all X input for the duration of its existence. - // This will usually be true, the exception being when inspecting extension - // popups with dev tools. - bool grab_input_; - - bool closed_by_escape_; - - NotificationRegistrar registrar_; - - ui::GtkSignalRegistrar signals_; - - DISALLOW_COPY_AND_ASSIGN(InfoBubbleGtk); -}; - -#endif // CHROME_BROWSER_UI_GTK_INFO_BUBBLE_GTK_H_ diff --git a/chrome/browser/ui/gtk/location_bar_view_gtk.cc b/chrome/browser/ui/gtk/location_bar_view_gtk.cc index 0bbe026..15abc6e 100644 --- a/chrome/browser/ui/gtk/location_bar_view_gtk.cc +++ b/chrome/browser/ui/gtk/location_bar_view_gtk.cc @@ -1232,7 +1232,7 @@ LocationBarViewGtk::ContentSettingImageViewGtk::ContentSettingImageViewGtk( label_(gtk_label_new(NULL)), parent_(parent), profile_(profile), - info_bubble_(NULL), + content_setting_bubble_(NULL), animation_(this), method_factory_(this) { gtk_alignment_set_padding(GTK_ALIGNMENT(alignment_.get()), 1, 1, 0, 0); @@ -1266,8 +1266,8 @@ LocationBarViewGtk::ContentSettingImageViewGtk::~ContentSettingImageViewGtk() { event_box_.Destroy(); alignment_.Destroy(); - if (info_bubble_) - info_bubble_->Close(); + if (content_setting_bubble_) + content_setting_bubble_->Close(); } void LocationBarViewGtk::ContentSettingImageViewGtk::UpdateFromTabContents( @@ -1373,7 +1373,7 @@ gboolean LocationBarViewGtk::ContentSettingImageViewGtk::OnButtonPressed( &display_host, NULL, NULL); - info_bubble_ = new ContentSettingBubbleGtk( + content_setting_bubble_ = new ContentSettingBubbleGtk( sender, this, ContentSettingBubbleModel::CreateContentSettingBubbleModel( tab_contents, profile_, content_settings_type), @@ -1410,10 +1410,10 @@ gboolean LocationBarViewGtk::ContentSettingImageViewGtk::OnExpose( return FALSE; } -void LocationBarViewGtk::ContentSettingImageViewGtk::InfoBubbleClosing( - InfoBubbleGtk* info_bubble, +void LocationBarViewGtk::ContentSettingImageViewGtk::BubbleClosing( + BubbleGtk* bubble, bool closed_by_escape) { - info_bubble_ = NULL; + content_setting_bubble_ = NULL; } //////////////////////////////////////////////////////////////////////////////// diff --git a/chrome/browser/ui/gtk/location_bar_view_gtk.h b/chrome/browser/ui/gtk/location_bar_view_gtk.h index 4db1c06..b07df3b 100644 --- a/chrome/browser/ui/gtk/location_bar_view_gtk.h +++ b/chrome/browser/ui/gtk/location_bar_view_gtk.h @@ -12,6 +12,7 @@ #include #include "base/basictypes.h" +#include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" #include "base/memory/scoped_vector.h" #include "chrome/browser/autocomplete/autocomplete_edit.h" @@ -20,7 +21,7 @@ #include "chrome/browser/extensions/image_loading_tracker.h" #include "chrome/browser/first_run/first_run.h" #include "chrome/browser/prefs/pref_member.h" -#include "chrome/browser/ui/gtk/info_bubble_gtk.h" +#include "chrome/browser/ui/gtk/bubble/bubble_gtk.h" #include "chrome/browser/ui/gtk/menu_gtk.h" #include "chrome/browser/ui/gtk/owned_widget_gtk.h" #include "chrome/browser/ui/omnibox/location_bar.h" @@ -142,7 +143,7 @@ class LocationBarViewGtk : public AutocompleteEditController, static const GdkColor kBackgroundColor; private: - class ContentSettingImageViewGtk : public InfoBubbleGtkDelegate, + class ContentSettingImageViewGtk : public BubbleDelegateGtk, public ui::AnimationDelegate { public: ContentSettingImageViewGtk(ContentSettingsType content_type, @@ -174,9 +175,9 @@ class LocationBarViewGtk : public AutocompleteEditController, CHROMEGTK_CALLBACK_1(ContentSettingImageViewGtk, gboolean, OnExpose, GdkEventExpose*); - // InfoBubbleDelegate overrides: - virtual void InfoBubbleClosing(InfoBubbleGtk* info_bubble, - bool closed_by_escape); + // BubbleDelegateGtk overrides: + virtual void BubbleClosing(BubbleGtk* bubble, + bool closed_by_escape) OVERRIDE; scoped_ptr content_setting_image_model_; @@ -195,8 +196,8 @@ class LocationBarViewGtk : public AutocompleteEditController, // The currently active profile. Profile* profile_; - // The currently shown info bubble if any. - ContentSettingBubbleGtk* info_bubble_; + // The currently shown bubble if any. + ContentSettingBubbleGtk* content_setting_bubble_; // When we show explanatory text, we slide it in/out. ui::SlideAnimation animation_; @@ -423,7 +424,7 @@ class LocationBarViewGtk : public AutocompleteEditController, // The transition type to use for the navigation. PageTransition::Type transition_; - // Used to schedule a task for the first run info bubble. + // Used to schedule a task for the first run bubble. ScopedRunnableMethodFactory first_run_bubble_; // When true, the location bar view is read only and also is has a slightly diff --git a/chrome/browser/ui/gtk/notifications/balloon_view_gtk.cc b/chrome/browser/ui/gtk/notifications/balloon_view_gtk.cc index 8e2ce41..d7432fd 100644 --- a/chrome/browser/ui/gtk/notifications/balloon_view_gtk.cc +++ b/chrome/browser/ui/gtk/notifications/balloon_view_gtk.cc @@ -24,7 +24,6 @@ #include "chrome/browser/ui/gtk/custom_button.h" #include "chrome/browser/ui/gtk/gtk_theme_service.h" #include "chrome/browser/ui/gtk/gtk_util.h" -#include "chrome/browser/ui/gtk/info_bubble_gtk.h" #include "chrome/browser/ui/gtk/menu_gtk.h" #include "chrome/browser/ui/gtk/notifications/balloon_view_host_gtk.h" #include "chrome/browser/ui/gtk/rounded_window.h" diff --git a/chrome/browser/ui/gtk/page_info_bubble_gtk.cc b/chrome/browser/ui/gtk/page_info_bubble_gtk.cc index db72101..7ca4cb1 100644 --- a/chrome/browser/ui/gtk/page_info_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/page_info_bubble_gtk.cc @@ -4,8 +4,8 @@ #include -#include "build/build_config.h" - +#include "base/basictypes.h" +#include "base/compiler_specific.h" #include "base/i18n/rtl.h" #include "base/utf_string_conversions.h" #include "chrome/browser/google/google_util.h" @@ -14,10 +14,10 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/gtk/browser_toolbar_gtk.h" #include "chrome/browser/ui/gtk/browser_window_gtk.h" +#include "chrome/browser/ui/gtk/bubble/bubble_gtk.h" #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h" #include "chrome/browser/ui/gtk/gtk_theme_service.h" #include "chrome/browser/ui/gtk/gtk_util.h" -#include "chrome/browser/ui/gtk/info_bubble_gtk.h" #include "chrome/browser/ui/gtk/location_bar_view_gtk.h" #include "chrome/common/url_constants.h" #include "content/browser/certificate_viewer.h" @@ -34,7 +34,7 @@ class Profile; namespace { class PageInfoBubbleGtk : public PageInfoModel::PageInfoModelObserver, - public InfoBubbleGtkDelegate, + public BubbleDelegateGtk, public NotificationObserver { public: PageInfoBubbleGtk(gfx::NativeWindow parent, @@ -44,17 +44,16 @@ class PageInfoBubbleGtk : public PageInfoModel::PageInfoModelObserver, bool show_history); virtual ~PageInfoBubbleGtk(); - // PageInfoModelObserver implementation: - virtual void ModelChanged(); + // PageInfoModel::PageInfoModelObserver implementation. + virtual void ModelChanged() OVERRIDE; + + // BubbleDelegateGtk implementation. + virtual void BubbleClosing(BubbleGtk* bubble, bool closed_by_escape) OVERRIDE; - // NotificationObserver implementation: + // NotificationObserver implementation. virtual void Observe(NotificationType type, const NotificationSource& source, - const NotificationDetails& details); - - // InfoBubbleGtkDelegate implementation: - virtual void InfoBubbleClosing(InfoBubbleGtk* info_bubble, - bool closed_by_escape); + const NotificationDetails& details) OVERRIDE; private: // Layouts the different sections retrieved from the model. @@ -92,7 +91,7 @@ class PageInfoBubbleGtk : public PageInfoModel::PageInfoModelObserver, std::vector labels_; std::vector links_; - InfoBubbleGtk* bubble_; + BubbleGtk* bubble_; NotificationRegistrar registrar_; @@ -122,17 +121,17 @@ PageInfoBubbleGtk::PageInfoBubbleGtk(gfx::NativeWindow parent, InitContents(); - InfoBubbleGtk::ArrowLocationGtk arrow_location = base::i18n::IsRTL() ? - InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT : - InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT; - bubble_ = InfoBubbleGtk::Show(anchor_, - NULL, // |rect| - contents_, - arrow_location, - true, // |match_system_theme| - true, // |grab_input| - theme_service_, - this); // |delegate| + BubbleGtk::ArrowLocationGtk arrow_location = base::i18n::IsRTL() ? + BubbleGtk::ARROW_LOCATION_TOP_RIGHT : + BubbleGtk::ARROW_LOCATION_TOP_LEFT; + bubble_ = BubbleGtk::Show(anchor_, + NULL, // |rect| + contents_, + arrow_location, + true, // |match_system_theme| + true, // |grab_input| + theme_service_, + this); // |delegate| if (!bubble_) { NOTREACHED(); return; @@ -146,6 +145,11 @@ void PageInfoBubbleGtk::ModelChanged() { InitContents(); } +void PageInfoBubbleGtk::BubbleClosing(BubbleGtk* bubble, + bool closed_by_escape) { + delete this; +} + void PageInfoBubbleGtk::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { @@ -171,11 +175,6 @@ void PageInfoBubbleGtk::Observe(NotificationType type, } } -void PageInfoBubbleGtk::InfoBubbleClosing(InfoBubbleGtk* info_bubble, - bool closed_by_escape) { - delete this; -} - void PageInfoBubbleGtk::InitContents() { if (!contents_) { contents_ = gtk_vbox_new(FALSE, gtk_util::kContentAreaSpacing); diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 88336a6..5e04ec0 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2582,6 +2582,10 @@ 'browser/ui/gtk/browser_window_factory_gtk.cc', 'browser/ui/gtk/browser_window_gtk.cc', 'browser/ui/gtk/browser_window_gtk.h', + 'browser/ui/gtk/bubble/bubble_accelerators_gtk.cc', + 'browser/ui/gtk/bubble/bubble_accelerators_gtk.h', + 'browser/ui/gtk/bubble/bubble_gtk.cc', + 'browser/ui/gtk/bubble/bubble_gtk.h', 'browser/ui/gtk/cairo_cached_surface.cc', 'browser/ui/gtk/cairo_cached_surface.h', 'browser/ui/gtk/certificate_dialogs.cc', @@ -2669,10 +2673,6 @@ 'browser/ui/gtk/importer/import_lock_dialog_gtk.h', 'browser/ui/gtk/importer/import_progress_dialog_gtk.cc', 'browser/ui/gtk/importer/import_progress_dialog_gtk.h', - 'browser/ui/gtk/info_bubble_accelerators_gtk.cc', - 'browser/ui/gtk/info_bubble_accelerators_gtk.h', - 'browser/ui/gtk/info_bubble_gtk.cc', - 'browser/ui/gtk/info_bubble_gtk.h', 'browser/ui/gtk/infobars/confirm_infobar_gtk.cc', 'browser/ui/gtk/infobars/confirm_infobar_gtk.h', 'browser/ui/gtk/infobars/extension_infobar_gtk.cc', -- cgit v1.1