diff options
author | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-27 21:55:21 +0000 |
---|---|---|
committer | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-27 21:55:21 +0000 |
commit | dcf05d0dff7ed3392ba91eeebd06712a609d0ccc (patch) | |
tree | e6d2067b4776daf2da7a8cae4664f06cc72bfc20 /chrome/browser/gtk | |
parent | ef0258273377dcaf33058194241af360e0961f0e (diff) | |
download | chromium_src-dcf05d0dff7ed3392ba91eeebd06712a609d0ccc.zip chromium_src-dcf05d0dff7ed3392ba91eeebd06712a609d0ccc.tar.gz chromium_src-dcf05d0dff7ed3392ba91eeebd06712a609d0ccc.tar.bz2 |
GTK: Make the info bubble (and bookmark bubble and first run bubble) bidi.
BUG=17631
Review URL: http://codereview.chromium.org/160131
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@21717 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/gtk')
-rw-r--r-- | chrome/browser/gtk/info_bubble_gtk.cc | 109 | ||||
-rw-r--r-- | chrome/browser/gtk/info_bubble_gtk.h | 14 | ||||
-rw-r--r-- | chrome/browser/gtk/location_bar_view_gtk.cc | 7 |
3 files changed, 94 insertions, 36 deletions
diff --git a/chrome/browser/gtk/info_bubble_gtk.cc b/chrome/browser/gtk/info_bubble_gtk.cc index 56a5ea5..8c7286f 100644 --- a/chrome/browser/gtk/info_bubble_gtk.cc +++ b/chrome/browser/gtk/info_bubble_gtk.cc @@ -8,6 +8,7 @@ #include <gtk/gtk.h> #include "app/gfx/path.h" +#include "app/l10n_util.h" #include "base/basictypes.h" #include "base/gfx/gtk_util.h" #include "base/gfx/rect.h" @@ -37,9 +38,8 @@ const GdkColor kFrameColor = GDK_COLOR_RGB(0x63, 0x63, 0x63); const gchar* kInfoBubbleToplevelKey = "__INFO_BUBBLE_TOPLEVEL__"; -// A small convenience since GdkPoint is a POD without a constructor. -GdkPoint MakeGdkPoint(gint x, gint y) { - GdkPoint point = {x, y}; +GdkPoint MakeBidiGdkPoint(gint x, gint y, gint width, bool ltr) { + GdkPoint point = {ltr ? x : width - x, y}; return point; } @@ -59,49 +59,54 @@ std::vector<GdkPoint> MakeFramePolygonPoints(int width, FrameType type) { std::vector<GdkPoint> points; + bool ltr = l10n_util::GetTextDirection() == l10n_util::LEFT_TO_RIGHT; // If we have a stroke, we have to offset some of our points by 1 pixel. - int off = (type == FRAME_MASK) ? 0 : 1; + // 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). + 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 RTL. + int x_off_r = !ltr ? -y_off : 0; // Top left corner. - points.push_back(MakeGdkPoint(0, kArrowSize + kCornerSize - 1)); - points.push_back(MakeGdkPoint(kCornerSize - 1, kArrowSize)); + points.push_back(MakeBidiGdkPoint( + x_off_r, kArrowSize + kCornerSize - 1, width, ltr)); + points.push_back(MakeBidiGdkPoint( + kCornerSize + x_off_r - 1, kArrowSize, width, ltr)); // The arrow. - points.push_back(MakeGdkPoint(kArrowX - kArrowSize, kArrowSize)); - points.push_back(MakeGdkPoint(kArrowX, 0)); - points.push_back(MakeGdkPoint(kArrowX + 1 - off, 0)); - points.push_back(MakeGdkPoint(kArrowX + kArrowSize + 1 - off, kArrowSize)); + points.push_back(MakeBidiGdkPoint( + kArrowX - kArrowSize + x_off_r, kArrowSize, width, ltr)); + points.push_back(MakeBidiGdkPoint( + kArrowX + x_off_r, 0, width, ltr)); + points.push_back(MakeBidiGdkPoint( + kArrowX + 1 + x_off_l, 0, width, ltr)); + points.push_back(MakeBidiGdkPoint( + kArrowX + kArrowSize + 1 + x_off_l, kArrowSize, width, ltr)); // Top right corner. - points.push_back(MakeGdkPoint(width - kCornerSize + 1 - off, kArrowSize)); - points.push_back(MakeGdkPoint(width - off, kArrowSize + kCornerSize - 1)); + points.push_back(MakeBidiGdkPoint( + width - kCornerSize + 1 + x_off_l, kArrowSize, width, ltr)); + points.push_back(MakeBidiGdkPoint( + width + x_off_l, kArrowSize + kCornerSize - 1, width, ltr)); // Bottom right corner. - points.push_back(MakeGdkPoint(width - off, height - kCornerSize)); - points.push_back(MakeGdkPoint(width - kCornerSize, height - off)); + points.push_back(MakeBidiGdkPoint( + width + x_off_l, height - kCornerSize, width, ltr)); + points.push_back(MakeBidiGdkPoint( + width - kCornerSize + x_off_r, height + y_off, width, ltr)); // Bottom left corner. - points.push_back(MakeGdkPoint(kCornerSize - off, height - off)); - points.push_back(MakeGdkPoint(0, height - kCornerSize)); + points.push_back(MakeBidiGdkPoint( + kCornerSize + x_off_l, height + y_off, width, ltr)); + points.push_back(MakeBidiGdkPoint( + x_off_r, height - kCornerSize, width, ltr)); return points; } -// When our size is initially allocated or changed, we need to recompute -// and apply our shape mask region. -void HandleSizeAllocate(GtkWidget* widget, - GtkAllocation* allocation, - gpointer unused) { - DCHECK(allocation->x == 0 && allocation->y == 0); - std::vector<GdkPoint> points = MakeFramePolygonPoints( - allocation->width, allocation->height, FRAME_MASK); - GdkRegion* mask_region = gdk_region_polygon(&points[0], - points.size(), - GDK_EVEN_ODD_RULE); - gdk_window_shape_combine_region(widget->window, mask_region, 0, 0); - gdk_region_destroy(mask_region); -} - gboolean HandleExpose(GtkWidget* widget, GdkEventExpose* event, gpointer unused) { @@ -149,8 +154,7 @@ void InfoBubbleGtk::Init(GtkWindow* transient_toplevel, const gfx::Rect& rect, GtkWidget* content) { DCHECK(!window_); - screen_x_ = rect.x() + (rect.width() / 2) - kArrowX; - screen_y_ = rect.y() + rect.height() + kArrowToContentPadding; + rect_ = rect; window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_transient_for(GTK_WINDOW(window_), transient_toplevel); @@ -180,15 +184,22 @@ void InfoBubbleGtk::Init(GtkWindow* transient_toplevel, // efficently mask a GdkRegion. Make sure the window is realized during // HandleSizeAllocate, so the mask can be applied to the GdkWindow. gtk_widget_realize(window_); + + UpdateScreenX(); + screen_y_ = rect.y() + rect.height() + kArrowToContentPadding; + // For RTL, we will have to move the window again when it is allocated, but + // this should be somewhat close to its final position. gtk_window_move(GTK_WINDOW(window_), screen_x_, screen_y_); + GtkRequisition req; + gtk_widget_size_request(window_, &req); gtk_widget_add_events(window_, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); - g_signal_connect(window_, "size-allocate", - G_CALLBACK(HandleSizeAllocate), NULL); g_signal_connect(window_, "expose-event", G_CALLBACK(HandleExpose), NULL); + g_signal_connect(window_, "size-allocate", + G_CALLBACK(HandleSizeAllocateThunk), this); g_signal_connect(window_, "configure-event", G_CALLBACK(&HandleConfigureThunk), this); g_signal_connect(window_, "button-press-event", @@ -223,6 +234,16 @@ void InfoBubbleGtk::Init(GtkWindow* transient_toplevel, theme_provider_->InitThemesFor(this); } +void InfoBubbleGtk::UpdateScreenX() { + if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) { + screen_x_ = rect_.x() + (rect_.width() / 2) - window_->allocation.width + + kArrowX; + } + else { + screen_x_ = rect_.x() + (rect_.width() / 2) - kArrowX; + } +} + void InfoBubbleGtk::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { @@ -261,6 +282,24 @@ gboolean InfoBubbleGtk::HandleEscape() { return TRUE; } +// When our size is initially allocated or changed, we need to recompute +// and apply our shape mask region. +void InfoBubbleGtk::HandleSizeAllocate() { + if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) { + UpdateScreenX(); + gtk_window_move(GTK_WINDOW(window_), screen_x_, screen_y_); + } + + DCHECK(window_->allocation.x == 0 && window_->allocation.y == 0); + std::vector<GdkPoint> points = MakeFramePolygonPoints( + window_->allocation.width, window_->allocation.height, FRAME_MASK); + GdkRegion* mask_region = gdk_region_polygon(&points[0], + points.size(), + GDK_EVEN_ODD_RULE); + gdk_window_shape_combine_region(window_->window, mask_region, 0, 0); + gdk_region_destroy(mask_region); +} + gboolean InfoBubbleGtk::HandleConfigure(GdkEventConfigure* event) { // If the window is moved someplace besides where we want it, move it back. // TODO(deanm): In the end, I will probably remove this code and just let diff --git a/chrome/browser/gtk/info_bubble_gtk.h b/chrome/browser/gtk/info_bubble_gtk.h index 7bc45b9..137b395 100644 --- a/chrome/browser/gtk/info_bubble_gtk.h +++ b/chrome/browser/gtk/info_bubble_gtk.h @@ -16,6 +16,7 @@ #include <gtk/gtk.h> #include "base/basictypes.h" +#include "base/gfx/rect.h" #include "chrome/common/notification_registrar.h" class GtkThemeProvider; @@ -70,6 +71,9 @@ class InfoBubbleGtk : public NotificationObserver { const gfx::Rect& rect, GtkWidget* content); + // Sets |screen_x_| according to our allocation and |rect_|. + void UpdateScreenX(); + // Sets the delegate. void set_delegate(InfoBubbleGtkDelegate* delegate) { delegate_ = delegate; } @@ -86,6 +90,13 @@ class InfoBubbleGtk : public NotificationObserver { } gboolean HandleEscape(); + static void HandleSizeAllocateThunk(GtkWidget* widget, + GtkAllocation* allocation, + gpointer user_data) { + reinterpret_cast<InfoBubbleGtk*>(user_data)->HandleSizeAllocate(); + } + void HandleSizeAllocate(); + static gboolean HandleConfigureThunk(GtkWidget* widget, GdkEventConfigure* event, gpointer user_data) { @@ -129,6 +140,9 @@ class InfoBubbleGtk : public NotificationObserver { // The accel group attached to |window_|, to handle closing with escape. GtkAccelGroup* accel_group_; + // The rectangle that we use to calculate |screen_x_| and |screen_y_|. + gfx::Rect rect_; + // Where we want our window to be positioned on the screen. int screen_x_; int screen_y_; diff --git a/chrome/browser/gtk/location_bar_view_gtk.cc b/chrome/browser/gtk/location_bar_view_gtk.cc index 01587ec..b1c4e66 100644 --- a/chrome/browser/gtk/location_bar_view_gtk.cc +++ b/chrome/browser/gtk/location_bar_view_gtk.cc @@ -541,9 +541,14 @@ void LocationBarViewGtk::ShowFirstRunBubbleInternal(bool use_OEM_bubble) { gdk_window_get_origin(widget()->window, &x, &y); // The bubble needs to be just below the Omnibox and slightly to the right // of star button, so shift x and y co-ordinates. - x += widget()->allocation.x + kFirstRunBubbleLeftMargin; y += widget()->allocation.y + widget()->allocation.height + kFirstRunBubbleTopMargin; + if (l10n_util::GetTextDirection() == l10n_util::LEFT_TO_RIGHT) { + x += widget()->allocation.x + kFirstRunBubbleLeftMargin; + } else { + x += widget()->allocation.x + widget()->allocation.width - + kFirstRunBubbleLeftMargin; + } FirstRunBubble::Show(profile_, GTK_WINDOW(gtk_widget_get_toplevel(widget())), |