diff options
-rw-r--r-- | chrome/browser/gtk/find_bar_gtk.cc | 57 | ||||
-rw-r--r-- | chrome/browser/gtk/find_bar_gtk.h | 16 | ||||
-rw-r--r-- | chrome/browser/gtk/nine_box.cc | 57 | ||||
-rw-r--r-- | chrome/browser/gtk/nine_box.h | 16 |
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]; }; |