summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorerg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-06 19:57:22 +0000
committererg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-06 19:57:22 +0000
commit1ed38c7a8e30647e1bc5c0aa857dd1ca8e8a3154 (patch)
treeb2ff03f24b674e8c5a4f12ecf46a1135df670b59
parent328f7367183ea9a87ffa76561cd3a27f97e1bc2d (diff)
downloadchromium_src-1ed38c7a8e30647e1bc5c0aa857dd1ca8e8a3154.zip
chromium_src-1ed38c7a8e30647e1bc5c0aa857dd1ca8e8a3154.tar.gz
chromium_src-1ed38c7a8e30647e1bc5c0aa857dd1ca8e8a3154.tar.bz2
GTK: Rounded corner on status bubble.
http://crbug.com/18309 Review URL: http://codereview.chromium.org/164010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22644 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/gtk/status_bubble_gtk.cc135
-rw-r--r--chrome/browser/gtk/status_bubble_gtk.h17
2 files changed, 124 insertions, 28 deletions
diff --git a/chrome/browser/gtk/status_bubble_gtk.cc b/chrome/browser/gtk/status_bubble_gtk.cc
index fb5fcc3..621edf9 100644
--- a/chrome/browser/gtk/status_bubble_gtk.cc
+++ b/chrome/browser/gtk/status_bubble_gtk.cc
@@ -7,6 +7,7 @@
#include <gtk/gtk.h>
#include "app/gfx/text_elider.h"
+#include "app/l10n_util.h"
#include "base/gfx/gtk_util.h"
#include "base/message_loop.h"
#include "base/string_util.h"
@@ -18,19 +19,70 @@
namespace {
-const GdkColor kTextColor = GDK_COLOR_RGB(100, 100, 100);
-const GdkColor kBackgroundColor = GDK_COLOR_RGB(0xe6, 0xed, 0xf4);
const GdkColor kFrameBorderColor = GDK_COLOR_RGB(0xbe, 0xc8, 0xd4);
// Inner padding between the border and the text label.
const int kInternalTopBottomPadding = 1;
const int kInternalLeftRightPadding = 2;
-// Border of color kFrameBorderColor around the status bubble.
-const int kBorderPadding = 1;
+// The radius of the edges of our bubble.
+const int kCornerSize = 4;
// Milliseconds before we hide the status bubble widget when you mouseout.
-static const int kHideDelay = 250;
+const int kHideDelay = 250;
+
+// Number of times that the background color should be counted when trying to
+// calculate the border color in GTK theme mode.
+const int kBgWeight = 3;
+
+// Reverses a point in RTL mode.
+GdkPoint MakeBidiGdkPoint(gint x, gint y, gint width, bool ltr) {
+ GdkPoint point = {ltr ? x : width - x, y};
+ return point;
+}
+
+enum FrameType {
+ FRAME_MASK,
+ FRAME_STROKE,
+};
+
+// Returns a list of points that either form the outline of the status bubble
+// (|type| == FRAME_MASK) or form the inner border around the inner edge
+// (|type| == FRAME_STROKE).
+std::vector<GdkPoint> MakeFramePolygonPoints(int width,
+ int height,
+ 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.
+ // 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;
+
+ // Top left corner.
+ points.push_back(MakeBidiGdkPoint(0, 0, width, ltr));
+
+ // Top right (rounded) corner.
+ points.push_back(MakeBidiGdkPoint(
+ width - kCornerSize + 1 + x_off_l, 0, width, ltr));
+ points.push_back(MakeBidiGdkPoint(
+ width + x_off_l, kCornerSize - 1, width, ltr));
+
+ // Bottom right corner.
+ points.push_back(MakeBidiGdkPoint(
+ width + x_off_l, height + y_off, width, ltr));
+
+ if (type == FRAME_MASK) {
+ // Bottom left corner.
+ points.push_back(MakeBidiGdkPoint(0, height + y_off, width, ltr));
+ }
+
+ return points;
+}
} // namespace
@@ -138,16 +190,18 @@ void StatusBubbleGtk::InitWidgets() {
GtkWidget* padding = gtk_alignment_new(0, 0, 1, 1);
gtk_alignment_set_padding(GTK_ALIGNMENT(padding),
kInternalTopBottomPadding, kInternalTopBottomPadding,
- kInternalLeftRightPadding, kInternalLeftRightPadding);
+ kInternalLeftRightPadding,
+ kInternalLeftRightPadding + kCornerSize);
gtk_container_add(GTK_CONTAINER(padding), label_);
- bg_box_ = gtk_event_box_new();
- gtk_container_add(GTK_CONTAINER(bg_box_), padding);
-
- container_.Own(gtk_util::CreateGtkBorderBin(bg_box_, &kFrameBorderColor,
- kBorderPadding, kBorderPadding, kBorderPadding, kBorderPadding));
+ container_.Own(gtk_event_box_new());
gtk_widget_set_name(container_.get(), "status-bubble");
+ gtk_container_add(GTK_CONTAINER(container_.get()), padding);
gtk_widget_set_app_paintable(container_.get(), TRUE);
+ g_signal_connect(G_OBJECT(container_.get()), "expose-event",
+ G_CALLBACK(OnExpose), this);
+ g_signal_connect(G_OBJECT(container_.get()), "size-allocate",
+ G_CALLBACK(OnSizeAllocate), this);
UserChangedTheme();
}
@@ -155,7 +209,21 @@ void StatusBubbleGtk::InitWidgets() {
void StatusBubbleGtk::UserChangedTheme() {
if (theme_provider_->UseGtkTheme()) {
gtk_widget_modify_fg(label_, GTK_STATE_NORMAL, NULL);
- gtk_widget_modify_bg(bg_box_, GTK_STATE_NORMAL, NULL);
+ gtk_widget_modify_bg(container_.get(), GTK_STATE_NORMAL, NULL);
+
+ // Creates a weighted average between the text and base color where
+ // the base color counts more than once.
+ GtkStyle* style = gtk_rc_get_style(container_.get());
+ border_color_.pixel = 0;
+ border_color_.red = (style->text[GTK_STATE_NORMAL].red +
+ (style->bg[GTK_STATE_NORMAL].red * kBgWeight)) /
+ (1 + kBgWeight);
+ border_color_.green = (style->text[GTK_STATE_NORMAL].green +
+ (style->bg[GTK_STATE_NORMAL].green * kBgWeight)) /
+ (1 + kBgWeight);
+ border_color_.blue = (style->text[GTK_STATE_NORMAL].blue +
+ (style->bg[GTK_STATE_NORMAL].blue * kBgWeight)) /
+ (1 + kBgWeight);
} else {
// TODO(erg): This is the closest to "text that will look good on a
// toolbar" that I can find. Maybe in later iterations of the theme system,
@@ -166,17 +234,38 @@ void StatusBubbleGtk::UserChangedTheme() {
GdkColor toolbar_color =
theme_provider_->GetGdkColor(BrowserThemeProvider::COLOR_TOOLBAR);
- gtk_widget_modify_bg(bg_box_, GTK_STATE_NORMAL, &toolbar_color);
+ gtk_widget_modify_bg(container_.get(), GTK_STATE_NORMAL, &toolbar_color);
+
+ border_color_ = kFrameBorderColor;
}
+}
- // TODO(erg): I don't know what to do with the status bubble border
- // (|container_|). There needs to be a border in GTK mode, and I'm not sure
- // which BrowserThemeProvider::COLOR I'm supposed to use here since the Views
- // implementation still uses constants in the equivalent, and it's used for
- // alpha blending instead of drawing a real border.
- //
- // This doesn't really matter because this part of the UI needs to be
- // rewritten per the UI review anyway; we should be matching windows with a
- // semi-transparent, rounded border instead of our constantly
- // CreateGtkBorderBin() usage.
+// static
+gboolean StatusBubbleGtk::OnExpose(GtkWidget* widget,
+ GdkEventExpose* event,
+ StatusBubbleGtk* bubble) {
+ GdkDrawable* drawable = GDK_DRAWABLE(event->window);
+ GdkGC* gc = gdk_gc_new(drawable);
+ gdk_gc_set_rgb_fg_color(gc, &bubble->border_color_);
+
+ // Stroke the frame border.
+ std::vector<GdkPoint> points = MakeFramePolygonPoints(
+ widget->allocation.width, widget->allocation.height, FRAME_STROKE);
+ gdk_draw_lines(drawable, gc, &points[0], points.size());
+
+ g_object_unref(gc);
+ return FALSE; // Propagate so our children paint, etc.
+}
+
+// static
+void StatusBubbleGtk::OnSizeAllocate(GtkWidget* widget,
+ GtkAllocation* allocation,
+ StatusBubbleGtk* bubble) {
+ std::vector<GdkPoint> points = MakeFramePolygonPoints(
+ widget->allocation.width, widget->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);
}
diff --git a/chrome/browser/gtk/status_bubble_gtk.h b/chrome/browser/gtk/status_bubble_gtk.h
index f5847aa..fbdc5fd 100644
--- a/chrome/browser/gtk/status_bubble_gtk.h
+++ b/chrome/browser/gtk/status_bubble_gtk.h
@@ -69,27 +69,34 @@ class StatusBubbleGtk : public StatusBubble,
// Notification from the window that we should retheme ourself.
void UserChangedTheme();
+ // Draws the inside border.
+ static gboolean OnExpose(GtkWidget* widget, GdkEventExpose* event,
+ StatusBubbleGtk* bubble);
+
+ // When we have a new size, modify our widget shape.
+ static void OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation,
+ StatusBubbleGtk* bubble);
+
NotificationRegistrar registrar_;
// Provides colors.
GtkThemeProvider* theme_provider_;
- // A GtkAlignment that is the child of |slide_widget_|.
+ // The toplevel event box.
OwnedWidgetGtk container_;
// The GtkLabel holding the text.
GtkWidget* label_;
- // The background event box. We keep this so we can change its background
- // color.
- GtkWidget* bg_box_;
-
// The status text we want to display when there are no URLs to display.
std::string status_text_;
// The url we want to display when there is no status text to display.
std::string url_text_;
+ // Color of the lighter border around the edge of the status bubble.
+ GdkColor border_color_;
+
// A timer that hides our window after a delay.
ScopedRunnableMethodFactory<StatusBubbleGtk> timer_factory_;
};