summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorevan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-17 19:47:15 +0000
committerevan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-17 19:47:15 +0000
commitea9a760bf723eda730f6de3662e71d3af3b9cdd1 (patch)
treebf26aa989ade18c4eb6a158595566041f3f9ddaa /chrome
parentd55ad15d8c3e118d6f03dbf236d6b98c62d66fe9 (diff)
downloadchromium_src-ea9a760bf723eda730f6de3662e71d3af3b9cdd1.zip
chromium_src-ea9a760bf723eda730f6de3662e71d3af3b9cdd1.tar.gz
chromium_src-ea9a760bf723eda730f6de3662e71d3af3b9cdd1.tar.bz2
Make the toolbar background themed on Linux.
Add a class for managing images for scalable themed widgets, and then implement the toolbar on top of this. Review URL: http://codereview.chromium.org/21390 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9898 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/browser.scons3
-rw-r--r--chrome/browser/gtk/browser_toolbar_view_gtk.cc30
-rw-r--r--chrome/browser/gtk/browser_toolbar_view_gtk.h3
-rw-r--r--chrome/browser/gtk/browser_window_gtk.cc88
-rw-r--r--chrome/browser/gtk/browser_window_gtk.h20
-rw-r--r--chrome/browser/gtk/nine_box.cc90
-rw-r--r--chrome/browser/gtk/nine_box.h39
7 files changed, 261 insertions, 12 deletions
diff --git a/chrome/browser/browser.scons b/chrome/browser/browser.scons
index f29fe40..4774b7a 100644
--- a/chrome/browser/browser.scons
+++ b/chrome/browser/browser.scons
@@ -789,8 +789,9 @@ if env.Bit('linux'):
'gtk/browser_toolbar_view_gtk.cc',
'gtk/browser_window_factory_gtk.cc',
'gtk/browser_window_gtk.cc',
- 'gtk/standard_menus.cc',
'gtk/menu_gtk.cc',
+ 'gtk/nine_box.cc',
+ 'gtk/standard_menus.cc',
'renderer_host/render_widget_host_view_gtk.cc',
'tab_contents/web_contents_view_gtk.cc',
])
diff --git a/chrome/browser/gtk/browser_toolbar_view_gtk.cc b/chrome/browser/gtk/browser_toolbar_view_gtk.cc
index 67840c7..b7ce06e 100644
--- a/chrome/browser/gtk/browser_toolbar_view_gtk.cc
+++ b/chrome/browser/gtk/browser_toolbar_view_gtk.cc
@@ -16,6 +16,18 @@
#include "chromium_strings.h"
#include "generated_resources.h"
+const int BrowserToolbarGtk::kToolbarHeight = 38;
+
+static GdkPixbuf* LoadThemeImage(const std::string& filename) {
+ FilePath path;
+ bool ok = PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ DCHECK(ok);
+ path = path.Append("chrome/app/theme").Append(filename);
+ // We intentionally ignore errors here, as some buttons don't have images
+ // for all states. This will all be removed once ResourceBundle works.
+ return gdk_pixbuf_new_from_file(path.value().c_str(), NULL);
+}
+
// CustomDrawButton manages the lifetimes of some resources used to make a
// custom-drawn Gtk button. We use them on the toolbar.
class BrowserToolbarGtk::CustomDrawButton {
@@ -76,15 +88,11 @@ GdkPixbuf* BrowserToolbarGtk::CustomDrawButton::LoadImage(
void BrowserToolbarGtk::CustomDrawButton::LoadImages(
const std::string& filename) {
// TODO(evanm): make this use ResourceBundle once that is ported.
- FilePath path;
- bool ok = PathService::Get(base::DIR_SOURCE_ROOT, &path);
- DCHECK(ok);
- path = path.Append("chrome/app/theme").Append(filename);
- pixbufs_[GTK_STATE_NORMAL] = LoadImage(path.value() + ".png");
- pixbufs_[GTK_STATE_ACTIVE] = LoadImage(path.value() + "_p.png");
- pixbufs_[GTK_STATE_PRELIGHT] = LoadImage(path.value() + "_h.png");
+ pixbufs_[GTK_STATE_NORMAL] = LoadThemeImage(filename + ".png");
+ pixbufs_[GTK_STATE_ACTIVE] = LoadThemeImage(filename + "_p.png");
+ pixbufs_[GTK_STATE_PRELIGHT] = LoadThemeImage(filename + "_h.png");
pixbufs_[GTK_STATE_SELECTED] = NULL;
- pixbufs_[GTK_STATE_INSENSITIVE] = LoadImage(path.value() + "_d.png");
+ pixbufs_[GTK_STATE_INSENSITIVE] = LoadThemeImage(filename + "_d.png");
gtk_widget_set_size_request(widget_,
gdk_pixbuf_get_width(pixbufs_[0]),
@@ -137,7 +145,11 @@ BrowserToolbarGtk::~BrowserToolbarGtk() {
void BrowserToolbarGtk::Init(Profile* profile) {
toolbar_ = gtk_hbox_new(FALSE, 0);
- gtk_container_set_border_width(GTK_CONTAINER(toolbar_), 6);
+ gtk_container_set_border_width(GTK_CONTAINER(toolbar_), 4);
+ // TODO(evanm): this setting of the x-size to 0 makes it so the window
+ // can be resized arbitrarily small. We should figure out what we want
+ // with respect to resizing before engineering around it, though.
+ gtk_widget_set_size_request(toolbar_, 0, kToolbarHeight);
toolbar_tooltips_ = gtk_tooltips_new();
diff --git a/chrome/browser/gtk/browser_toolbar_view_gtk.h b/chrome/browser/gtk/browser_toolbar_view_gtk.h
index 48d278d..2ef52f7 100644
--- a/chrome/browser/gtk/browser_toolbar_view_gtk.h
+++ b/chrome/browser/gtk/browser_toolbar_view_gtk.h
@@ -22,6 +22,9 @@ class ToolbarModel;
class BrowserToolbarGtk : public CommandUpdater::CommandObserver,
public MenuGtk::Delegate {
public:
+ // Height of the toolbar, in pixels.
+ static const int kToolbarHeight;
+
explicit BrowserToolbarGtk(Browser* browser);
virtual ~BrowserToolbarGtk();
diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc
index 1c05e9c..6b739dc 100644
--- a/chrome/browser/gtk/browser_window_gtk.cc
+++ b/chrome/browser/gtk/browser_window_gtk.cc
@@ -5,13 +5,26 @@
#include "chrome/browser/gtk/browser_window_gtk.h"
#include "base/logging.h"
+#include "base/base_paths_linux.h"
+#include "base/path_service.h"
#include "chrome/browser/browser.h"
+#include "chrome/browser/gtk/nine_box.h"
#include "chrome/browser/gtk/browser_toolbar_view_gtk.h"
#include "chrome/browser/renderer_host/render_widget_host_view_gtk.h"
#include "chrome/browser/tab_contents/web_contents.h"
namespace {
+static GdkPixbuf* LoadThemeImage(const std::string& filename) {
+ FilePath path;
+ bool ok = PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ DCHECK(ok);
+ path = path.Append("chrome/app/theme").Append(filename);
+ // We intentionally ignore errors here, as some buttons don't have images
+ // for all states. This will all be removed once ResourceBundle works.
+ return gdk_pixbuf_new_from_file(path.value().c_str(), NULL);
+}
+
gboolean MainWindowDestroyed(GtkWindow* window, BrowserWindowGtk* browser_win) {
delete browser_win;
return FALSE; // Don't stop this message.
@@ -44,7 +57,9 @@ gfx::Rect GetInitialWindowBounds(GtkWindow* window) {
BrowserWindowGtk::BrowserWindowGtk(Browser* browser)
: content_area_(NULL),
- browser_(browser) {
+ browser_(browser),
+ custom_frame_(false) // TODO(port): make this a pref.
+{
Init();
}
@@ -52,6 +67,42 @@ BrowserWindowGtk::~BrowserWindowGtk() {
Close();
}
+gboolean BrowserWindowGtk::OnContentAreaExpose(GtkWidget* widget,
+ GdkEventExpose* e,
+ BrowserWindowGtk* window) {
+ if (window->custom_frame_) {
+ NOTIMPLEMENTED() << " needs custom drawing for the custom frame.";
+ return FALSE;
+ }
+
+ // The theme graphics include the 2px frame, but we don't draw the frame
+ // in the non-custom-frame mode. So we subtract it off.
+ const int kFramePixels = 2;
+
+ GdkPixbuf* pixbuf =
+ gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, // alpha
+ 8, // bit depth
+ widget->allocation.width,
+ BrowserToolbarGtk::kToolbarHeight + kFramePixels);
+
+#ifndef NDEBUG
+ // Fill with a bright color so we can see any pixels we're missing.
+ gdk_pixbuf_fill(pixbuf, 0x00FFFFFF);
+#endif
+
+ window->content_area_ninebox_->RenderTopCenterStrip(pixbuf, 0,
+ widget->allocation.width);
+ gdk_draw_pixbuf(widget->window, NULL, pixbuf,
+ 0, 0,
+ widget->allocation.x,
+ widget->allocation.y - kFramePixels,
+ -1, -1,
+ GDK_RGB_DITHER_NORMAL, 0, 0);
+ gdk_pixbuf_unref(pixbuf);
+
+ return FALSE; // Allow subwidgets to paint.
+}
+
void BrowserWindowGtk::Init() {
window_ = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
gtk_window_set_title(window_, "Chromium");
@@ -64,12 +115,36 @@ void BrowserWindowGtk::Init() {
G_CALLBACK(MainWindowStateChanged), this);
bounds_ = GetInitialWindowBounds(window_);
+ GdkPixbuf* images[9] = {
+ LoadThemeImage("content_top_left_corner.png"),
+ LoadThemeImage("content_top_center.png"),
+ LoadThemeImage("content_top_right_corner.png"),
+ LoadThemeImage("content_left_side.png"),
+ NULL,
+ LoadThemeImage("content_right_side.png"),
+ LoadThemeImage("content_bottom_left_corner.png"),
+ LoadThemeImage("content_bottom_center.png"),
+ LoadThemeImage("content_bottom_right_corner.png")
+ };
+ content_area_ninebox_.reset(new NineBox(images));
+
+ // This vbox is intended to surround the "content": toolbar+page.
+ // When we add the tab strip, it should go in a vbox surrounding this one.
vbox_ = gtk_vbox_new(FALSE, 0);
+ gtk_widget_set_app_paintable(vbox_, TRUE);
+ gtk_widget_set_double_buffered(vbox_, FALSE);
+ g_signal_connect(G_OBJECT(vbox_), "expose-event",
+ G_CALLBACK(&OnContentAreaExpose), this);
toolbar_.reset(new BrowserToolbarGtk(browser_.get()));
toolbar_->Init(browser_->profile());
toolbar_->AddToolbarToBox(vbox_);
+ // Note that calling this the first time is necessary to get the
+ // proper control layout.
+ // TODO(port): make this a pref.
+ SetCustomFrame(false);
+
gtk_container_add(GTK_CONTAINER(window_), vbox_);
}
@@ -248,3 +323,14 @@ void BrowserWindowGtk::OnBoundsChanged(const gfx::Rect& bounds) {
void BrowserWindowGtk::OnStateChanged(GdkWindowState state) {
state_ = state;
}
+
+void BrowserWindowGtk::SetCustomFrame(bool custom_frame) {
+ custom_frame_ = custom_frame;
+ if (custom_frame_) {
+ gtk_container_set_border_width(GTK_CONTAINER(vbox_), 2);
+ // TODO(port): all the crazy blue title bar, etc.
+ NOTIMPLEMENTED();
+ } else {
+ gtk_container_set_border_width(GTK_CONTAINER(vbox_), 0);
+ }
+}
diff --git a/chrome/browser/gtk/browser_window_gtk.h b/chrome/browser/gtk/browser_window_gtk.h
index 57ace19..dc1f545 100644
--- a/chrome/browser/gtk/browser_window_gtk.h
+++ b/chrome/browser/gtk/browser_window_gtk.h
@@ -1,4 +1,4 @@
- // Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -12,6 +12,7 @@
#include "chrome/browser/browser_window.h"
class BrowserToolbarGtk;
+class NineBox;
// An implementation of BrowserWindow for GTK.
// Cross-platform code will interact with this object when
@@ -73,9 +74,26 @@ class BrowserWindowGtk : public BrowserWindow {
scoped_ptr<Browser> browser_;
private:
+ // Change whether we're showing the custom blue frame.
+ // Must be called once at startup.
+ // Triggers relayout of the content.
+ void SetCustomFrame(bool custom_frame);
+
+ // Callback for when the "content area" vbox needs to be redrawn.
+ // The content area includes the toolbar and web page but not the tab strip.
+ // It has a soft gray border when we have a custom frame.
+ static gboolean OnContentAreaExpose(GtkWidget* widget, GdkEventExpose* e,
+ BrowserWindowGtk* window);
+
gfx::Rect bounds_;
GdkWindowState state_;
+ // Theme graphics for the content area.
+ scoped_ptr<NineBox> content_area_ninebox_;
+
+ // Whether we're drawing the custom Chrome frame (including title bar).
+ bool custom_frame_;
+
scoped_ptr<BrowserToolbarGtk> toolbar_;
};
diff --git a/chrome/browser/gtk/nine_box.cc b/chrome/browser/gtk/nine_box.cc
new file mode 100644
index 0000000..98164d9
--- /dev/null
+++ b/chrome/browser/gtk/nine_box.cc
@@ -0,0 +1,90 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/gtk/nine_box.h"
+
+#include "base/logging.h"
+
+namespace {
+
+// Draw pixbuf |src| into |dst| at position (x, y).
+// Shorthand for gdk_pixbuf_copy_area.
+void DrawPixbuf(GdkPixbuf* src, GdkPixbuf* dst, int x, int y) {
+ gdk_pixbuf_copy_area(src, 0, 0,
+ gdk_pixbuf_get_width(src),
+ gdk_pixbuf_get_height(src),
+ dst, x, y);
+}
+
+} // anonymous namespace
+
+NineBox::NineBox(GdkPixbuf* images[9]) {
+ memcpy(images_, images, 9*sizeof(GdkPixbuf*));
+}
+
+NineBox::~NineBox() {
+ for (int i = 0; i < 9; ++i) {
+ if (images_[i])
+ gdk_pixbuf_unref(images_[i]);
+ }
+}
+
+void NineBox::RenderToPixbuf(GdkPixbuf* 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];
+
+ // x, y coordinate of bottom right corner drawing offset.
+ int x = gdk_pixbuf_get_width(dst) - gdk_pixbuf_get_width(images[2]);
+ int y = gdk_pixbuf_get_height(dst) - gdk_pixbuf_get_height(images[2]);
+
+ DrawPixbuf(images[0], dst, 0, 0);
+ RenderTopCenterStrip(dst, gdk_pixbuf_get_width(images[0]), x);
+ DrawPixbuf(images[2], dst, x, 0);
+
+ // Center row. Needs vertical tiling.
+ images = &images_[1 * 3];
+ TileImage(images[0], dst,
+ 0, gdk_pixbuf_get_height(images[0]),
+ 0, y);
+ // TODO(port): tile center image if it exists.
+ DCHECK(images[1] == NULL);
+ TileImage(images[2], dst,
+ x, gdk_pixbuf_get_height(images[0]),
+ x, y);
+
+ // Bottom row.
+ images = &images_[2 * 3];
+ DrawPixbuf(images[0], dst, 0, y);
+ TileImage(images[1], dst,
+ gdk_pixbuf_get_width(images[0]), y,
+ x, y);
+ DrawPixbuf(images[2], dst, x, y);
+}
+
+void NineBox::RenderTopCenterStrip(GdkPixbuf* dst, int x1, int x2) {
+ TileImage(images_[1], dst,
+ x1, 0,
+ x2, 0);
+}
+
+void NineBox::TileImage(GdkPixbuf* src, GdkPixbuf* dst,
+ int x1, int y1, int x2, int y2) {
+ const int width = gdk_pixbuf_get_width(src);
+ const int height = gdk_pixbuf_get_height(src);
+
+ // Compute delta x or y.
+ int dx = 0, dy = 0;
+ if (x2 > x1)
+ dx = width;
+ if (y2 > y1)
+ dy = height;
+
+ for (int x = x1, y = y1;
+ x + width <= x2 || y + height <= y2;
+ x += dx, y += dy) {
+ DrawPixbuf(src, dst, x, y);
+ }
+}
diff --git a/chrome/browser/gtk/nine_box.h b/chrome/browser/gtk/nine_box.h
new file mode 100644
index 0000000..3521a82
--- /dev/null
+++ b/chrome/browser/gtk/nine_box.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_GTK_NINE_BOX_H_
+#define CHROME_BROWSER_GTK_NINE_BOX_H_
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+// A NineBox manages a set of source images representing a 3x3 grid, where
+// non-corner images can be tiled to make a larger image. It's used to
+// use bitmaps for constructing image-based resizable widgets like buttons.
+//
+// TODO(port): add support for caching server-side pixmaps of prerendered
+// nineboxes.
+class NineBox {
+ public:
+ // Construct a NineBox with nine images. NULL images are allowed.
+ // Takes ownership of each image, but not the |images| array.
+ NineBox(GdkPixbuf* images[9]);
+ ~NineBox();
+
+ // Render the NineBox to dst.
+ // Expects dst to already be the proper size.
+ void RenderToPixbuf(GdkPixbuf* dst);
+
+ // Render the top row of images to dst between x1 and x2.
+ // This is split from RenderToPixbuf so the toolbar can use it.
+ void RenderTopCenterStrip(GdkPixbuf* dst, int x1, int x2);
+
+ private:
+ // Repeatedly stamp src across dst.
+ void TileImage(GdkPixbuf* src, GdkPixbuf* dst,
+ int x1, int y1, int x2, int y2);
+
+ GdkPixbuf* images_[9];
+};
+
+#endif // CHROME_BROWSER_GTK_NINE_BOX_H_