diff options
author | dbeam@chromium.org <dbeam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-26 22:00:25 +0000 |
---|---|---|
committer | dbeam@chromium.org <dbeam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-26 22:00:25 +0000 |
commit | 4b88ddac62bec4c723f3d844cf1b577d0d795453 (patch) | |
tree | f0ec7f65e2612a04fa7c986a8b8ec1456096136d | |
parent | d4d245fc2988177f622d043592e349a0c603a950 (diff) | |
download | chromium_src-4b88ddac62bec4c723f3d844cf1b577d0d795453.zip chromium_src-4b88ddac62bec4c723f3d844cf1b577d0d795453.tar.gz chromium_src-4b88ddac62bec4c723f3d844cf1b577d0d795453.tar.bz2 |
[zoom bubble] Handle entering/leaving/being in fullscreen on GTK.
This patch should:
- hide the zoom bubble when toggling fullscreen
- show a bubble without an arrow while in fullscreen
This patch also:
- changes ArrowLocationGtk to FrameStyle as it's a more appropriate name
- renames all of the arrow locations to the equivalent frame styles
- adds FIXED_TOP_LEFT, FIXED_TOP_RIGHT to the available frame styles
- automatically flips bubbles in RTL to avoid making callers do this
- fixes about ~3 callers that weren't flipping
BUG=167365
Review URL: https://codereview.chromium.org/11553046
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@174636 0039d316-1c4b-4281-b951-d872f2087c98
28 files changed, 321 insertions, 258 deletions
diff --git a/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.cc b/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.cc index 1e95a45..72ea14e 100644 --- a/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.cc @@ -36,7 +36,7 @@ const int kNewProfileLinkLeftPadding = 40; AvatarMenuBubbleGtk::AvatarMenuBubbleGtk(Browser* browser, GtkWidget* anchor, - BubbleGtk::ArrowLocationGtk arrow, + BubbleGtk::FrameStyle arrow, const gfx::Rect* rect) : contents_(NULL), theme_service_(GtkThemeService::GetFrom(browser->profile())), diff --git a/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.h b/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.h index 7c3247c..fcb3101 100644 --- a/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.h +++ b/chrome/browser/ui/gtk/avatar_menu_bubble_gtk.h @@ -29,7 +29,7 @@ class AvatarMenuBubbleGtk : public BubbleDelegateGtk, public: AvatarMenuBubbleGtk(Browser* browser, GtkWidget* anchor, - BubbleGtk::ArrowLocationGtk arrow, + BubbleGtk::FrameStyle arrow, const gfx::Rect* rect); virtual ~AvatarMenuBubbleGtk(); diff --git a/chrome/browser/ui/gtk/avatar_menu_button_gtk.cc b/chrome/browser/ui/gtk/avatar_menu_button_gtk.cc index af58abe..5ff6b1b 100644 --- a/chrome/browser/ui/gtk/avatar_menu_button_gtk.cc +++ b/chrome/browser/ui/gtk/avatar_menu_button_gtk.cc @@ -19,7 +19,7 @@ AvatarMenuButtonGtk::AvatarMenuButtonGtk(Browser* browser) : image_(NULL), browser_(browser), - arrow_location_(BubbleGtk::ARROW_LOCATION_TOP_LEFT), + frame_style_(BubbleGtk::ANCHOR_TOP_LEFT), is_gaia_picture_(false), old_height_(0) { GtkWidget* event_box = gtk_event_box_new(); @@ -71,7 +71,7 @@ void AvatarMenuButtonGtk::ShowAvatarBubble() { DCHECK(chrome::IsCommandEnabled(browser_, IDC_SHOW_AVATAR_MENU)); // Only show the avatar bubble if the avatar button is in the title bar. if (gtk_widget_get_parent_window(widget_.get())) - new AvatarMenuBubbleGtk(browser_, widget_.get(), arrow_location_, NULL); + new AvatarMenuBubbleGtk(browser_, widget_.get(), frame_style_, NULL); } void AvatarMenuButtonGtk::UpdateButtonIcon() { diff --git a/chrome/browser/ui/gtk/avatar_menu_button_gtk.h b/chrome/browser/ui/gtk/avatar_menu_button_gtk.h index 1f97cbc..24e4d4f 100644 --- a/chrome/browser/ui/gtk/avatar_menu_button_gtk.h +++ b/chrome/browser/ui/gtk/avatar_menu_button_gtk.h @@ -31,8 +31,8 @@ class AvatarMenuButtonGtk { GtkWidget* widget() const { return widget_.get(); } // Sets the location the arrow should be displayed on the menu bubble. - void set_menu_arrow_location(BubbleGtk::ArrowLocationGtk arrow_location) { - arrow_location_ = arrow_location; + void set_menu_frame_style(BubbleGtk::FrameStyle frame_style) { + frame_style_ = frame_style; } // Sets the image to display on the button, typically the profile icon. @@ -59,7 +59,7 @@ class AvatarMenuButtonGtk { Browser* browser_; // Which side of the bubble to display the arrow. - BubbleGtk::ArrowLocationGtk arrow_location_; + BubbleGtk::FrameStyle frame_style_; scoped_ptr<gfx::Image> icon_; bool is_gaia_picture_; diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.cc b/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.cc index 760dc91..f8b5ffa 100644 --- a/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/bookmarks/bookmark_bubble_gtk.cc @@ -154,14 +154,10 @@ 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); - BubbleGtk::ArrowLocationGtk arrow_location = - base::i18n::IsRTL() ? - BubbleGtk::ARROW_LOCATION_TOP_LEFT : - BubbleGtk::ARROW_LOCATION_TOP_RIGHT; bubble_ = BubbleGtk::Show(anchor_, NULL, content, - arrow_location, + BubbleGtk::ANCHOR_TOP_RIGHT, BubbleGtk::MATCH_SYSTEM_THEME | BubbleGtk::POPUP_WINDOW | BubbleGtk::GRAB_INPUT, diff --git a/chrome/browser/ui/gtk/browser_titlebar.cc b/chrome/browser/ui/gtk/browser_titlebar.cc index a3a49a1..186977e 100644 --- a/chrome/browser/ui/gtk/browser_titlebar.cc +++ b/chrome/browser/ui/gtk/browser_titlebar.cc @@ -815,12 +815,8 @@ void BrowserTitlebar::UpdateAvatar() { avatar = cache.GetAvatarIconOfProfileAtIndex(index); } avatar_button_->SetIcon(avatar, is_gaia_picture); - - BubbleGtk::ArrowLocationGtk arrow_location = - display_avatar_on_left_ ^ base::i18n::IsRTL() ? - BubbleGtk::ARROW_LOCATION_TOP_LEFT : - BubbleGtk::ARROW_LOCATION_TOP_RIGHT; - avatar_button_->set_menu_arrow_location(arrow_location); + avatar_button_->set_menu_frame_style(display_avatar_on_left_ ? + BubbleGtk::ANCHOR_TOP_LEFT : BubbleGtk::ANCHOR_TOP_RIGHT); } void BrowserTitlebar::MaximizeButtonClicked() { diff --git a/chrome/browser/ui/gtk/browser_window_gtk.cc b/chrome/browser/ui/gtk/browser_window_gtk.cc index 9805f8d..65be17e 100644 --- a/chrome/browser/ui/gtk/browser_window_gtk.cc +++ b/chrome/browser/ui/gtk/browser_window_gtk.cc @@ -1158,7 +1158,7 @@ void BrowserWindowGtk::ShowAvatarBubble(WebContents* web_contents, const gfx::Rect& rect) { GtkWidget* widget = web_contents->GetContentNativeView(); new AvatarMenuBubbleGtk(browser_.get(), widget, - BubbleGtk::ARROW_LOCATION_TOP_LEFT, &rect); + BubbleGtk::ANCHOR_TOP_LEFT, &rect); } void BrowserWindowGtk::ShowAvatarBubbleFromAvatarButton() { diff --git a/chrome/browser/ui/gtk/bubble/bubble_gtk.cc b/chrome/browser/ui/gtk/bubble/bubble_gtk.cc index b955a52..d097b39 100644 --- a/chrome/browser/ui/gtk/bubble/bubble_gtk.cc +++ b/chrome/browser/ui/gtk/bubble/bubble_gtk.cc @@ -6,7 +6,7 @@ #include <gdk/gdkkeysyms.h> -#include "base/logging.h" +#include "base/i18n/rtl.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" @@ -35,40 +35,90 @@ const int kArrowToContentPadding = -4; // We draw flat diagonal corners, each corner is an NxN square. const int kCornerSize = 3; +// The amount of padding (in pixels) from the top of |toplevel_window_| to the +// top of |window_| when fixed positioning is used. +const int kFixedPositionPaddingEnd = 10; +const int kFixedPositionPaddingTop = 5; + const GdkColor kBackgroundColor = GDK_COLOR_RGB(0xff, 0xff, 0xff); const GdkColor kFrameColor = GDK_COLOR_RGB(0x63, 0x63, 0x63); // Helper functions that encapsulate arrow locations. -bool HasArrow(BubbleGtk::ArrowLocationGtk location) { - return location != BubbleGtk::ARROW_LOCATION_NONE && - location != BubbleGtk::ARROW_LOCATION_FLOAT; +bool HasArrow(BubbleGtk::FrameStyle frame_style) { + return frame_style != BubbleGtk::FLOAT_BELOW_RECT && + frame_style != BubbleGtk::CENTER_OVER_RECT && + frame_style != BubbleGtk::FIXED_TOP_LEFT && + frame_style != BubbleGtk::FIXED_TOP_RIGHT; +} + +bool IsArrowLeft(BubbleGtk::FrameStyle frame_style) { + return frame_style == BubbleGtk::ANCHOR_TOP_LEFT || + frame_style == BubbleGtk::ANCHOR_BOTTOM_LEFT; } -bool IsArrowLeft(BubbleGtk::ArrowLocationGtk location) { - return location == BubbleGtk::ARROW_LOCATION_TOP_LEFT || - location == BubbleGtk::ARROW_LOCATION_BOTTOM_LEFT; +bool IsArrowMiddle(BubbleGtk::FrameStyle frame_style) { + return frame_style == BubbleGtk::ANCHOR_TOP_MIDDLE || + frame_style == BubbleGtk::ANCHOR_BOTTOM_MIDDLE; } -bool IsArrowMiddle(BubbleGtk::ArrowLocationGtk location) { - return location == BubbleGtk::ARROW_LOCATION_TOP_MIDDLE || - location == BubbleGtk::ARROW_LOCATION_BOTTOM_MIDDLE; +bool IsArrowRight(BubbleGtk::FrameStyle frame_style) { + return frame_style == BubbleGtk::ANCHOR_TOP_RIGHT || + frame_style == BubbleGtk::ANCHOR_BOTTOM_RIGHT; } -bool IsArrowRight(BubbleGtk::ArrowLocationGtk location) { - return location == BubbleGtk::ARROW_LOCATION_TOP_RIGHT || - location == BubbleGtk::ARROW_LOCATION_BOTTOM_RIGHT; +bool IsArrowTop(BubbleGtk::FrameStyle frame_style) { + return frame_style == BubbleGtk::ANCHOR_TOP_LEFT || + frame_style == BubbleGtk::ANCHOR_TOP_MIDDLE || + frame_style == BubbleGtk::ANCHOR_TOP_RIGHT; } -bool IsArrowTop(BubbleGtk::ArrowLocationGtk location) { - return location == BubbleGtk::ARROW_LOCATION_TOP_LEFT || - location == BubbleGtk::ARROW_LOCATION_TOP_MIDDLE || - location == BubbleGtk::ARROW_LOCATION_TOP_RIGHT; +bool IsArrowBottom(BubbleGtk::FrameStyle frame_style) { + return frame_style == BubbleGtk::ANCHOR_BOTTOM_LEFT || + frame_style == BubbleGtk::ANCHOR_BOTTOM_MIDDLE || + frame_style == BubbleGtk::ANCHOR_BOTTOM_RIGHT; } -bool IsArrowBottom(BubbleGtk::ArrowLocationGtk location) { - return location == BubbleGtk::ARROW_LOCATION_BOTTOM_LEFT || - location == BubbleGtk::ARROW_LOCATION_BOTTOM_MIDDLE || - location == BubbleGtk::ARROW_LOCATION_BOTTOM_RIGHT; +bool IsFixed(BubbleGtk::FrameStyle frame_style) { + return frame_style == BubbleGtk::FIXED_TOP_LEFT || + frame_style == BubbleGtk::FIXED_TOP_RIGHT; +} + +BubbleGtk::FrameStyle AdjustFrameStyleForLocale( + BubbleGtk::FrameStyle frame_style) { + // Only RTL requires more work. + if (!base::i18n::IsRTL()) + return frame_style; + + switch (frame_style) { + // These don't flip. + case BubbleGtk::ANCHOR_TOP_MIDDLE: + case BubbleGtk::ANCHOR_BOTTOM_MIDDLE: + case BubbleGtk::FLOAT_BELOW_RECT: + case BubbleGtk::CENTER_OVER_RECT: + return frame_style; + + // These do flip. + case BubbleGtk::ANCHOR_TOP_LEFT: + return BubbleGtk::ANCHOR_TOP_RIGHT; + + case BubbleGtk::ANCHOR_TOP_RIGHT: + return BubbleGtk::ANCHOR_TOP_LEFT; + + case BubbleGtk::ANCHOR_BOTTOM_LEFT: + return BubbleGtk::ANCHOR_BOTTOM_RIGHT; + + case BubbleGtk::ANCHOR_BOTTOM_RIGHT: + return BubbleGtk::ANCHOR_BOTTOM_LEFT; + + case BubbleGtk::FIXED_TOP_LEFT: + return BubbleGtk::FIXED_TOP_RIGHT; + + case BubbleGtk::FIXED_TOP_RIGHT: + return BubbleGtk::FIXED_TOP_LEFT; + } + + NOTREACHED(); + return BubbleGtk::ANCHOR_TOP_LEFT; } } // namespace @@ -77,17 +127,21 @@ bool IsArrowBottom(BubbleGtk::ArrowLocationGtk location) { BubbleGtk* BubbleGtk::Show(GtkWidget* anchor_widget, const gfx::Rect* rect, GtkWidget* content, - ArrowLocationGtk arrow_location, + FrameStyle frame_style, int attribute_flags, GtkThemeService* provider, BubbleDelegateGtk* delegate) { - BubbleGtk* bubble = new BubbleGtk(provider, attribute_flags); - bubble->Init(anchor_widget, rect, content, arrow_location, attribute_flags); + BubbleGtk* bubble = new BubbleGtk(provider, + AdjustFrameStyleForLocale(frame_style), + attribute_flags); + bubble->Init(anchor_widget, rect, content, attribute_flags); bubble->set_delegate(delegate); return bubble; } -BubbleGtk::BubbleGtk(GtkThemeService* provider, int attribute_flags) +BubbleGtk::BubbleGtk(GtkThemeService* provider, + FrameStyle frame_style, + int attribute_flags) : delegate_(NULL), window_(NULL), theme_service_(provider), @@ -95,10 +149,10 @@ BubbleGtk::BubbleGtk(GtkThemeService* provider, int attribute_flags) toplevel_window_(NULL), anchor_widget_(NULL), mask_region_(NULL), - preferred_arrow_location_(ARROW_LOCATION_TOP_LEFT), - current_arrow_location_(ARROW_LOCATION_TOP_LEFT), + requested_frame_style_(frame_style), + actual_frame_style_(ANCHOR_TOP_LEFT), match_system_theme_(attribute_flags & MATCH_SYSTEM_THEME), - grab_input_(true), + grab_input_(attribute_flags & GRAB_INPUT), closed_by_escape_(false) { } @@ -116,7 +170,6 @@ BubbleGtk::~BubbleGtk() { void BubbleGtk::Init(GtkWidget* anchor_widget, const gfx::Rect* rect, GtkWidget* content, - ArrowLocationGtk arrow_location, int attribute_flags) { // If there is a current grab widget (menu, other bubble, etc.), hide it. GtkWidget* current_grab_widget = gtk_grab_get_current(); @@ -128,9 +181,7 @@ void BubbleGtk::Init(GtkWidget* anchor_widget, toplevel_window_ = gtk_widget_get_toplevel(anchor_widget_); DCHECK(gtk_widget_is_toplevel(toplevel_window_)); rect_ = rect ? *rect : gtk_util::WidgetBounds(anchor_widget); - preferred_arrow_location_ = arrow_location; - grab_input_ = attribute_flags & 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(attribute_flags & POPUP_WINDOW ? @@ -154,8 +205,13 @@ void BubbleGtk::Init(GtkWidget* anchor_widget, gtk_window_add_accel_group(GTK_WINDOW(window_), accel_group_); + // |requested_frame_style_| is used instead of |actual_frame_style_| here + // because |actual_frame_style_| is only correct after calling + // |UpdateFrameStyle()|. Unfortunately, |UpdateFrameStyle()| requires knowing + // the size of |window_| (which happens later on). + int arrow_padding = HasArrow(requested_frame_style_) ? kArrowSize : 0; GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); - gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), kArrowSize, 0, 0, 0); + gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), arrow_padding, 0, 0, 0); gtk_container_add(GTK_CONTAINER(alignment), content); gtk_container_add(GTK_CONTAINER(window_), alignment); @@ -165,7 +221,7 @@ void BubbleGtk::Init(GtkWidget* anchor_widget, // OnSizeAllocate, so the mask can be applied to the GdkWindow. gtk_widget_realize(window_); - UpdateArrowLocation(true); // Force move and reshape. + UpdateFrameStyle(true); // Force move and reshape. StackWindow(); gtk_widget_add_events(window_, GDK_BUTTON_PRESS_MASK); @@ -218,22 +274,22 @@ void BubbleGtk::Init(GtkWidget* anchor_widget, // corners. This is a lot more work, but they get anti-aliasing. // static std::vector<GdkPoint> BubbleGtk::MakeFramePolygonPoints( - ArrowLocationGtk arrow_location, + FrameStyle frame_style, int width, int height, FrameType type) { using gtk_util::MakeBidiGdkPoint; std::vector<GdkPoint> points; - int top_arrow_size = IsArrowTop(arrow_location) ? kArrowSize : 0; - int bottom_arrow_size = IsArrowBottom(arrow_location) ? kArrowSize : 0; - bool on_left = IsArrowLeft(arrow_location); + int top_arrow_size = IsArrowTop(frame_style) ? kArrowSize : 0; + int bottom_arrow_size = IsArrowBottom(frame_style) ? kArrowSize : 0; + bool on_left = IsArrowLeft(frame_style); // 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; + // right side for ANCHOR_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. @@ -247,8 +303,7 @@ std::vector<GdkPoint> BubbleGtk::MakeFramePolygonPoints( // The top arrow. if (top_arrow_size) { - int arrow_x = arrow_location == ARROW_LOCATION_TOP_MIDDLE ? - width / 2 : kArrowX; + int arrow_x = frame_style == ANCHOR_TOP_MIDDLE ? width / 2 : kArrowX; points.push_back(MakeBidiGdkPoint( arrow_x - top_arrow_size + x_off_r, top_arrow_size, width, on_left)); points.push_back(MakeBidiGdkPoint( @@ -276,7 +331,7 @@ std::vector<GdkPoint> BubbleGtk::MakeFramePolygonPoints( // The bottom arrow. if (bottom_arrow_size) { - int arrow_x = arrow_location == ARROW_LOCATION_BOTTOM_MIDDLE ? + int arrow_x = frame_style == ANCHOR_BOTTOM_MIDDLE ? width / 2 : kArrowX; points.push_back(MakeBidiGdkPoint( arrow_x + bottom_arrow_size + 1 + x_off_l, @@ -304,43 +359,46 @@ std::vector<GdkPoint> BubbleGtk::MakeFramePolygonPoints( return points; } -BubbleGtk::ArrowLocationGtk BubbleGtk::GetArrowLocation( - ArrowLocationGtk preferred_location, +BubbleGtk::FrameStyle BubbleGtk::GetAllowedFrameStyle( + FrameStyle preferred_style, int arrow_x, int arrow_y, int width, int height) { + if (IsFixed(preferred_style)) + return preferred_style; + const int screen_width = gdk_screen_get_width(gdk_screen_get_default()); const int screen_height = gdk_screen_get_height(gdk_screen_get_default()); // Choose whether to show the bubble above or below the specified location. - const bool prefer_top_arrow = IsArrowTop(preferred_location) || - preferred_location == ARROW_LOCATION_NONE; + const bool prefer_top_arrow = IsArrowTop(preferred_style) || + preferred_style == FLOAT_BELOW_RECT; // The bleed measures the amount of bubble that would be shown offscreen. const int top_arrow_bleed = std::max(height + kArrowSize + arrow_y - screen_height, 0); const int bottom_arrow_bleed = std::max(height + kArrowSize - arrow_y, 0); - ArrowLocationGtk arrow_location_none = ARROW_LOCATION_NONE; - ArrowLocationGtk arrow_location_left = ARROW_LOCATION_TOP_LEFT; - ArrowLocationGtk arrow_location_middle = ARROW_LOCATION_TOP_MIDDLE; - ArrowLocationGtk arrow_location_right = ARROW_LOCATION_TOP_RIGHT; + FrameStyle frame_style_none = FLOAT_BELOW_RECT; + FrameStyle frame_style_left = ANCHOR_TOP_LEFT; + FrameStyle frame_style_middle = ANCHOR_TOP_MIDDLE; + FrameStyle frame_style_right = ANCHOR_TOP_RIGHT; if ((prefer_top_arrow && (top_arrow_bleed > bottom_arrow_bleed)) || (!prefer_top_arrow && (top_arrow_bleed >= bottom_arrow_bleed))) { - arrow_location_none = ARROW_LOCATION_FLOAT; - arrow_location_left = ARROW_LOCATION_BOTTOM_LEFT; - arrow_location_middle = ARROW_LOCATION_BOTTOM_MIDDLE; - arrow_location_right =ARROW_LOCATION_BOTTOM_RIGHT; + frame_style_none = CENTER_OVER_RECT; + frame_style_left = ANCHOR_BOTTOM_LEFT; + frame_style_middle = ANCHOR_BOTTOM_MIDDLE; + frame_style_right = ANCHOR_BOTTOM_RIGHT; } - if (!HasArrow(preferred_location)) - return arrow_location_none; + if (!HasArrow(preferred_style)) + return frame_style_none; - if (IsArrowMiddle(preferred_location)) - return arrow_location_middle; + if (IsArrowMiddle(preferred_style)) + return frame_style_middle; // Choose whether to show the bubble left or right of the specified location. - const bool prefer_left_arrow = IsArrowLeft(preferred_location); + const bool prefer_left_arrow = IsArrowLeft(preferred_style); // The bleed measures the amount of bubble that would be shown offscreen. const int left_arrow_bleed = std::max(width + arrow_x - kArrowX - screen_width, 0); @@ -349,10 +407,10 @@ BubbleGtk::ArrowLocationGtk BubbleGtk::GetArrowLocation( // Use the preferred location if it doesn't bleed more than the opposite side. return ((prefer_left_arrow && (left_arrow_bleed <= right_arrow_bleed)) || (!prefer_left_arrow && (left_arrow_bleed < right_arrow_bleed))) ? - arrow_location_left : arrow_location_right; + frame_style_left : frame_style_right; } -bool BubbleGtk::UpdateArrowLocation(bool force_move_and_reshape) { +bool BubbleGtk::UpdateFrameStyle(bool force_move_and_reshape) { if (!toplevel_window_ || !anchor_widget_) return false; @@ -363,17 +421,17 @@ bool BubbleGtk::UpdateArrowLocation(bool force_move_and_reshape) { gtk_widget_translate_coordinates(anchor_widget_, toplevel_window_, rect_.x(), rect_.y(), &offset_x, &offset_y); - ArrowLocationGtk old_location = current_arrow_location_; + FrameStyle old_frame_style = actual_frame_style_; GtkAllocation allocation; gtk_widget_get_allocation(window_, &allocation); - current_arrow_location_ = GetArrowLocation( - preferred_arrow_location_, + actual_frame_style_ = GetAllowedFrameStyle( + requested_frame_style_, toplevel_x + offset_x + (rect_.width() / 2), // arrow_x toplevel_y + offset_y, allocation.width, allocation.height); - if (force_move_and_reshape || current_arrow_location_ != old_location) { + if (force_move_and_reshape || actual_frame_style_ != old_frame_style) { UpdateWindowShape(); MoveWindow(); // We need to redraw the entire window to repaint its border. @@ -391,7 +449,7 @@ void BubbleGtk::UpdateWindowShape() { GtkAllocation allocation; gtk_widget_get_allocation(window_, &allocation); std::vector<GdkPoint> points = MakeFramePolygonPoints( - current_arrow_location_, allocation.width, allocation.height, + actual_frame_style_, allocation.width, allocation.height, FRAME_MASK); mask_region_ = gdk_region_polygon(&points[0], points.size(), @@ -414,17 +472,28 @@ void BubbleGtk::MoveWindow() { gtk_widget_translate_coordinates(anchor_widget_, toplevel_window_, rect_.x(), rect_.y(), &offset_x, &offset_y); - GtkAllocation allocation; - gtk_widget_get_allocation(window_, &allocation); - gint screen_x = 0; - if (!HasArrow(current_arrow_location_) || - IsArrowMiddle(current_arrow_location_)) { + if (IsFixed(actual_frame_style_)) { + GtkAllocation toplevel_allocation; + gtk_widget_get_allocation(toplevel_window_, &toplevel_allocation); + + GtkAllocation bubble_allocation; + gtk_widget_get_allocation(window_, &bubble_allocation); + + int x_offset = actual_frame_style_ == FIXED_TOP_LEFT ? + kFixedPositionPaddingEnd : + toplevel_allocation.width - bubble_allocation.width - + kFixedPositionPaddingEnd; + screen_x = toplevel_x + x_offset; + } else if (!HasArrow(actual_frame_style_) || + IsArrowMiddle(actual_frame_style_)) { + GtkAllocation allocation; + gtk_widget_get_allocation(window_, &allocation); screen_x = toplevel_x + offset_x + (rect_.width() / 2) - allocation.width / 2; - } else if (IsArrowLeft(current_arrow_location_)) { + } else if (IsArrowLeft(actual_frame_style_)) { screen_x = toplevel_x + offset_x + (rect_.width() / 2) - kArrowX; - } else if (IsArrowRight(current_arrow_location_)) { + } else if (IsArrowRight(actual_frame_style_)) { GtkAllocation allocation; gtk_widget_get_allocation(window_, &allocation); screen_x = toplevel_x + offset_x + (rect_.width() / 2) - @@ -434,10 +503,14 @@ void BubbleGtk::MoveWindow() { } gint screen_y = toplevel_y + offset_y + rect_.height(); - if (IsArrowTop(current_arrow_location_) || - current_arrow_location_ == ARROW_LOCATION_NONE) { + if (IsFixed(actual_frame_style_)) { + screen_y = toplevel_y + kFixedPositionPaddingTop; + } else if (IsArrowTop(actual_frame_style_) || + actual_frame_style_ == FLOAT_BELOW_RECT) { screen_y += kArrowToContentPadding; } else { + GtkAllocation allocation; + gtk_widget_get_allocation(window_, &allocation); screen_y -= allocation.height + kArrowToContentPadding; } @@ -579,7 +652,7 @@ gboolean BubbleGtk::OnExpose(GtkWidget* widget, GdkEventExpose* expose) { GtkAllocation allocation; gtk_widget_get_allocation(window_, &allocation); std::vector<GdkPoint> points = MakeFramePolygonPoints( - current_arrow_location_, allocation.width, allocation.height, + actual_frame_style_, allocation.width, allocation.height, FRAME_STROKE); gdk_draw_polygon(drawable, gc, FALSE, &points[0], points.size()); @@ -599,10 +672,9 @@ gboolean BubbleGtk::OnExpose(GtkWidget* widget, GdkEventExpose* expose) { // and apply our shape mask region. void BubbleGtk::OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) { - if (!UpdateArrowLocation(false)) { + if (!UpdateFrameStyle(false)) { UpdateWindowShape(); - if (current_arrow_location_ != ARROW_LOCATION_TOP_LEFT) - MoveWindow(); + MoveWindow(); } } @@ -671,7 +743,7 @@ void BubbleGtk::OnForeshadowWidgetHide(GtkWidget* widget) { gboolean BubbleGtk::OnToplevelConfigure(GtkWidget* widget, GdkEventConfigure* event) { - if (!UpdateArrowLocation(false)) + if (!UpdateFrameStyle(false)) MoveWindow(); StackWindow(); return FALSE; @@ -684,7 +756,7 @@ gboolean BubbleGtk::OnToplevelUnmap(GtkWidget* widget, GdkEvent* event) { void BubbleGtk::OnAnchorAllocate(GtkWidget* widget, GtkAllocation* allocation) { - if (!UpdateArrowLocation(false)) + if (!UpdateFrameStyle(false)) MoveWindow(); } diff --git a/chrome/browser/ui/gtk/bubble/bubble_gtk.h b/chrome/browser/ui/gtk/bubble/bubble_gtk.h index 5005b30..d076556 100644 --- a/chrome/browser/ui/gtk/bubble/bubble_gtk.h +++ b/chrome/browser/ui/gtk/bubble/bubble_gtk.h @@ -48,37 +48,40 @@ class BubbleDelegateGtk { // calling Close(). class BubbleGtk : public content::NotificationObserver { public: - // Where should the arrow be placed relative to the bubble? - enum ArrowLocationGtk { - ARROW_LOCATION_TOP_LEFT, - ARROW_LOCATION_TOP_MIDDLE, - ARROW_LOCATION_TOP_RIGHT, - ARROW_LOCATION_BOTTOM_LEFT, - ARROW_LOCATION_BOTTOM_MIDDLE, - ARROW_LOCATION_BOTTOM_RIGHT, - ARROW_LOCATION_NONE, // No arrow. Positioned under the supplied rect. - ARROW_LOCATION_FLOAT, // No arrow. Centered over the supplied rect. + // The style of the frame of the bubble (includes positioning and arrow). + enum FrameStyle { + ANCHOR_TOP_LEFT, + ANCHOR_TOP_MIDDLE, + ANCHOR_TOP_RIGHT, + ANCHOR_BOTTOM_LEFT, + ANCHOR_BOTTOM_MIDDLE, + ANCHOR_BOTTOM_RIGHT, + FLOAT_BELOW_RECT, // No arrow. Positioned under the supplied rect. + CENTER_OVER_RECT, // No arrow. Centered over the supplied rect. + FIXED_TOP_LEFT, // No arrow. Shown at top left of |toplevel_window_|. + FIXED_TOP_RIGHT, // No arrow. Shown at top right of |toplevel_window_|. }; enum BubbleAttribute { NONE = 0, - MATCH_SYSTEM_THEME = 1 << 0, // Matches system colors/themes when possible. - POPUP_WINDOW = 1 << 1, // Displays as popup instead of top-level window. - GRAB_INPUT = 1 << 2, // Causes bubble to grab keyboard/pointer input. + MATCH_SYSTEM_THEME = 1 << 0, // Matches system colors/themes when possible. + POPUP_WINDOW = 1 << 1, // Displays as popup instead of top-level window. + GRAB_INPUT = 1 << 2, // Causes bubble to grab keyboard/pointer input. }; // 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. + // will be drawn according to |frame_style| if possible, and will be + // automatically flipped in RTL locales. 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, + FrameStyle frame_style, int attribute_flags, GtkThemeService* provider, BubbleDelegateGtk* delegate); @@ -109,40 +112,40 @@ class BubbleGtk : public content::NotificationObserver { FRAME_STROKE, }; - BubbleGtk(GtkThemeService* provider, int attribute_flags); + BubbleGtk(GtkThemeService* provider, + FrameStyle frame_style, + int attribute_flags); virtual ~BubbleGtk(); // Creates the Bubble. void Init(GtkWidget* anchor_widget, const gfx::Rect* rect, GtkWidget* content, - ArrowLocationGtk arrow_location, int attribute_flags); // Make the points for our polygon frame, either for fill (the mask), or for // when we stroke the border. static std::vector<GdkPoint> MakeFramePolygonPoints( - ArrowLocationGtk arrow_location, + FrameStyle frame_style, 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| (or |arrow_y|) is the X component (or - // Y component) in screen coordinates of the point at which the bubble's arrow - // should be aimed, respectively. |width| (or |height|) is the bubble's width - // (or height). - static ArrowLocationGtk GetArrowLocation(ArrowLocationGtk preferred_location, - int arrow_x, - int arrow_y, - int width, - int height); - - // 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); + // Get the allowed frame style (which is a function of the preferred style and + // of the direction that the bubble should be facing to fit onscreen). + // |arrow_x| (or |arrow_y|) is the X component (or Y component) in screen + // coordinates of the point at which the bubble's arrow should be aimed, + // respectively. |width| (or |height|) is the bubble's width (or height). + static FrameStyle GetAllowedFrameStyle(FrameStyle preferred_location, + int arrow_x, + int arrow_y, + int width, + int height); + + // Updates the frame style 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 UpdateFrameStyle(bool force_move_and_reshape); // Reshapes the window and updates |mask_region_|. void UpdateWindowShape(); @@ -209,10 +212,13 @@ class BubbleGtk : public content::NotificationObserver { // 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_; + // The frame style given to |Show()| that will attempt to be used. It will be + // flipped in RTL. If there's not enough screen space for the given + // FrameStyle, this may be changed and differ from |actual_frame_style_|. + FrameStyle requested_frame_style_; + + // The currently used frame style given screen size and directionality. + FrameStyle actual_frame_style_; // Whether the background should match the system theme, when the system theme // is being used. For example, the bookmark bubble does, but extension popups diff --git a/chrome/browser/ui/gtk/bubble/bubble_gtk_browsertest.cc b/chrome/browser/ui/gtk/bubble/bubble_gtk_browsertest.cc index dbf4cb8..b7c54ab 100644 --- a/chrome/browser/ui/gtk/bubble/bubble_gtk_browsertest.cc +++ b/chrome/browser/ui/gtk/bubble/bubble_gtk_browsertest.cc @@ -44,31 +44,31 @@ class BubbleGtkTest : public InProcessBrowserTest, // Tests that we can adjust a bubble arrow so we can show a bubble without being // clipped. This test verifies the following four issues: -// 1. Shows a bubble to the top-left corner and see its arrow location always -// becomes ARROW_LOCATION_TOP_LEFT. -// 2. Shows a bubble to the top-right corner and see its arrow location always -// becomes ARROW_LOCATION_TOP_RIGHT. -// 3. Shows a bubble to the bottom-left corner and see its arrow location always -// becomes ARROW_LOCATION_BOTTOM_LEFT. -// 4. Shows a bubble to the top-left corner and see its arrow location always -// becomes ARROW_LOCATION_BOTTOM_RIGHT. +// 1. Shows a bubble to the top-left corner and see its frame style always +// becomes ANCHOR_TOP_LEFT. +// 2. Shows a bubble to the top-right corner and see its frame style always +// becomes ANCHOR_TOP_RIGHT. +// 3. Shows a bubble to the bottom-left corner and see its frame style always +// becomes ANCHOR_BOTTOM_LEFT. +// 4. Shows a bubble to the top-left corner and see its frame style always +// becomes ANCHOR_BOTTOM_RIGHT. IN_PROC_BROWSER_TEST_F(BubbleGtkTest, ArrowLocation) { int width = gdk_screen_get_width(gdk_screen_get_default()); int height = gdk_screen_get_height(gdk_screen_get_default()); struct { int x, y; - BubbleGtk::ArrowLocationGtk expected; + BubbleGtk::FrameStyle expected; } points[] = { - {0, 0, BubbleGtk::ARROW_LOCATION_TOP_LEFT}, - {width - 1, 0, BubbleGtk::ARROW_LOCATION_TOP_RIGHT}, - {0, height - 1, BubbleGtk::ARROW_LOCATION_BOTTOM_LEFT}, - {width - 1, height - 1, BubbleGtk::ARROW_LOCATION_BOTTOM_RIGHT}, + {0, 0, BubbleGtk::ANCHOR_TOP_LEFT}, + {width - 1, 0, BubbleGtk::ANCHOR_TOP_RIGHT}, + {0, height - 1, BubbleGtk::ANCHOR_BOTTOM_LEFT}, + {width - 1, height - 1, BubbleGtk::ANCHOR_BOTTOM_RIGHT}, }; - static const BubbleGtk::ArrowLocationGtk kPreferredLocations[] = { - BubbleGtk::ARROW_LOCATION_TOP_LEFT, - BubbleGtk::ARROW_LOCATION_TOP_RIGHT, - BubbleGtk::ARROW_LOCATION_BOTTOM_LEFT, - BubbleGtk::ARROW_LOCATION_BOTTOM_RIGHT, + static const BubbleGtk::FrameStyle kPreferredLocations[] = { + BubbleGtk::ANCHOR_TOP_LEFT, + BubbleGtk::ANCHOR_TOP_RIGHT, + BubbleGtk::ANCHOR_BOTTOM_LEFT, + BubbleGtk::ANCHOR_BOTTOM_RIGHT, }; GtkWidget* anchor = GetNativeBrowserWindow(); @@ -89,7 +89,7 @@ IN_PROC_BROWSER_TEST_F(BubbleGtkTest, ArrowLocation) { BubbleGtk::GRAB_INPUT, theme_service, this); - EXPECT_EQ(points[i].expected, bubble->current_arrow_location_); + EXPECT_EQ(points[i].expected, bubble->actual_frame_style_); bubble->Close(); } } @@ -100,16 +100,16 @@ IN_PROC_BROWSER_TEST_F(BubbleGtkTest, NoArrow) { int height = gdk_screen_get_height(gdk_screen_get_default()); struct { int x, y; - BubbleGtk::ArrowLocationGtk expected; + BubbleGtk::FrameStyle expected; } points[] = { - {0, 0, BubbleGtk::ARROW_LOCATION_NONE}, - {width - 1, 0, BubbleGtk::ARROW_LOCATION_NONE}, - {0, height - 1, BubbleGtk::ARROW_LOCATION_FLOAT}, - {width - 1, height - 1, BubbleGtk::ARROW_LOCATION_FLOAT}, + {0, 0, BubbleGtk::FLOAT_BELOW_RECT}, + {width - 1, 0, BubbleGtk::FLOAT_BELOW_RECT}, + {0, height - 1, BubbleGtk::CENTER_OVER_RECT}, + {width - 1, height - 1, BubbleGtk::CENTER_OVER_RECT}, }; - static const BubbleGtk::ArrowLocationGtk kPreferredLocations[] = { - BubbleGtk::ARROW_LOCATION_NONE, - BubbleGtk::ARROW_LOCATION_FLOAT, + static const BubbleGtk::FrameStyle kPreferredLocations[] = { + BubbleGtk::FLOAT_BELOW_RECT, + BubbleGtk::CENTER_OVER_RECT, }; GtkWidget* anchor = GetNativeBrowserWindow(); @@ -130,7 +130,7 @@ IN_PROC_BROWSER_TEST_F(BubbleGtkTest, NoArrow) { BubbleGtk::GRAB_INPUT, theme_service, this); - EXPECT_EQ(points[i].expected, bubble->current_arrow_location_); + EXPECT_EQ(points[i].expected, bubble->actual_frame_style_); bubble->Close(); } } diff --git a/chrome/browser/ui/gtk/chrome_to_mobile_bubble_gtk.cc b/chrome/browser/ui/gtk/chrome_to_mobile_bubble_gtk.cc index 870bc7f..6e7b5e4 100644 --- a/chrome/browser/ui/gtk/chrome_to_mobile_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/chrome_to_mobile_bubble_gtk.cc @@ -245,11 +245,10 @@ ChromeToMobileBubbleGtk::ChromeToMobileBubbleGtk(GtkWidget* anchor_widget, // Initialize focus to the send button. gtk_container_set_focus_child(GTK_CONTAINER(content), send_); - BubbleGtk::ArrowLocationGtk arrow_location = base::i18n::IsRTL() ? - BubbleGtk::ARROW_LOCATION_TOP_LEFT : BubbleGtk::ARROW_LOCATION_TOP_RIGHT; + BubbleGtk::FrameStyle frame_style = BubbleGtk::ANCHOR_TOP_RIGHT; const int attribute_flags = BubbleGtk::MATCH_SYSTEM_THEME | BubbleGtk::POPUP_WINDOW | BubbleGtk::GRAB_INPUT; - bubble_ = BubbleGtk::Show(anchor_widget_, NULL, content, arrow_location, + bubble_ = BubbleGtk::Show(anchor_widget_, NULL, content, frame_style, attribute_flags, theme_service_, this /*delegate*/); if (!bubble_) { NOTREACHED(); diff --git a/chrome/browser/ui/gtk/confirm_bubble_gtk.cc b/chrome/browser/ui/gtk/confirm_bubble_gtk.cc index 28aba96..7822767 100644 --- a/chrome/browser/ui/gtk/confirm_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/confirm_bubble_gtk.cc @@ -139,7 +139,7 @@ void ConfirmBubbleGtk::Show() { bubble_ = BubbleGtk::Show(anchor_, &rect, content, - BubbleGtk::ARROW_LOCATION_NONE, + BubbleGtk::FLOAT_BELOW_RECT, BubbleGtk::MATCH_SYSTEM_THEME | BubbleGtk::POPUP_WINDOW | BubbleGtk::GRAB_INPUT, diff --git a/chrome/browser/ui/gtk/content_setting_bubble_gtk.cc b/chrome/browser/ui/gtk/content_setting_bubble_gtk.cc index 8c60c61..6430802 100644 --- a/chrome/browser/ui/gtk/content_setting_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/content_setting_bubble_gtk.cc @@ -258,14 +258,10 @@ void ContentSettingBubbleGtk::BuildBubble() { gtk_widget_grab_focus(bottom_box); gtk_widget_grab_focus(button); - BubbleGtk::ArrowLocationGtk arrow_location = - !base::i18n::IsRTL() ? - BubbleGtk::ARROW_LOCATION_TOP_RIGHT : - BubbleGtk::ARROW_LOCATION_TOP_LEFT; bubble_ = BubbleGtk::Show(anchor_, NULL, bubble_content, - arrow_location, + BubbleGtk::ANCHOR_TOP_RIGHT, BubbleGtk::MATCH_SYSTEM_THEME | BubbleGtk::POPUP_WINDOW | BubbleGtk::GRAB_INPUT, diff --git a/chrome/browser/ui/gtk/extensions/bundle_installed_bubble_gtk.cc b/chrome/browser/ui/gtk/extensions/bundle_installed_bubble_gtk.cc index 0211c5e..792642b 100644 --- a/chrome/browser/ui/gtk/extensions/bundle_installed_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/extensions/bundle_installed_bubble_gtk.cc @@ -91,15 +91,12 @@ void BundleInstalledBubbleGtk::ShowInternal(const BundleInstaller* bundle) { gtk_box_pack_start(GTK_BOX(close_column), close_button_->widget(), FALSE, FALSE, 0); - BubbleGtk::ArrowLocationGtk arrow_location = - !base::i18n::IsRTL() ? BubbleGtk::ARROW_LOCATION_TOP_RIGHT : - BubbleGtk::ARROW_LOCATION_TOP_LEFT; gfx::Rect bounds = gtk_util::WidgetBounds(reference_widget); bubble_ = BubbleGtk::Show(reference_widget, &bounds, bubble_content, - arrow_location, + BubbleGtk::ANCHOR_TOP_RIGHT, BubbleGtk::MATCH_SYSTEM_THEME | BubbleGtk::POPUP_WINDOW | BubbleGtk::GRAB_INPUT, 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 08f3f39..724f1a1 100644 --- a/chrome/browser/ui/gtk/extensions/extension_installed_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/extensions/extension_installed_bubble_gtk.cc @@ -327,20 +327,14 @@ void ExtensionInstalledBubbleGtk::ShowInternal() { gtk_box_pack_start(GTK_BOX(close_column), close_button_->widget(), FALSE, FALSE, 0); - BubbleGtk::ArrowLocationGtk arrow_location = - !base::i18n::IsRTL() ? - BubbleGtk::ARROW_LOCATION_TOP_RIGHT : - BubbleGtk::ARROW_LOCATION_TOP_LEFT; + BubbleGtk::FrameStyle frame_style = BubbleGtk::ANCHOR_TOP_RIGHT; gfx::Rect bounds = gtk_util::WidgetBounds(reference_widget); if (type_ == OMNIBOX_KEYWORD) { // Reverse the arrow for omnibox keywords, since the bubble will be on the // other side of the window. We also clear the width to avoid centering // the popup on the URL bar. - arrow_location = - !base::i18n::IsRTL() ? - BubbleGtk::ARROW_LOCATION_TOP_LEFT : - BubbleGtk::ARROW_LOCATION_TOP_RIGHT; + frame_style = BubbleGtk::ANCHOR_TOP_LEFT; if (base::i18n::IsRTL()) bounds.Offset(bounds.width(), 0); bounds.set_width(0); @@ -349,7 +343,7 @@ void ExtensionInstalledBubbleGtk::ShowInternal() { bubble_ = BubbleGtk::Show(reference_widget, &bounds, bubble_content, - arrow_location, + frame_style, BubbleGtk::MATCH_SYSTEM_THEME | BubbleGtk::POPUP_WINDOW | BubbleGtk::GRAB_INPUT, diff --git a/chrome/browser/ui/gtk/extensions/extension_popup_gtk.cc b/chrome/browser/ui/gtk/extensions/extension_popup_gtk.cc index e0b0605..42c95da 100644 --- a/chrome/browser/ui/gtk/extensions/extension_popup_gtk.cc +++ b/chrome/browser/ui/gtk/extensions/extension_popup_gtk.cc @@ -185,14 +185,10 @@ 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. - BubbleGtk::ArrowLocationGtk arrow_location = - !base::i18n::IsRTL() ? - BubbleGtk::ARROW_LOCATION_TOP_RIGHT : - BubbleGtk::ARROW_LOCATION_TOP_LEFT; bubble_ = BubbleGtk::Show(anchor_, NULL, border_box, - arrow_location, + BubbleGtk::ANCHOR_TOP_RIGHT, being_inspected_ ? 0 : BubbleGtk::POPUP_WINDOW | BubbleGtk::GRAB_INPUT, GtkThemeService::GetFrom(browser_->profile()), diff --git a/chrome/browser/ui/gtk/first_run_bubble.cc b/chrome/browser/ui/gtk/first_run_bubble.cc index a0776b9..7207758 100644 --- a/chrome/browser/ui/gtk/first_run_bubble.cc +++ b/chrome/browser/ui/gtk/first_run_bubble.cc @@ -69,12 +69,10 @@ FirstRunBubble::FirstRunBubble(Browser* browser, gtk_box_pack_start(GTK_BOX(content), top_line, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(content), subtext, FALSE, FALSE, 0); - BubbleGtk::ArrowLocationGtk arrow_location = !base::i18n::IsRTL() ? - BubbleGtk::ARROW_LOCATION_TOP_LEFT : BubbleGtk::ARROW_LOCATION_TOP_RIGHT; bubble_ = BubbleGtk::Show(anchor, &rect, content, - arrow_location, + BubbleGtk::ANCHOR_TOP_LEFT, BubbleGtk::MATCH_SYSTEM_THEME | BubbleGtk::POPUP_WINDOW | BubbleGtk::GRAB_INPUT, diff --git a/chrome/browser/ui/gtk/global_error_bubble.cc b/chrome/browser/ui/gtk/global_error_bubble.cc index ea6c6c1..c28cb49 100644 --- a/chrome/browser/ui/gtk/global_error_bubble.cc +++ b/chrome/browser/ui/gtk/global_error_bubble.cc @@ -101,14 +101,10 @@ GlobalErrorBubble::GlobalErrorBubble(Browser* browser, g_signal_connect(bottom, "realize", G_CALLBACK(OnBottomRealizeThunk), this); - BubbleGtk::ArrowLocationGtk arrow_location = - base::i18n::IsRTL() ? - BubbleGtk::ARROW_LOCATION_TOP_LEFT : - BubbleGtk::ARROW_LOCATION_TOP_RIGHT; bubble_ = BubbleGtk::Show(anchor, NULL, content, - arrow_location, + BubbleGtk::ANCHOR_TOP_RIGHT, BubbleGtk::MATCH_SYSTEM_THEME | BubbleGtk::POPUP_WINDOW | BubbleGtk::GRAB_INPUT, diff --git a/chrome/browser/ui/gtk/location_bar_view_gtk.cc b/chrome/browser/ui/gtk/location_bar_view_gtk.cc index fc11c4b..ac0abc3 100644 --- a/chrome/browser/ui/gtk/location_bar_view_gtk.cc +++ b/chrome/browser/ui/gtk/location_bar_view_gtk.cc @@ -620,6 +620,10 @@ void LocationBarViewGtk::Init(bool popup_window_mode) { registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOCATION_BAR_UPDATED, content::Source<Profile>(browser()->profile())); + registrar_.Add(this, + chrome::NOTIFICATION_FULLSCREEN_CHANGED, + content::Source<FullscreenController>( + browser()->fullscreen_controller())); edit_bookmarks_enabled_.Init(prefs::kEditBookmarksEnabled, profile->GetPrefs(), base::Bind(&LocationBarViewGtk::UpdateStarIcon, @@ -751,7 +755,7 @@ void LocationBarViewGtk::Update(const WebContents* contents) { } else { gtk_widget_queue_draw(widget()); } - ZoomBubbleGtk::Close(); + ZoomBubbleGtk::CloseBubble(); } void LocationBarViewGtk::OnAutocompleteAccept(const GURL& url, @@ -1184,6 +1188,11 @@ void LocationBarViewGtk::Observe(int type, break; } + case chrome::NOTIFICATION_FULLSCREEN_CHANGED: { + ZoomBubbleGtk::CloseBubble(); + break; + } + default: NOTREACHED(); } @@ -1523,7 +1532,7 @@ gboolean LocationBarViewGtk::OnZoomButtonPress(GtkWidget* widget, if (event->button == 1 && GetWebContents()) { // If the zoom icon is clicked, show the zoom bubble and keep it open until // it loses focus. - ZoomBubbleGtk::Show(zoom_.get(), GetWebContents(), false); + ZoomBubbleGtk::ShowBubble(GetZoomBubbleAnchor(), GetWebContents(), false); return TRUE; } return FALSE; @@ -1575,7 +1584,14 @@ void LocationBarViewGtk::ShowZoomBubble() { if (!zoom_.get() || toolbar_model_->GetInputInProgress()) return; - ZoomBubbleGtk::Show(zoom_.get(), GetWebContents(), true); + ZoomBubbleGtk::ShowBubble(GetZoomBubbleAnchor(), GetWebContents(), true); +} + +GtkWidget* LocationBarViewGtk::GetZoomBubbleAnchor() { + // |browser_->window()| is null until |browser_->CreateBrowserWindow()| has + // been called. + return browser_->window() && browser_->window()->IsFullscreen() ? + GTK_WIDGET(browser()->window()->GetNativeWindow()) : zoom_.get(); } void LocationBarViewGtk::ShowStarBubble(const GURL& url, @@ -1622,7 +1638,7 @@ void LocationBarViewGtk::UpdateZoomIcon() { if (!zoom_controller || zoom_controller->IsAtDefaultZoom() || toolbar_model_->GetInputInProgress()) { gtk_widget_hide(zoom_.get()); - ZoomBubbleGtk::Close(); + ZoomBubbleGtk::CloseBubble(); return; } diff --git a/chrome/browser/ui/gtk/location_bar_view_gtk.h b/chrome/browser/ui/gtk/location_bar_view_gtk.h index 0a2443d..e734a1f 100644 --- a/chrome/browser/ui/gtk/location_bar_view_gtk.h +++ b/chrome/browser/ui/gtk/location_bar_view_gtk.h @@ -102,9 +102,6 @@ class LocationBarViewGtk : public OmniboxEditController, // Shows the Chrome To Mobile bubble. void ShowChromeToMobileBubble(); - // Shows the bookmark bubble. - void ShowZoomBubble(); - // Happens when the zoom changes for the active tab. |can_show_bubble| will be // true if it was a user action and a bubble could be shown. void ZoomChangedForActiveTab(bool can_show_bubble); @@ -395,6 +392,13 @@ class LocationBarViewGtk : public OmniboxEditController, void ShowFirstRunBubbleInternal(); + // Get the correct zoom bubble anchor according to whether the browser window + // is fullscreen or not. + GtkWidget* GetZoomBubbleAnchor(); + + // Shows the zoom bubble. + void ShowZoomBubble(); + // Show or hide |tab_to_search_box_| and |tab_to_search_hint_| according to // the value of |show_selected_keyword_|, |show_keyword_hint_|, and the // available horizontal space in the location bar. diff --git a/chrome/browser/ui/gtk/one_click_signin_bubble_gtk.cc b/chrome/browser/ui/gtk/one_click_signin_bubble_gtk.cc index 5b64086..bbc495a 100644 --- a/chrome/browser/ui/gtk/one_click_signin_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/one_click_signin_bubble_gtk.cc @@ -78,15 +78,12 @@ OneClickSigninBubbleGtk::OneClickSigninBubbleGtk( GtkWidget* const app_menu_widget = browser_window_gtk->GetToolbar()->GetAppMenuButton(); gfx::Rect bounds = gtk_util::WidgetBounds(app_menu_widget); - BubbleGtk::ArrowLocationGtk arrow_location = base::i18n::IsRTL() ? - BubbleGtk::ARROW_LOCATION_TOP_LEFT : BubbleGtk::ARROW_LOCATION_TOP_RIGHT; - bubble_ = - BubbleGtk::Show(app_menu_widget, &bounds, bubble_content, - arrow_location, - BubbleGtk::MATCH_SYSTEM_THEME | - BubbleGtk::POPUP_WINDOW | - BubbleGtk::GRAB_INPUT, - theme_provider, this); + bubble_ = BubbleGtk::Show(app_menu_widget, &bounds, bubble_content, + BubbleGtk::ANCHOR_TOP_RIGHT, + BubbleGtk::MATCH_SYSTEM_THEME | + BubbleGtk::POPUP_WINDOW | + BubbleGtk::GRAB_INPUT, + theme_provider, this); gtk_widget_grab_focus(ok_button); } diff --git a/chrome/browser/ui/gtk/page_info_bubble_gtk.cc b/chrome/browser/ui/gtk/page_info_bubble_gtk.cc index baed55f..f33adcd 100644 --- a/chrome/browser/ui/gtk/page_info_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/page_info_bubble_gtk.cc @@ -119,13 +119,10 @@ PageInfoBubbleGtk::PageInfoBubbleGtk(gfx::NativeWindow parent, InitContents(); - 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, + BubbleGtk::ANCHOR_TOP_LEFT, BubbleGtk::MATCH_SYSTEM_THEME | BubbleGtk::POPUP_WINDOW | BubbleGtk::GRAB_INPUT, diff --git a/chrome/browser/ui/gtk/password_generation_bubble_gtk.cc b/chrome/browser/ui/gtk/password_generation_bubble_gtk.cc index 15edaf3..660d563 100644 --- a/chrome/browser/ui/gtk/password_generation_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/password_generation_bubble_gtk.cc @@ -89,7 +89,7 @@ PasswordGenerationBubbleGtk::PasswordGenerationBubbleGtk( bubble_ = BubbleGtk::Show(web_contents->GetContentNativeView(), &anchor_rect, content, - BubbleGtk::ARROW_LOCATION_TOP_LEFT, + BubbleGtk::ANCHOR_TOP_LEFT, BubbleGtk::MATCH_SYSTEM_THEME | BubbleGtk::POPUP_WINDOW | BubbleGtk::GRAB_INPUT, diff --git a/chrome/browser/ui/gtk/script_bubble_gtk.cc b/chrome/browser/ui/gtk/script_bubble_gtk.cc index 181313c..bc8c8e9 100644 --- a/chrome/browser/ui/gtk/script_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/script_bubble_gtk.cc @@ -130,14 +130,10 @@ void ScriptBubbleGtk::BuildBubble() { G_CALLBACK(&OnItemLinkClickedThunk), this); } - BubbleGtk::ArrowLocationGtk arrow_location = - !base::i18n::IsRTL() ? - BubbleGtk::ARROW_LOCATION_TOP_RIGHT : - BubbleGtk::ARROW_LOCATION_TOP_LEFT; bubble_ = BubbleGtk::Show(anchor_, NULL, bubble_content, - arrow_location, + BubbleGtk::ANCHOR_TOP_RIGHT, BubbleGtk::MATCH_SYSTEM_THEME | BubbleGtk::POPUP_WINDOW | BubbleGtk::GRAB_INPUT, diff --git a/chrome/browser/ui/gtk/speech_recognition_bubble_gtk.cc b/chrome/browser/ui/gtk/speech_recognition_bubble_gtk.cc index c712723..a5acd69 100644 --- a/chrome/browser/ui/gtk/speech_recognition_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/speech_recognition_bubble_gtk.cc @@ -197,7 +197,7 @@ void SpeechRecognitionBubbleGtk::Show() { bubble_ = BubbleGtk::Show(reference_widget, &target_rect, content, - BubbleGtk::ARROW_LOCATION_TOP_LEFT, + BubbleGtk::ANCHOR_TOP_LEFT, BubbleGtk::POPUP_WINDOW | BubbleGtk::GRAB_INPUT, theme_provider, this); diff --git a/chrome/browser/ui/gtk/website_settings/website_settings_popup_gtk.cc b/chrome/browser/ui/gtk/website_settings/website_settings_popup_gtk.cc index a5bda8f..a3202af 100644 --- a/chrome/browser/ui/gtk/website_settings/website_settings_popup_gtk.cc +++ b/chrome/browser/ui/gtk/website_settings/website_settings_popup_gtk.cc @@ -166,9 +166,6 @@ InternalPageInfoPopupGtk::InternalPageInfoPopupGtk( gtk_widget_show_all(contents); // Create the bubble. - BubbleGtk::ArrowLocationGtk arrow_location = base::i18n::IsRTL() ? - BubbleGtk::ARROW_LOCATION_TOP_RIGHT : - BubbleGtk::ARROW_LOCATION_TOP_LEFT; BrowserWindowGtk* browser_window = BrowserWindowGtk::GetBrowserWindowForNativeWindow(parent); GtkWidget* anchor = browser_window-> @@ -176,7 +173,7 @@ InternalPageInfoPopupGtk::InternalPageInfoPopupGtk( bubble_ = BubbleGtk::Show(anchor, NULL, // |rect| contents, - arrow_location, + BubbleGtk::ANCHOR_TOP_LEFT, BubbleGtk::MATCH_SYSTEM_THEME | BubbleGtk::POPUP_WINDOW | BubbleGtk::GRAB_INPUT, @@ -239,13 +236,10 @@ WebsiteSettingsPopupGtk::WebsiteSettingsPopupGtk( InitContents(); - 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, + BubbleGtk::ANCHOR_TOP_LEFT, BubbleGtk::MATCH_SYSTEM_THEME | BubbleGtk::POPUP_WINDOW | BubbleGtk::GRAB_INPUT, diff --git a/chrome/browser/ui/gtk/zoom_bubble_gtk.cc b/chrome/browser/ui/gtk/zoom_bubble_gtk.cc index cb27846..9d82d80a 100644 --- a/chrome/browser/ui/gtk/zoom_bubble_gtk.cc +++ b/chrome/browser/ui/gtk/zoom_bubble_gtk.cc @@ -4,6 +4,7 @@ #include "chrome/browser/ui/gtk/zoom_bubble_gtk.h" +#include "base/i18n/rtl.h" #include "base/utf_string_conversions.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" @@ -33,9 +34,9 @@ const int kBubbleAnchorHeight = 25; } // namespace // static -void ZoomBubbleGtk::Show(GtkWidget* anchor, - content::WebContents* web_contents, - bool auto_close) { +void ZoomBubbleGtk::ShowBubble(GtkWidget* anchor, + content::WebContents* web_contents, + bool auto_close) { // If the bubble is already showing and its |auto_close_| value is equal to // |auto_close|, the bubble can be reused and only the label text needs to // be updated. @@ -47,7 +48,7 @@ void ZoomBubbleGtk::Show(GtkWidget* anchor, // If the bubble is already showing but its |auto_close_| value is not equal // to |auto_close|, the bubble's focus properties must change, so the // current bubble must be closed and a new one created. - Close(); + CloseBubble(); DCHECK(!g_bubble); g_bubble = new ZoomBubbleGtk(anchor, web_contents, auto_close); @@ -55,9 +56,14 @@ void ZoomBubbleGtk::Show(GtkWidget* anchor, } // static -void ZoomBubbleGtk::Close() { +void ZoomBubbleGtk::CloseBubble() { if (g_bubble) - g_bubble->CloseBubble(); + g_bubble->Close(); +} + +// static +bool ZoomBubbleGtk::IsShowing() { + return g_bubble != NULL; } ZoomBubbleGtk::ZoomBubbleGtk(GtkWidget* anchor, @@ -104,11 +110,11 @@ ZoomBubbleGtk::ZoomBubbleGtk(GtkWidget* anchor, gtk_container_set_focus_child(GTK_CONTAINER(container), NULL); - gfx::Rect rect(kBubbleAnchorWidth, kBubbleAnchorHeight); - BubbleGtk::ArrowLocationGtk arrow_location = - BubbleGtk::ARROW_LOCATION_TOP_MIDDLE; + gfx::Rect rect = gfx::Rect(kBubbleAnchorWidth, kBubbleAnchorHeight); + BubbleGtk::FrameStyle frame_style = gtk_widget_is_toplevel(anchor) ? + BubbleGtk::FIXED_TOP_RIGHT : BubbleGtk::ANCHOR_TOP_MIDDLE; int bubble_options = BubbleGtk::MATCH_SYSTEM_THEME | BubbleGtk::POPUP_WINDOW; - bubble_ = BubbleGtk::Show(anchor, &rect, event_box_, arrow_location, + bubble_ = BubbleGtk::Show(anchor, &rect, event_box_, frame_style, auto_close ? bubble_options : bubble_options | BubbleGtk::GRAB_INPUT, theme_service, NULL); @@ -167,7 +173,7 @@ void ZoomBubbleGtk::StartTimerIfNecessary() { FROM_HERE, base::TimeDelta::FromMilliseconds(kBubbleCloseDelay), this, - &ZoomBubbleGtk::CloseBubble); + &ZoomBubbleGtk::Close); } } @@ -176,7 +182,7 @@ void ZoomBubbleGtk::StopTimerIfNecessary() { timer_.Stop(); } -void ZoomBubbleGtk::CloseBubble() { +void ZoomBubbleGtk::Close() { DCHECK(bubble_); bubble_->Close(); } diff --git a/chrome/browser/ui/gtk/zoom_bubble_gtk.h b/chrome/browser/ui/gtk/zoom_bubble_gtk.h index c4d8397..fe79917 100644 --- a/chrome/browser/ui/gtk/zoom_bubble_gtk.h +++ b/chrome/browser/ui/gtk/zoom_bubble_gtk.h @@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_UI_GTK_ZOOM_BUBBLE_GTK_H_ #define CHROME_BROWSER_UI_GTK_ZOOM_BUBBLE_GTK_H_ +#include <gtk/gtk.h> + #include "base/basictypes.h" #include "base/timer.h" #include "chrome/browser/ui/gtk/bubble/bubble_gtk.h" @@ -18,13 +20,18 @@ class WebContents; class ZoomBubbleGtk { public: - // Shows the zoom bubble, pointing at |anchor_widget|. - static void Show(GtkWidget* anchor, - content::WebContents* web_contents, - bool auto_close); + // Shows the zoom bubble below |anchor_widget| with an arrow pointing at + // |anchor_widget|. If |anchor_widget| is a toplevel window, the bubble will + // fixed positioned in the top right of corner of the widget with no arrow. + static void ShowBubble(GtkWidget* anchor, + content::WebContents* web_contents, + bool auto_close); - // Closes the zoom bubble. - static void Close(); + // Whether the zoom bubble is currently showing. + static bool IsShowing(); + + // Closes the zoom bubble (if there is one). + static void CloseBubble(); private: ZoomBubbleGtk(GtkWidget* anchor, @@ -44,7 +51,7 @@ class ZoomBubbleGtk { void Refresh(); // Closes the zoom bubble. - void CloseBubble(); + void Close(); // Notified when the bubble is destroyed so this instance can be deleted. CHROMEGTK_CALLBACK_0(ZoomBubbleGtk, void, OnDestroy); |