summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/gtk/find_bar_gtk.cc57
-rw-r--r--chrome/browser/gtk/find_bar_gtk.h16
-rw-r--r--chrome/browser/gtk/nine_box.cc57
-rw-r--r--chrome/browser/gtk/nine_box.h16
4 files changed, 130 insertions, 16 deletions
diff --git a/chrome/browser/gtk/find_bar_gtk.cc b/chrome/browser/gtk/find_bar_gtk.cc
index 4f84e77..14b6d51 100644
--- a/chrome/browser/gtk/find_bar_gtk.cc
+++ b/chrome/browser/gtk/find_bar_gtk.cc
@@ -11,6 +11,7 @@
#include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
#include "chrome/browser/gtk/custom_button.h"
+#include "chrome/browser/gtk/nine_box.h"
#include "chrome/browser/gtk/tab_contents_container_gtk.h"
#include "chrome/browser/tab_contents/web_contents.h"
#include "chrome/common/gtk_util.h"
@@ -42,9 +43,36 @@ gboolean KeyPressEvent(GtkWindow* window, GdkEventKey* event,
return FALSE;
}
+// Get the ninebox that draws the background of |container_|. It is also used
+// to change the shape of |container_|. The pointer is shared by all instances
+// of FindBarGtk.
+const NineBox* GetDialogBackground() {
+ static NineBox* dialog_background = NULL;
+ if (!dialog_background) {
+ dialog_background = new NineBox(
+ IDR_FIND_DLG_LEFT_BACKGROUND,
+ IDR_FIND_DLG_MIDDLE_BACKGROUND,
+ IDR_FIND_DLG_RIGHT_BACKGROUND,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ dialog_background->ChangeWhiteToTransparent();
+ }
+
+ return dialog_background;
+}
+
+// Used to handle custom painting of |container_|.
+gboolean OnExpose(GtkWidget* widget, GdkEventExpose* e, gpointer userdata) {
+ GetDialogBackground()->RenderToWidget(widget);
+ GtkWidget* child = gtk_bin_get_child(GTK_BIN(widget));
+ if (child)
+ gtk_container_propagate_expose(GTK_CONTAINER(widget), child, e);
+ return TRUE;
}
-FindBarGtk::FindBarGtk(BrowserWindowGtk* browser) {
+} // namespace
+
+FindBarGtk::FindBarGtk(BrowserWindowGtk* browser)
+ : container_shaped_(false) {
InitWidgets();
// Insert the widget into the browser gtk hierarchy.
@@ -57,7 +85,11 @@ FindBarGtk::FindBarGtk(BrowserWindowGtk* browser) {
g_signal_connect(find_text_, "key-press-event",
G_CALLBACK(KeyPressEvent), this);
g_signal_connect(widget(), "size-allocate",
- G_CALLBACK(OnSizeAllocate), this);
+ G_CALLBACK(OnFixedSizeAllocate), this);
+ // We can't call ContourWidget() until after |container| has been
+ // allocated, hence we connect to this signal.
+ g_signal_connect(container_, "size-allocate",
+ G_CALLBACK(OnContainerSizeAllocate), this);
}
FindBarGtk::~FindBarGtk() {
@@ -73,13 +105,16 @@ void FindBarGtk::InitWidgets() {
GtkWidget* hbox = gtk_hbox_new(false, 0);
container_ = gfx::CreateGtkBorderBin(hbox, &kBackgroundColor,
kBarPadding, kBarPadding, kBarPadding, kBarPadding);
- fixed_.Own(gtk_fixed_new());
+ gtk_widget_set_app_paintable(container_, TRUE);
+ g_signal_connect(container_, "expose-event",
+ G_CALLBACK(OnExpose), NULL);
// |fixed_| has to be at least one pixel tall. We color this pixel the same
// color as the border that separates the toolbar from the web contents.
// TODO(estade): find a better solution. (Ideally the tool bar shouldn't draw
// its own border, but the border is part of the background bitmap, so
// changing that would affect all platforms.)
+ fixed_.Own(gtk_fixed_new());
border_ = gtk_event_box_new();
gtk_widget_set_size_request(border_, 1, 1);
gtk_widget_modify_bg(border_, GTK_STATE_NORMAL, &kBorderColor);
@@ -237,9 +272,9 @@ void FindBarGtk::OnButtonPressed(GtkWidget* button, FindBarGtk* find_bar) {
}
// static
-void FindBarGtk::OnSizeAllocate(GtkWidget* fixed,
- GtkAllocation* allocation,
- FindBarGtk* findbar) {
+void FindBarGtk::OnFixedSizeAllocate(GtkWidget* fixed,
+ GtkAllocation* allocation,
+ FindBarGtk* findbar) {
// Set the background widget to the size of |fixed|.
if (findbar->border_->allocation.width != allocation->width) {
// Typically it's not a good idea to use this function outside of container
@@ -261,3 +296,13 @@ void FindBarGtk::OnSizeAllocate(GtkWidget* fixed,
gtk_fixed_move(GTK_FIXED(fixed), container, xposition, kVerticalOffset);
}
}
+
+// static
+void FindBarGtk::OnContainerSizeAllocate(GtkWidget* container,
+ GtkAllocation* allocation,
+ FindBarGtk* findbar) {
+ if (!findbar->container_shaped_) {
+ GetDialogBackground()->ContourWidget(container);
+ findbar->container_shaped_ = true;
+ }
+}
diff --git a/chrome/browser/gtk/find_bar_gtk.h b/chrome/browser/gtk/find_bar_gtk.h
index eedbcdf..a25d5be 100644
--- a/chrome/browser/gtk/find_bar_gtk.h
+++ b/chrome/browser/gtk/find_bar_gtk.h
@@ -72,9 +72,15 @@ class FindBarGtk : public FindBar,
static void OnButtonPressed(GtkWidget* button, FindBarGtk* find_bar);
// Called when |fixed_| changes sizes. Used to position |container_|.
- static void OnSizeAllocate(GtkWidget* fixed,
- GtkAllocation* allocation,
- FindBarGtk* container_);
+ static void OnFixedSizeAllocate(GtkWidget* fixed,
+ GtkAllocation* allocation,
+ FindBarGtk* findbar);
+
+ // Called when |container_| is allocated.
+ static void OnContainerSizeAllocate(GtkWidget* container,
+ GtkAllocation* allocation,
+ FindBarGtk* findbar);
+
// GtkFixed containing the find bar widgets.
OwnedWidgetGtk fixed_;
@@ -88,6 +94,10 @@ class FindBarGtk : public FindBar,
// field, the buttons, etc.).
GtkWidget* container_;
+ // This will be set to true after ContourWidget() has been called so we don't
+ // call it twice.
+ bool container_shaped_;
+
// The widget where text is entered.
GtkWidget* find_text_;
diff --git a/chrome/browser/gtk/nine_box.cc b/chrome/browser/gtk/nine_box.cc
index ea79903..d957bfb 100644
--- a/chrome/browser/gtk/nine_box.cc
+++ b/chrome/browser/gtk/nine_box.cc
@@ -51,7 +51,7 @@ NineBox::NineBox(int top_left, int top, int top_right, int left, int center,
NineBox::~NineBox() {
}
-void NineBox::RenderToWidget(GtkWidget* dst) {
+void NineBox::RenderToWidget(GtkWidget* dst) const {
// TODO(evanm): this is stupid; it should just be implemented with SkBitmaps
// and convert to a GdkPixbuf at the last second.
@@ -61,7 +61,7 @@ void NineBox::RenderToWidget(GtkWidget* dst) {
// This function paints one row at a time.
// To make indexing sane, |images| points at the current row of images,
// so images[0] always refers to the left-most image of the current row.
- GdkPixbuf** images = &images_[0];
+ GdkPixbuf* const* images = &images_[0];
// The upper-left and lower-right corners of the center square in the
// rendering of the ninebox.
@@ -113,14 +113,63 @@ void NineBox::RenderToWidget(GtkWidget* dst) {
DrawPixbuf(dst, images[2], x2, y2);
}
-void NineBox::RenderTopCenterStrip(GtkWidget* dst, int x1, int x2, int y1) {
+void NineBox::RenderTopCenterStrip(GtkWidget* dst, int x1,
+ int x2, int y1) const {
TileImage(dst, images_[1],
x1, y1,
x2, y1);
}
+void NineBox::ChangeWhiteToTransparent() {
+ for (int image_idx = 0; image_idx < 9; ++image_idx) {
+ GdkPixbuf* pixbuf = images_[image_idx];
+ if (!pixbuf)
+ continue;
+
+ guchar* pixels = gdk_pixbuf_get_pixels(pixbuf);
+ int rowstride = gdk_pixbuf_get_rowstride(pixbuf);
+
+ for (int i = 0; i < gdk_pixbuf_get_height(pixbuf); ++i) {
+ for (int j = 0; j < gdk_pixbuf_get_width(pixbuf); ++j) {
+ guchar* pixel = &pixels[i * rowstride + j * 4];
+ if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff) {
+ pixel[3] = 0;
+ }
+ }
+ }
+ }
+}
+
+void NineBox::ContourWidget(GtkWidget* widget) const {
+ int x1 = gdk_pixbuf_get_width(images_[0]);
+ int x2 = widget->allocation.width - gdk_pixbuf_get_width(images_[2]);
+
+ // Paint the left and right sides.
+ GdkBitmap* mask = gdk_pixmap_new(NULL, widget->allocation.width,
+ widget->allocation.height, 1);
+ gdk_pixbuf_render_threshold_alpha(images_[0], mask,
+ 0, 0,
+ 0, 0, -1, -1,
+ 1);
+ gdk_pixbuf_render_threshold_alpha(images_[2], mask,
+ 0, 0,
+ x2, 0, -1, -1,
+ 1);
+
+ // Assume no transparency in the middle rectangle.
+ cairo_t* cr = gdk_cairo_create(mask);
+ cairo_rectangle(cr, x1, 0, x2 - x1, widget->allocation.height);
+ cairo_fill(cr);
+
+ // Mask the widget's window's shape.
+ gtk_widget_shape_combine_mask(widget, mask, 0, 0);
+
+ g_object_unref(mask);
+ cairo_destroy(cr);
+}
+
void NineBox::TileImage(GtkWidget* dst, GdkPixbuf* src,
- int x1, int y1, int x2, int y2) {
+ int x1, int y1, int x2, int y2) const {
GdkGC* gc = dst->style->fg_gc[GTK_WIDGET_STATE(dst)];
const int src_width = gdk_pixbuf_get_width(src);
const int src_height = gdk_pixbuf_get_height(src);
diff --git a/chrome/browser/gtk/nine_box.h b/chrome/browser/gtk/nine_box.h
index c4c5414..950a359 100644
--- a/chrome/browser/gtk/nine_box.h
+++ b/chrome/browser/gtk/nine_box.h
@@ -28,16 +28,26 @@ class NineBox {
// Render the NineBox to |dst|.
// The images will be tiled to fit into the widget.
- void RenderToWidget(GtkWidget* dst);
+ void RenderToWidget(GtkWidget* dst) const;
// Render the top row of images to |dst| between |x1| and |x2|.
// This is split from RenderToWidget so the toolbar can use it.
- void RenderTopCenterStrip(GtkWidget* dst, int x1, int x2, int y1);
+ void RenderTopCenterStrip(GtkWidget* dst, int x1, int x2, int y1) const;
+
+ // Change all pixels that are white in |images_| to have 0 opacity.
+ void ChangeWhiteToTransparent();
+
+ // Set the shape of |widget| to match that of the ninebox. Note that |widget|
+ // must have its own window and be allocated. Also, currently only the top
+ // three images are used.
+ // TODO(estade): extend this function to use all 9 images (if it's ever
+ // needed).
+ void ContourWidget(GtkWidget* widget) const;
private:
// Repeatedly stamp src across dst.
void TileImage(GtkWidget* dst, GdkPixbuf* src,
- int x1, int y1, int x2, int y2);
+ int x1, int y1, int x2, int y2) const;
GdkPixbuf* images_[9];
};