diff options
author | evan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-17 19:47:15 +0000 |
---|---|---|
committer | evan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-17 19:47:15 +0000 |
commit | ea9a760bf723eda730f6de3662e71d3af3b9cdd1 (patch) | |
tree | bf26aa989ade18c4eb6a158595566041f3f9ddaa /chrome | |
parent | d55ad15d8c3e118d6f03dbf236d6b98c62d66fe9 (diff) | |
download | chromium_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.scons | 3 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_toolbar_view_gtk.cc | 30 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_toolbar_view_gtk.h | 3 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_window_gtk.cc | 88 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_window_gtk.h | 20 | ||||
-rw-r--r-- | chrome/browser/gtk/nine_box.cc | 90 | ||||
-rw-r--r-- | chrome/browser/gtk/nine_box.h | 39 |
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_ |