summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk
diff options
context:
space:
mode:
authorestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-27 21:55:21 +0000
committerestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-27 21:55:21 +0000
commitdcf05d0dff7ed3392ba91eeebd06712a609d0ccc (patch)
treee6d2067b4776daf2da7a8cae4664f06cc72bfc20 /chrome/browser/gtk
parentef0258273377dcaf33058194241af360e0961f0e (diff)
downloadchromium_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.cc109
-rw-r--r--chrome/browser/gtk/info_bubble_gtk.h14
-rw-r--r--chrome/browser/gtk/location_bar_view_gtk.cc7
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())),