| Index: chrome/browser/gtk/info_bubble_gtk.cc
|
| diff --git a/chrome/browser/gtk/info_bubble_gtk.cc b/chrome/browser/gtk/info_bubble_gtk.cc
|
| index 68fbc2d3470b9ee904f7fa46bf7ce5c9bd4bffea..a480905abf1ac09c97e67df271877a007c09883a 100644
|
| --- a/chrome/browser/gtk/info_bubble_gtk.cc
|
| +++ b/chrome/browser/gtk/info_bubble_gtk.cc
|
| @@ -47,10 +47,11 @@ const GdkColor kFrameColor = GDK_COLOR_RGB(0x63, 0x63, 0x63);
|
| InfoBubbleGtk* InfoBubbleGtk::Show(GtkWindow* toplevel_window,
|
| const gfx::Rect& rect,
|
| GtkWidget* content,
|
| + ArrowLocationGtk arrow_location,
|
| GtkThemeProvider* provider,
|
| InfoBubbleGtkDelegate* delegate) {
|
| InfoBubbleGtk* bubble = new InfoBubbleGtk(provider);
|
| - bubble->Init(toplevel_window, rect, content);
|
| + bubble->Init(toplevel_window, rect, content, arrow_location);
|
| bubble->set_delegate(delegate);
|
| return bubble;
|
| }
|
| @@ -62,7 +63,8 @@ InfoBubbleGtk::InfoBubbleGtk(GtkThemeProvider* provider)
|
| accel_group_(gtk_accel_group_new()),
|
| toplevel_window_(NULL),
|
| mask_region_(NULL),
|
| - arrow_location_(ARROW_LOCATION_TOP_LEFT) {
|
| + preferred_arrow_location_(ARROW_LOCATION_TOP_LEFT),
|
| + current_arrow_location_(ARROW_LOCATION_TOP_LEFT) {
|
| }
|
|
|
| InfoBubbleGtk::~InfoBubbleGtk() {
|
| @@ -85,10 +87,12 @@ InfoBubbleGtk::~InfoBubbleGtk() {
|
|
|
| void InfoBubbleGtk::Init(GtkWindow* toplevel_window,
|
| const gfx::Rect& rect,
|
| - GtkWidget* content) {
|
| + GtkWidget* content,
|
| + ArrowLocationGtk arrow_location) {
|
| DCHECK(!window_);
|
| toplevel_window_ = toplevel_window;
|
| rect_ = rect;
|
| + preferred_arrow_location_ = arrow_location;
|
|
|
| window_ = gtk_window_new(GTK_WINDOW_POPUP);
|
| gtk_widget_set_app_paintable(window_, TRUE);
|
| @@ -112,12 +116,7 @@ void InfoBubbleGtk::Init(GtkWindow* toplevel_window,
|
| // HandleSizeAllocate, so the mask can be applied to the GdkWindow.
|
| gtk_widget_realize(window_);
|
|
|
| - // For RTL, we will have to move the window again when it is allocated, but
|
| - // this should be somewhat close to its final position.
|
| - MoveWindow();
|
| - GtkRequisition req;
|
| - gtk_widget_size_request(window_, &req);
|
| -
|
| + UpdateArrowLocation(true); // Force move and reshape.
|
| StackWindow();
|
|
|
| gtk_widget_add_events(window_, GDK_BUTTON_PRESS_MASK |
|
| @@ -176,85 +175,84 @@ std::vector<GdkPoint> InfoBubbleGtk::MakeFramePolygonPoints(
|
| using gtk_util::MakeBidiGdkPoint;
|
| std::vector<GdkPoint> points;
|
|
|
| - // This name isn't completely accurate; the arrow location can differ from its
|
| - // expected location for LTR/RTL if needed for the bubble to fit onscreen.
|
| - bool ltr = (arrow_location == ARROW_LOCATION_TOP_LEFT);
|
| + bool on_left = (arrow_location == ARROW_LOCATION_TOP_LEFT);
|
|
|
| - // If we have a stroke, we have to offset some of our points by 1 pixel.
|
| - // We have to inset by 1 pixel when we draw horizontal lines that are on the
|
| - // bottom or when we draw vertical lines that are closer to the end (end is
|
| - // right for ltr).
|
| + // 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 LTR.
|
| - int x_off_l = ltr ? y_off : 0;
|
| + // 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 = !ltr ? -y_off : 0;
|
| + int x_off_r = !on_left ? -y_off : 0;
|
|
|
| // Top left corner.
|
| points.push_back(MakeBidiGdkPoint(
|
| - x_off_r, kArrowSize + kCornerSize - 1, width, ltr));
|
| + x_off_r, kArrowSize + kCornerSize - 1, width, on_left));
|
| points.push_back(MakeBidiGdkPoint(
|
| - kCornerSize + x_off_r - 1, kArrowSize, width, ltr));
|
| + kCornerSize + x_off_r - 1, kArrowSize, width, on_left));
|
|
|
| // The arrow.
|
| points.push_back(MakeBidiGdkPoint(
|
| - kArrowX - kArrowSize + x_off_r, kArrowSize, width, ltr));
|
| + kArrowX - kArrowSize + x_off_r, kArrowSize, width, on_left));
|
| points.push_back(MakeBidiGdkPoint(
|
| - kArrowX + x_off_r, 0, width, ltr));
|
| + kArrowX + x_off_r, 0, width, on_left));
|
| points.push_back(MakeBidiGdkPoint(
|
| - kArrowX + 1 + x_off_l, 0, width, ltr));
|
| + kArrowX + 1 + x_off_l, 0, width, on_left));
|
| points.push_back(MakeBidiGdkPoint(
|
| - kArrowX + kArrowSize + 1 + x_off_l, kArrowSize, width, ltr));
|
| + 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, ltr));
|
| + width - kCornerSize + 1 + x_off_l, kArrowSize, width, on_left));
|
| points.push_back(MakeBidiGdkPoint(
|
| - width + x_off_l, kArrowSize + kCornerSize - 1, width, ltr));
|
| + width + x_off_l, kArrowSize + kCornerSize - 1, width, on_left));
|
|
|
| // Bottom right corner.
|
| points.push_back(MakeBidiGdkPoint(
|
| - width + x_off_l, height - kCornerSize, width, ltr));
|
| + width + x_off_l, height - kCornerSize, width, on_left));
|
| points.push_back(MakeBidiGdkPoint(
|
| - width - kCornerSize + x_off_r, height + y_off, width, ltr));
|
| + 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, ltr));
|
| + kCornerSize + x_off_l, height + y_off, width, on_left));
|
| points.push_back(MakeBidiGdkPoint(
|
| - x_off_r, height - kCornerSize, width, ltr));
|
| + x_off_r, height - kCornerSize, width, on_left));
|
|
|
| return points;
|
| }
|
|
|
| InfoBubbleGtk::ArrowLocationGtk InfoBubbleGtk::GetArrowLocation(
|
| - int arrow_x, int width) {
|
| - bool ltr = (l10n_util::GetTextDirection() == l10n_util::LEFT_TO_RIGHT);
|
| + 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 expected location for our LTR/RTL-ness if it fits onscreen, use
|
| - // whatever fits otherwise, and use the expected location if neither fits.
|
| - if (left_is_onscreen && (ltr || !right_is_onscreen))
|
| + // 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 && (!ltr || !left_is_onscreen))
|
| + if (right_is_onscreen && (!wants_left || !left_is_onscreen))
|
| return ARROW_LOCATION_TOP_RIGHT;
|
| - return (ltr ? ARROW_LOCATION_TOP_LEFT : ARROW_LOCATION_TOP_RIGHT);
|
| + return (wants_left ? ARROW_LOCATION_TOP_LEFT : ARROW_LOCATION_TOP_RIGHT);
|
| }
|
|
|
| -bool InfoBubbleGtk::UpdateArrowLocation() {
|
| +bool InfoBubbleGtk::UpdateArrowLocation(bool force_move_and_reshape) {
|
| gint toplevel_x = 0, toplevel_y = 0;
|
| gdk_window_get_position(
|
| GTK_WIDGET(toplevel_window_)->window, &toplevel_x, &toplevel_y);
|
|
|
| - ArrowLocationGtk old_location = arrow_location_;
|
| - arrow_location_ = GetArrowLocation(
|
| + ArrowLocationGtk old_location = current_arrow_location_;
|
| + current_arrow_location_ = GetArrowLocation(
|
| + preferred_arrow_location_,
|
| toplevel_x + rect_.x() + (rect_.width() / 2), // arrow_x
|
| window_->allocation.width);
|
|
|
| - if (arrow_location_ != old_location) {
|
| + if (force_move_and_reshape || current_arrow_location_ != old_location) {
|
| UpdateWindowShape();
|
| MoveWindow();
|
| // We need to redraw the entire window to repaint its border.
|
| @@ -270,7 +268,8 @@ void InfoBubbleGtk::UpdateWindowShape() {
|
| mask_region_ = NULL;
|
| }
|
| std::vector<GdkPoint> points = MakeFramePolygonPoints(
|
| - arrow_location_, window_->allocation.width, window_->allocation.height,
|
| + current_arrow_location_,
|
| + window_->allocation.width, window_->allocation.height,
|
| FRAME_MASK);
|
| mask_region_ = gdk_region_polygon(&points[0],
|
| points.size(),
|
| @@ -284,9 +283,9 @@ void InfoBubbleGtk::MoveWindow() {
|
| GTK_WIDGET(toplevel_window_)->window, &toplevel_x, &toplevel_y);
|
|
|
| gint screen_x = 0;
|
| - if (arrow_location_ == ARROW_LOCATION_TOP_LEFT) {
|
| + if (current_arrow_location_ == ARROW_LOCATION_TOP_LEFT) {
|
| screen_x = toplevel_x + rect_.x() + (rect_.width() / 2) - kArrowX;
|
| - } else if (arrow_location_ == ARROW_LOCATION_TOP_RIGHT) {
|
| + } else if (current_arrow_location_ == ARROW_LOCATION_TOP_RIGHT) {
|
| screen_x = toplevel_x + rect_.x() + (rect_.width() / 2) -
|
| window_->allocation.width + kArrowX;
|
| } else {
|
| @@ -372,7 +371,8 @@ gboolean InfoBubbleGtk::HandleExpose() {
|
|
|
| // Stroke the frame border.
|
| std::vector<GdkPoint> points = MakeFramePolygonPoints(
|
| - arrow_location_, window_->allocation.width, window_->allocation.height,
|
| + current_arrow_location_,
|
| + window_->allocation.width, window_->allocation.height,
|
| FRAME_STROKE);
|
| gdk_draw_polygon(drawable, gc, FALSE, &points[0], points.size());
|
|
|
| @@ -383,9 +383,9 @@ gboolean InfoBubbleGtk::HandleExpose() {
|
| // When our size is initially allocated or changed, we need to recompute
|
| // and apply our shape mask region.
|
| void InfoBubbleGtk::HandleSizeAllocate() {
|
| - if (!UpdateArrowLocation()) {
|
| + if (!UpdateArrowLocation(false)) {
|
| UpdateWindowShape();
|
| - if (arrow_location_ == ARROW_LOCATION_TOP_RIGHT)
|
| + if (current_arrow_location_ == ARROW_LOCATION_TOP_RIGHT)
|
| MoveWindow();
|
| }
|
| }
|
| @@ -420,7 +420,7 @@ gboolean InfoBubbleGtk::HandleDestroy() {
|
| }
|
|
|
| gboolean InfoBubbleGtk::HandleToplevelConfigure(GdkEventConfigure* event) {
|
| - if (!UpdateArrowLocation())
|
| + if (!UpdateArrowLocation(false))
|
| MoveWindow();
|
| StackWindow();
|
| return FALSE;
|
|
|