diff options
author | erg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-03 00:42:29 +0000 |
---|---|---|
committer | erg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-03 00:42:29 +0000 |
commit | a5166af69628552e4bcf746a38f3710cc895eac3 (patch) | |
tree | 0d6e0ab20143724111855ac501aad3fd469e6b8d /chrome/browser/gtk | |
parent | 08f91cc8431cc6dea19e3c3ff3a229c71a7fc71f (diff) | |
download | chromium_src-a5166af69628552e4bcf746a38f3710cc895eac3.zip chromium_src-a5166af69628552e4bcf746a38f3710cc895eac3.tar.gz chromium_src-a5166af69628552e4bcf746a38f3710cc895eac3.tar.bz2 |
GTK: Initial implementation of using GTK themes, partially based on evan's CL 118358.
A lot of stuff works:
- Colors are picked out of the GTK theme.
- Buttons use the current GTK button theme.
- We use the user's icon theme.
A lot of stuff doesn't:
- We could do a better job of picking colors for the skylines.
- The omnibox hasn't been touched.
- UI that's not part of the toolbar hasn't been touched.
- We currently fail on themes like HighContrastInverse.
TEST=Under Options>Personal Stuff, click GTK Theme. Colors and widgets should be rendered with the current GTK theme stuff.
TEST=With chrome open and in GTK Theme mode, change your GTK theme or icon theme. chrome should pick up on the change immediately and reimport the colors and images.
http://crbug.com/13967
Review URL: http://codereview.chromium.org/150176
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19868 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/gtk')
20 files changed, 444 insertions, 60 deletions
diff --git a/chrome/browser/gtk/back_forward_button_gtk.cc b/chrome/browser/gtk/back_forward_button_gtk.cc index f354ab4..dd35a0b 100644 --- a/chrome/browser/gtk/back_forward_button_gtk.cc +++ b/chrome/browser/gtk/back_forward_button_gtk.cc @@ -25,20 +25,24 @@ BackForwardButtonGtk::BackForwardButtonGtk(Browser* browser, bool is_forward) last_release_event_flags_(0), show_menu_factory_(this) { int normal, active, highlight, depressed, tooltip; + const char* stock; if (is_forward) { normal = IDR_FORWARD; active = IDR_FORWARD_P; highlight = IDR_FORWARD_H; depressed = IDR_FORWARD_D; tooltip = IDS_TOOLTIP_FORWARD; + stock = GTK_STOCK_GO_FORWARD; } else { normal = IDR_BACK; active = IDR_BACK_P; highlight = IDR_BACK_H; depressed = IDR_BACK_D; tooltip = IDS_TOOLTIP_BACK; + stock = GTK_STOCK_GO_BACK; } - button_.reset(new CustomDrawButton(normal, active, highlight, depressed)); + button_.reset(new CustomDrawButton(normal, active, highlight, depressed, + stock)); gtk_widget_set_tooltip_text(widget(), l10n_util::GetStringUTF8(tooltip).c_str()); menu_model_.reset(new BackForwardMenuModelGtk(browser, @@ -72,6 +76,10 @@ void BackForwardButtonGtk::StoppedShowingMenu() { button_->UnsetPaintOverride(); } +void BackForwardButtonGtk::SetUseSystemTheme(bool use_gtk) { + button_->SetUseSystemTheme(use_gtk); +} + void BackForwardButtonGtk::ShowBackForwardMenu() { menu_.reset(new MenuGtk(menu_model_.get(), true)); button_->SetPaintOverride(GTK_STATE_ACTIVE); diff --git a/chrome/browser/gtk/back_forward_button_gtk.h b/chrome/browser/gtk/back_forward_button_gtk.h index 693ff40..d63412f 100644 --- a/chrome/browser/gtk/back_forward_button_gtk.h +++ b/chrome/browser/gtk/back_forward_button_gtk.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_GTK_BACK_FORWARD_BUTTON_GTK_ -#define CHROME_BROWSER_GTK_BACK_FORWARD_BUTTON_GTK_ +#ifndef CHROME_BROWSER_GTK_BACK_FORWARD_BUTTON_GTK_H_ +#define CHROME_BROWSER_GTK_BACK_FORWARD_BUTTON_GTK_H_ #include "base/scoped_ptr.h" #include "base/task.h" @@ -27,6 +27,9 @@ class BackForwardButtonGtk { GtkWidget* widget() { return button_->widget(); } + // Advises our CustomDrawButtons on how to render. + void SetUseSystemTheme(bool use_gtk); + private: // Executes the browser command. static void OnClick(GtkWidget* widget, BackForwardButtonGtk* button); @@ -75,4 +78,4 @@ class BackForwardButtonGtk { DISALLOW_COPY_AND_ASSIGN(BackForwardButtonGtk); }; -#endif // CHROME_BROWSER_GTK_BACK_FORWARD_BUTTON_GTK_ +#endif // CHROME_BROWSER_GTK_BACK_FORWARD_BUTTON_GTK_H_ diff --git a/chrome/browser/gtk/bookmark_bar_gtk.cc b/chrome/browser/gtk/bookmark_bar_gtk.cc index dd06d05..ca12189 100644 --- a/chrome/browser/gtk/bookmark_bar_gtk.cc +++ b/chrome/browser/gtk/bookmark_bar_gtk.cc @@ -22,6 +22,7 @@ #include "chrome/browser/gtk/custom_button.h" #include "chrome/browser/gtk/gtk_chrome_button.h" #include "chrome/browser/gtk/gtk_dnd_util.h" +#include "chrome/browser/gtk/gtk_theme_provider.h" #include "chrome/browser/gtk/nine_box.h" #include "chrome/browser/gtk/tabs/tab_strip_gtk.h" #include "chrome/browser/metrics/user_metrics.h" @@ -45,6 +46,13 @@ const int kInstructionsPadding = 6; // Color of the instructional text. const GdkColor kInstructionsColor = GDK_COLOR_RGB(128, 128, 142); +void SetUseSystemThemeGraphicsOnToolbarItems(GtkToolItem* item, bool use_gtk) { + GtkWidget* child = gtk_bin_get_child(GTK_BIN(item)); + if (GTK_IS_CHROME_BUTTON(child)) { + gtk_chrome_button_set_use_gtk_rendering(GTK_CHROME_BUTTON(child), use_gtk); + } +} + } // namespace BookmarkBarGtk::BookmarkBarGtk(Profile* profile, Browser* browser, @@ -167,6 +175,9 @@ void BookmarkBarGtk::Init(Profile* profile) { gtk_box_pack_start(GTK_BOX(bookmark_hbox_.get()), other_bookmarks_button_, FALSE, FALSE, 0); + + // Set the current theme state for all the buttons. + UserChangedTheme(profile); gtk_widget_set_size_request(bookmark_hbox_.get(), -1, 0); slide_animation_.reset(new SlideAnimation(this)); @@ -260,9 +271,11 @@ void BookmarkBarGtk::BookmarkNodeAdded(BookmarkModel* model, } DCHECK(index >= 0 && index <= GetBookmarkButtonCount()); + GtkToolItem* item = CreateBookmarkToolItem(parent->GetChild(index)); gtk_toolbar_insert(GTK_TOOLBAR(bookmark_toolbar_.get()), - CreateBookmarkToolItem(parent->GetChild(index)), - index); + item, index); + bool use_gtk = GtkThemeProvider::UseSystemThemeGraphics(profile_); + SetUseSystemThemeGraphicsOnToolbarItems(item, use_gtk); SetInstructionState(parent); } @@ -321,6 +334,10 @@ void BookmarkBarGtk::CreateAllBookmarkButtons(const BookmarkNode* node) { gtk_toolbar_insert(GTK_TOOLBAR(bookmark_toolbar_.get()), item, -1); } + // Now that we've made a bunch of toolbar items, we need to make sure they + // have the correct theme state. + UserChangedTheme(profile_); + SetInstructionState(node); } @@ -350,6 +367,19 @@ bool BookmarkBarGtk::IsAlwaysShown() { return profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar); } +void BookmarkBarGtk::UserChangedTheme(Profile* profile) { + bool use_gtk = GtkThemeProvider::UseSystemThemeGraphics(profile); + + gtk_chrome_button_set_use_gtk_rendering( + GTK_CHROME_BUTTON(other_bookmarks_button_), use_gtk); + + gtk_container_foreach( + GTK_CONTAINER(bookmark_toolbar_.get()), + reinterpret_cast<void (*)(GtkWidget*, void*)>( + SetUseSystemThemeGraphicsOnToolbarItems), + reinterpret_cast<void*>(use_gtk)); +} + void BookmarkBarGtk::AnimationProgressed(const Animation* animation) { DCHECK_EQ(animation, slide_animation_.get()); diff --git a/chrome/browser/gtk/bookmark_bar_gtk.h b/chrome/browser/gtk/bookmark_bar_gtk.h index d7f5eb8..3d0c03c 100644 --- a/chrome/browser/gtk/bookmark_bar_gtk.h +++ b/chrome/browser/gtk/bookmark_bar_gtk.h @@ -67,6 +67,9 @@ class BookmarkBarGtk : public AnimationDelegate, // Returns true if the bookmarks bar preference is set to 'always show'. bool IsAlwaysShown(); + // Alerts us that the theme changed, and we might need to change theme images. + void UserChangedTheme(Profile* profile); + // AnimationDelegate implementation ------------------------------------------ virtual void AnimationProgressed(const Animation* animation); virtual void AnimationEnded(const Animation* animation); diff --git a/chrome/browser/gtk/browser_titlebar.cc b/chrome/browser/gtk/browser_titlebar.cc index 70b6a32..2448cae 100644 --- a/chrome/browser/gtk/browser_titlebar.cc +++ b/chrome/browser/gtk/browser_titlebar.cc @@ -144,7 +144,7 @@ void BrowserTitlebar::Init() { CustomDrawButton* BrowserTitlebar::BuildTitlebarButton(int image, int image_pressed, int image_hot, GtkWidget* box, int tooltip) { CustomDrawButton* button = new CustomDrawButton(image, image_pressed, - image_hot, 0); + image_hot, 0, NULL); gtk_widget_add_events(GTK_WIDGET(button->widget()), GDK_POINTER_MOTION_MASK); g_signal_connect(button->widget(), "clicked", G_CALLBACK(OnButtonClicked), this); diff --git a/chrome/browser/gtk/browser_toolbar_gtk.cc b/chrome/browser/gtk/browser_toolbar_gtk.cc index d7fddfd..8340cef 100644 --- a/chrome/browser/gtk/browser_toolbar_gtk.cc +++ b/chrome/browser/gtk/browser_toolbar_gtk.cc @@ -21,6 +21,7 @@ #include "chrome/browser/gtk/go_button_gtk.h" #include "chrome/browser/gtk/gtk_chrome_button.h" #include "chrome/browser/gtk/gtk_dnd_util.h" +#include "chrome/browser/gtk/gtk_theme_provider.h" #include "chrome/browser/gtk/location_bar_view_gtk.h" #include "chrome/browser/gtk/nine_box.h" #include "chrome/browser/gtk/standard_menus.h" @@ -124,10 +125,12 @@ void BrowserToolbarGtk::Init(Profile* profile, gtk_box_pack_start(GTK_BOX(toolbar_), back_forward_hbox_, FALSE, FALSE, 0); reload_.reset(BuildToolbarButton(IDR_RELOAD, IDR_RELOAD_P, IDR_RELOAD_H, 0, - l10n_util::GetStringUTF8(IDS_TOOLTIP_RELOAD))); + l10n_util::GetStringUTF8(IDS_TOOLTIP_RELOAD), + GTK_STOCK_REFRESH)); home_.reset(BuildToolbarButton(IDR_HOME, IDR_HOME_P, IDR_HOME_H, 0, - l10n_util::GetStringUTF8(IDS_TOOLTIP_HOME))); + l10n_util::GetStringUTF8(IDS_TOOLTIP_HOME), + GTK_STOCK_HOME)); gtk_util::SetButtonTriggersNavigation(home_->widget()); SetUpDragForHomeButton(); @@ -162,6 +165,9 @@ void BrowserToolbarGtk::Init(Profile* profile, gtk_box_pack_start(GTK_BOX(toolbar_), menus_hbox_, FALSE, FALSE, 0); + // Force all the CustomDrawButtons to load the correct rendering style. + UserChangedTheme(); + gtk_widget_show_all(toolbar_); if (show_home_button_.GetValue()) { @@ -274,6 +280,19 @@ void BrowserToolbarGtk::UpdateTabContents(TabContents* contents, location_bar_->Update(should_restore_state ? contents : NULL); } +void BrowserToolbarGtk::UserChangedTheme() { + bool use_gtk = GtkThemeProvider::UseSystemThemeGraphics(profile_); + back_->SetUseSystemTheme(use_gtk); + forward_->SetUseSystemTheme(use_gtk); + reload_->SetUseSystemTheme(use_gtk); + home_->SetUseSystemTheme(use_gtk); + + gtk_chrome_button_set_use_gtk_rendering( + GTK_CHROME_BUTTON(page_menu_button_.get()), use_gtk); + gtk_chrome_button_set_use_gtk_rendering( + GTK_CHROME_BUTTON(app_menu_button_.get()), use_gtk); +} + gfx::Rect BrowserToolbarGtk::GetPopupBounds() const { GtkWidget* star = star_->widget(); GtkWidget* go = go_->widget(); @@ -297,9 +316,9 @@ gfx::Rect BrowserToolbarGtk::GetPopupBounds() const { CustomDrawButton* BrowserToolbarGtk::BuildToolbarButton( int normal_id, int active_id, int highlight_id, int depressed_id, - const std::string& localized_tooltip) { + const std::string& localized_tooltip, const char* stock_id) { CustomDrawButton* button = new CustomDrawButton(normal_id, active_id, - highlight_id, depressed_id); + highlight_id, depressed_id, stock_id); gtk_widget_set_tooltip_text(button->widget(), localized_tooltip.c_str()); @@ -332,7 +351,8 @@ GtkWidget* BrowserToolbarGtk::BuildToolbarMenuButton( owner->Own(button); ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - gtk_container_set_border_width(GTK_CONTAINER(button), 2); + if (!GtkThemeProvider::UseSystemThemeGraphics(profile_)) + gtk_container_set_border_width(GTK_CONTAINER(button), 2); gtk_container_add(GTK_CONTAINER(button), gtk_image_new_from_pixbuf(rb.GetPixbufNamed(icon_id))); diff --git a/chrome/browser/gtk/browser_toolbar_gtk.h b/chrome/browser/gtk/browser_toolbar_gtk.h index ed4dc17..9ed0929 100644 --- a/chrome/browser/gtk/browser_toolbar_gtk.h +++ b/chrome/browser/gtk/browser_toolbar_gtk.h @@ -78,6 +78,9 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver, ToolbarStarToggleGtk* star() { return star_.get(); } + // Alerts us that the theme changed, and we might need to change theme images. + void UserChangedTheme(); + // Implement AutocompletePopupPositioner, return the position of where the // Omnibox results popup should go (from the star to the go buttons). virtual gfx::Rect GetPopupBounds() const; @@ -90,7 +93,8 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver, int active_id, int highlight_id, int depressed_id, - const std::string& localized_tooltip); + const std::string& localized_tooltip, + const char* stock_id); // Create the star button given the tooltip. Returns the widget created. ToolbarStarToggleGtk* BuildStarButton(const std::string& localized_tooltip); diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc index 2060ca4..529ecd6 100644 --- a/chrome/browser/gtk/browser_window_gtk.cc +++ b/chrome/browser/gtk/browser_window_gtk.cc @@ -10,6 +10,7 @@ #include "app/resource_bundle.h" #include "app/theme_provider.h" #include "base/base_paths_linux.h" +#include "base/command_line.h" #include "base/gfx/gtk_util.h" #include "base/logging.h" #include "base/message_loop.h" @@ -34,6 +35,7 @@ #include "chrome/browser/gtk/edit_search_engine_dialog.h" #include "chrome/browser/gtk/find_bar_gtk.h" #include "chrome/browser/gtk/go_button_gtk.h" +#include "chrome/browser/gtk/gtk_theme_provider.h" #include "chrome/browser/gtk/import_dialog_gtk.h" #include "chrome/browser/gtk/infobar_container_gtk.h" #include "chrome/browser/gtk/keyword_editor_view.h" @@ -713,6 +715,9 @@ void BrowserWindowGtk::UserChangedTheme() { SetBackgroundColor(); gdk_window_invalidate_rect(GTK_WIDGET(window_)->window, >K_WIDGET(window_)->allocation, TRUE); + + toolbar_->UserChangedTheme(); + bookmark_bar_->UserChangedTheme(browser_->profile()); } int BrowserWindowGtk::GetExtraRenderViewHeight() const { @@ -1039,9 +1044,8 @@ void BrowserWindowGtk::InitWidgets() { void BrowserWindowGtk::SetBackgroundColor() { // TODO(tc): Handle active/inactive colors. - - ThemeProvider* theme_provider = browser()->profile()->GetThemeProvider(); - + Profile* profile = browser()->profile(); + ThemeProvider* theme_provider = profile->GetThemeProvider(); SkColor frame_color; if (browser()->profile()->IsOffTheRecord()) { frame_color = theme_provider->GetColor( diff --git a/chrome/browser/gtk/custom_button.cc b/chrome/browser/gtk/custom_button.cc index e828243..6729ee6 100644 --- a/chrome/browser/gtk/custom_button.cc +++ b/chrome/browser/gtk/custom_button.cc @@ -7,6 +7,7 @@ #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "base/basictypes.h" +#include "base/gfx/gtk_util.h" #include "grit/theme_resources.h" @@ -64,26 +65,46 @@ CustomDrawButton::CustomDrawButton( int normal_id, int active_id, int highlight_id, - int depressed_id) - : button_base_(normal_id, active_id, highlight_id, depressed_id) { + int depressed_id, + const char* stock_id) + : button_base_(normal_id, active_id, highlight_id, depressed_id), + gtk_stock_name_(stock_id), + has_expose_signal_handler_(false) { widget_.Own(gtk_button_new()); GTK_WIDGET_UNSET_FLAGS(widget_.get(), GTK_CAN_FOCUS); - - gtk_widget_set_size_request(widget_.get(), - gdk_pixbuf_get_width(button_base_.pixbufs(0)), - gdk_pixbuf_get_height(button_base_.pixbufs(0))); - - gtk_widget_set_app_paintable(widget_.get(), TRUE); - // We effectively double-buffer by virtue of having only one image... - gtk_widget_set_double_buffered(widget_.get(), FALSE); - g_signal_connect(G_OBJECT(widget_.get()), "expose-event", - G_CALLBACK(OnExpose), this); + SetUseSystemTheme(false); } CustomDrawButton::~CustomDrawButton() { widget_.Destroy(); } +void CustomDrawButton::SetUseSystemTheme(bool use_gtk) { + if (use_gtk && gtk_stock_name_) { + gtk_button_set_image( + GTK_BUTTON(widget_.get()), + gtk_image_new_from_stock(gtk_stock_name_, GTK_ICON_SIZE_BUTTON)); + gtk_widget_set_size_request(widget_.get(), -1, -1); + gtk_widget_set_app_paintable(widget_.get(), FALSE); + gtk_widget_set_double_buffered(widget_.get(), TRUE); + + if (has_expose_signal_handler_) + gtk_signal_disconnect_by_data(GTK_OBJECT(widget_.get()), this); + has_expose_signal_handler_ = false; + } else { + gtk_widget_set_size_request(widget_.get(), + gdk_pixbuf_get_width(button_base_.pixbufs(0)), + gdk_pixbuf_get_height(button_base_.pixbufs(0))); + + gtk_widget_set_app_paintable(widget_.get(), TRUE); + // We effectively double-buffer by virtue of having only one image... + gtk_widget_set_double_buffered(widget_.get(), FALSE); + g_signal_connect(G_OBJECT(widget_.get()), "expose-event", + G_CALLBACK(OnCustomExpose), this); + has_expose_signal_handler_ = true; + } +} + void CustomDrawButton::SetPaintOverride(GtkStateType state) { button_base_.set_paint_override(state); gtk_widget_queue_draw(widget_.get()); @@ -95,14 +116,16 @@ void CustomDrawButton::UnsetPaintOverride() { } // static -gboolean CustomDrawButton::OnExpose(GtkWidget* widget, - GdkEventExpose* e, - CustomDrawButton* button) { +gboolean CustomDrawButton::OnCustomExpose(GtkWidget* widget, + GdkEventExpose* e, + CustomDrawButton* button) { return button->button_base_.OnExpose(widget, e); } // static CustomDrawButton* CustomDrawButton::CloseButton() { - return new CustomDrawButton(IDR_CLOSE_BAR, IDR_CLOSE_BAR_P, - IDR_CLOSE_BAR_H, 0); + CustomDrawButton* button = + new CustomDrawButton(IDR_CLOSE_BAR, IDR_CLOSE_BAR_P, + IDR_CLOSE_BAR_H, 0, NULL); + return button; } diff --git a/chrome/browser/gtk/custom_button.h b/chrome/browser/gtk/custom_button.h index 0e54732..143a090 100644 --- a/chrome/browser/gtk/custom_button.h +++ b/chrome/browser/gtk/custom_button.h @@ -45,7 +45,8 @@ class CustomDrawButtonBase { }; // CustomDrawButton is a plain button where all its various states are drawn -// with static images. +// with static images. In GTK rendering mode, it will show the standard button +// with GTK |stock_id|. class CustomDrawButton { public: // The constructor takes 4 resource ids. If a resource doesn't exist for a @@ -53,7 +54,8 @@ class CustomDrawButton { CustomDrawButton(int normal_id, int active_id, int highlight_id, - int depressed_id); + int depressed_id, + const char* stock_id); explicit CustomDrawButton(const std::string& filename); ~CustomDrawButton(); @@ -69,6 +71,12 @@ class CustomDrawButton { int width() const { return widget_->allocation.width; } int height() const { return widget_->allocation.height; } + // Sets properties on the GtkButton returned by widget(). By default, the + // button is very boring. This will either give it an image from the + // |gtk_stock_name_| if |use_gtk| is true or will use the chrome frame + // images. + void SetUseSystemTheme(bool use_gtk); + // Set the state to draw. We will paint the widget as if it were in this // state. void SetPaintOverride(GtkStateType state); @@ -80,16 +88,22 @@ class CustomDrawButton { static CustomDrawButton* CloseButton(); private: - // Callback for expose, used to draw the custom graphics. - static gboolean OnExpose(GtkWidget* widget, - GdkEventExpose* e, - CustomDrawButton* obj); + // Callback for custom button expose, used to draw the custom graphics. + static gboolean OnCustomExpose(GtkWidget* widget, + GdkEventExpose* e, + CustomDrawButton* obj); // The actual button widget. OwnedWidgetGtk widget_; CustomDrawButtonBase button_base_; + // The stock icon name. + const char* gtk_stock_name_; + + // Whether we have an expose signal handler we may need to remove. + bool has_expose_signal_handler_; + DISALLOW_COPY_AND_ASSIGN(CustomDrawButton); }; diff --git a/chrome/browser/gtk/find_bar_gtk.cc b/chrome/browser/gtk/find_bar_gtk.cc index e8e70d3..54fe240 100644 --- a/chrome/browser/gtk/find_bar_gtk.cc +++ b/chrome/browser/gtk/find_bar_gtk.cc @@ -163,7 +163,8 @@ void FindBarGtk::InitWidgets() { l10n_util::GetStringUTF8(IDS_FIND_IN_PAGE_CLOSE_TOOLTIP).c_str()); find_next_button_.reset(new CustomDrawButton(IDR_FINDINPAGE_NEXT, - IDR_FINDINPAGE_NEXT_H, IDR_FINDINPAGE_NEXT_H, IDR_FINDINPAGE_NEXT_P)); + IDR_FINDINPAGE_NEXT_H, IDR_FINDINPAGE_NEXT_H, IDR_FINDINPAGE_NEXT_P, + NULL)); g_signal_connect(G_OBJECT(find_next_button_->widget()), "clicked", G_CALLBACK(OnClicked), this); gtk_widget_set_tooltip_text(find_next_button_->widget(), @@ -172,7 +173,8 @@ void FindBarGtk::InitWidgets() { FALSE, FALSE, 0); find_previous_button_.reset(new CustomDrawButton(IDR_FINDINPAGE_PREV, - IDR_FINDINPAGE_PREV_H, IDR_FINDINPAGE_PREV_H, IDR_FINDINPAGE_PREV_P)); + IDR_FINDINPAGE_PREV_H, IDR_FINDINPAGE_PREV_H, IDR_FINDINPAGE_PREV_P, + NULL)); g_signal_connect(G_OBJECT(find_previous_button_->widget()), "clicked", G_CALLBACK(OnClicked), this); gtk_widget_set_tooltip_text(find_previous_button_->widget(), diff --git a/chrome/browser/gtk/gtk_chrome_button.cc b/chrome/browser/gtk/gtk_chrome_button.cc index 558e610..6b35716 100644 --- a/chrome/browser/gtk/gtk_chrome_button.cc +++ b/chrome/browser/gtk/gtk_chrome_button.cc @@ -5,6 +5,7 @@ #include "chrome/browser/gtk/gtk_chrome_button.h" #include "base/basictypes.h" +#include "base/gfx/gtk_util.h" #include "chrome/browser/gtk/nine_box.h" #include "grit/app_resources.h" @@ -27,6 +28,10 @@ typedef struct _GtkChromeButtonPrivate GtkChromeButtonPrivate; struct _GtkChromeButtonPrivate { int paint_state; + + // If true, we use images provided by the theme instead of GTK's default + // button rendering. + gboolean use_gtk_rendering; }; G_DEFINE_TYPE(GtkChromeButton, gtk_chrome_button, GTK_TYPE_BUTTON) @@ -66,6 +71,7 @@ static void gtk_chrome_button_class_init(GtkChromeButtonClass* button_class) { static void gtk_chrome_button_init(GtkChromeButton* button) { GtkChromeButtonPrivate* priv = GTK_CHROME_BUTTON_GET_PRIVATE(button); priv->paint_state = -1; + priv->use_gtk_rendering = FALSE; gtk_widget_set_app_paintable(GTK_WIDGET(button), TRUE); @@ -78,19 +84,34 @@ static gboolean gtk_chrome_button_expose(GtkWidget* widget, int paint_state = priv->paint_state < 0 ? GTK_WIDGET_STATE(widget) : priv->paint_state; - NineBox* nine_box = NULL; - if (paint_state == GTK_STATE_PRELIGHT) - nine_box = g_nine_box_prelight; - else if (paint_state == GTK_STATE_ACTIVE) - nine_box = g_nine_box_active; - - // Only draw theme graphics if we have some. - if (nine_box) - nine_box->RenderToWidget(widget); - - gtk_container_propagate_expose(GTK_CONTAINER(widget), - gtk_bin_get_child(GTK_BIN(widget)), - event); + if (priv->use_gtk_rendering) { + // We have the superclass handle this expose when we aren't using custom + // rendering AND we're in either the prelight or active state so that we + // get the button border for the current GTK theme drawn. + if (paint_state == GTK_STATE_PRELIGHT || paint_state == GTK_STATE_ACTIVE) { + (*GTK_WIDGET_CLASS(gtk_chrome_button_parent_class)->expose_event) + (widget, event); + } else { + // Otherwise, we're still responsible for rendering our children. + gtk_container_propagate_expose(GTK_CONTAINER(widget), + gtk_bin_get_child(GTK_BIN(widget)), + event); + } + } else { + NineBox* nine_box = NULL; + if (paint_state == GTK_STATE_PRELIGHT) + nine_box = g_nine_box_prelight; + else if (paint_state == GTK_STATE_ACTIVE) + nine_box = g_nine_box_active; + + // Only draw theme graphics if we have some. + if (nine_box) + nine_box->RenderToWidget(widget); + + gtk_container_propagate_expose(GTK_CONTAINER(widget), + gtk_bin_get_child(GTK_BIN(widget)), + event); + } return TRUE; // Don't propagate, we are the default handler. } @@ -118,4 +139,11 @@ void gtk_chrome_button_unset_paint_state(GtkChromeButton* button) { gtk_widget_queue_draw(GTK_WIDGET(button)); } +void gtk_chrome_button_set_use_gtk_rendering(GtkChromeButton* button, + gboolean value) { + g_return_if_fail(GTK_IS_CHROME_BUTTON(button)); + GtkChromeButtonPrivate *priv = GTK_CHROME_BUTTON_GET_PRIVATE(button); + priv->use_gtk_rendering = value; +} + G_END_DECLS diff --git a/chrome/browser/gtk/gtk_chrome_button.h b/chrome/browser/gtk/gtk_chrome_button.h index c1437d4..921e1e2 100644 --- a/chrome/browser/gtk/gtk_chrome_button.h +++ b/chrome/browser/gtk/gtk_chrome_button.h @@ -45,6 +45,10 @@ void gtk_chrome_button_set_paint_state(GtkChromeButton* button, // Revert to using the widget's current state for painting. void gtk_chrome_button_unset_paint_state(GtkChromeButton* button); +// Whether we should use custom theme images or let GTK take care of it. +void gtk_chrome_button_set_use_gtk_rendering(GtkChromeButton* button, + gboolean value); + G_END_DECLS #endif // CHROME_BROWSER_GTK_GTK_CHROME_BUTTON_H_ diff --git a/chrome/browser/gtk/gtk_theme_provider.cc b/chrome/browser/gtk/gtk_theme_provider.cc new file mode 100644 index 0000000..f030398 --- /dev/null +++ b/chrome/browser/gtk/gtk_theme_provider.cc @@ -0,0 +1,154 @@ +// 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/gtk_theme_provider.h" + +#include <gtk/gtk.h> + +#include "base/gfx/gtk_util.h" +#include "chrome/browser/metrics/user_metrics.h" +#include "chrome/browser/profile.h" +#include "chrome/common/pref_names.h" +#include "grit/theme_resources.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkCanvas.h" + +namespace { + +// The size of the rendered toolbar image. +const int kToolbarImageWidth = 64; +const int kToolbarImageHeight = 128; + +} // namespace + +GtkThemeProvider::GtkThemeProvider() + : BrowserThemeProvider(), + fake_window_(gtk_window_new(GTK_WINDOW_TOPLEVEL)) { + // Only realized widgets receive style-set notifications, which we need to + // broadcast new theme images and colors. + gtk_widget_realize(fake_window_); + g_signal_connect(fake_window_, "style-set", G_CALLBACK(&OnStyleSet), this); +} + +GtkThemeProvider::~GtkThemeProvider() { + gtk_widget_destroy(fake_window_); +} + +void GtkThemeProvider::SetTheme(Extension* extension) { + profile()->GetPrefs()->SetBoolean(prefs::kUsesSystemTheme, false); + BrowserThemeProvider::SetTheme(extension); +} + +void GtkThemeProvider::UseDefaultTheme() { + profile()->GetPrefs()->SetBoolean(prefs::kUsesSystemTheme, false); + BrowserThemeProvider::UseDefaultTheme(); +} + +void GtkThemeProvider::SetNativeTheme() { + profile()->GetPrefs()->SetBoolean(prefs::kUsesSystemTheme, true); + ClearAllThemeData(); + LoadGtkValues(); + NotifyThemeChanged(); +} + +// static +bool GtkThemeProvider::UseSystemThemeGraphics(Profile* profile) { + return profile->GetPrefs()->GetBoolean(prefs::kUsesSystemTheme); +} + +void GtkThemeProvider::LoadThemePrefs() { + if (profile()->GetPrefs()->GetBoolean(prefs::kUsesSystemTheme)) { + LoadGtkValues(); + } else { + BrowserThemeProvider::LoadThemePrefs(); + } +} + +SkBitmap* GtkThemeProvider::LoadThemeBitmap(int id) { + if (id == IDR_THEME_TOOLBAR && UseSystemThemeGraphics(profile())) { + GtkStyle* style = gtk_rc_get_style(fake_window_); + GdkColor* color = &style->bg[GTK_STATE_NORMAL]; + SkBitmap* bitmap = new SkBitmap; + bitmap->setConfig(SkBitmap::kARGB_8888_Config, + kToolbarImageWidth, kToolbarImageHeight); + bitmap->allocPixels(); + bitmap->eraseRGB(color->red >> 8, color->green >> 8, color->blue >> 8); + return bitmap; + } else { + return BrowserThemeProvider::LoadThemeBitmap(id); + } +} + +// static +void GtkThemeProvider::OnStyleSet(GtkWidget* widget, + GtkStyle* previous_style, + GtkThemeProvider* provider) { + if (provider->profile()->GetPrefs()->GetBoolean(prefs::kUsesSystemTheme)) { + provider->ClearAllThemeData(); + provider->LoadGtkValues(); + provider->NotifyThemeChanged(); + } +} + +void GtkThemeProvider::LoadGtkValues() { + GtkStyle* style = gtk_rc_get_style(fake_window_); + + SetThemeColorFromGtk(themes::kColorFrame, &style->bg[GTK_STATE_SELECTED]); + SetThemeColorFromGtk(themes::kColorFrameInactive, + &style->bg[GTK_STATE_INSENSITIVE]); + // TODO(erg): Incognito images. + SetThemeColorFromGtk(themes::kColorToolbar, + &style->bg[GTK_STATE_NORMAL]); + SetThemeColorFromGtk(themes::kColorTabText, + &style->text[GTK_STATE_NORMAL]); + SetThemeColorFromGtk(themes::kColorBackgroundTabText, + &style->text[GTK_STATE_NORMAL]); + SetThemeColorFromGtk(themes::kColorBookmarkText, + &style->text[GTK_STATE_NORMAL]); + SetThemeColorFromGtk(themes::kColorControlBackground, + &style->bg[GTK_STATE_NORMAL]); + SetThemeColorFromGtk(themes::kColorButtonBackground, + &style->bg[GTK_STATE_NORMAL]); + + SetThemeTintFromGtk(themes::kTintButtons, &style->bg[GTK_STATE_SELECTED], + themes::kDefaultTintButtons); + SetThemeTintFromGtk(themes::kTintFrame, &style->bg[GTK_STATE_SELECTED], + themes::kDefaultTintFrame); + SetThemeTintFromGtk(themes::kTintFrameInactive, + &style->bg[GTK_STATE_SELECTED], + themes::kDefaultTintFrameInactive); + SetThemeTintFromGtk(themes::kTintFrameIncognito, + &style->bg[GTK_STATE_SELECTED], + themes::kDefaultTintFrameIncognito); + SetThemeTintFromGtk(themes::kTintFrameIncognitoInactive, + &style->bg[GTK_STATE_SELECTED], + themes::kDefaultTintFrameIncognitoInactive); + SetThemeTintFromGtk(themes::kTintBackgroundTab, + &style->bg[GTK_STATE_SELECTED], + themes::kDefaultTintBackgroundTab); + + GenerateFrameColors(); + GenerateFrameImages(); +} + +void GtkThemeProvider::SetThemeColorFromGtk(const char* id, GdkColor* color) { + SetColor(id, SkColorSetRGB(color->red >> 8, + color->green >> 8, + color->blue >> 8)); +} + +void GtkThemeProvider::SetThemeTintFromGtk(const char* id, GdkColor* color, + const skia::HSL& default_tint) { + skia::HSL hsl; + skia::SkColorToHSL(SkColorSetRGB((color->red >> 8), + (color->green >> 8), + (color->blue >> 8)), hsl); + if (default_tint.s != -1) + hsl.s = default_tint.s; + + if (default_tint.l != -1) + hsl.l = default_tint.l; + SetTint(id, hsl); +} + diff --git a/chrome/browser/gtk/gtk_theme_provider.h b/chrome/browser/gtk/gtk_theme_provider.h new file mode 100644 index 0000000..88f0fed --- /dev/null +++ b/chrome/browser/gtk/gtk_theme_provider.h @@ -0,0 +1,61 @@ +// 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_GTK_THEME_PROVIDER_H_ +#define CHROME_BROWSER_GTK_GTK_THEME_PROVIDER_H_ + +#include "chrome/browser/browser_theme_provider.h" + +#include "skia/ext/skia_utils.h" + +class Profile; + +typedef struct _GtkStyle GtkStyle; +typedef struct _GtkWidget GtkWidget; + +// Specialization of BrowserThemeProvider which supplies system colors. +class GtkThemeProvider : public BrowserThemeProvider { + public: + GtkThemeProvider(); + virtual ~GtkThemeProvider(); + + // Overridden from BrowserThemeProvider: + // + // Sets that we aren't using the system theme, then calls + // BrowserThemeProvider's implementation. + virtual void SetTheme(Extension* extension); + virtual void UseDefaultTheme(); + virtual void SetNativeTheme(); + + // Whether we should use the GTK system theme. + static bool UseSystemThemeGraphics(Profile* profile); + + private: + // Load theme data from preferences, possibly picking colors from GTK. + virtual void LoadThemePrefs(); + + // Possibly creates a theme specific version of theme_toolbar_default. + // (minimally acceptable version right now, which is just a fill of the bg + // color; this should instead invoke gtk_draw_box(...) for complex theme + // engines.) + virtual SkBitmap* LoadThemeBitmap(int id); + + // Handles signal from GTK that our theme has been changed. + static void OnStyleSet(GtkWidget* widget, + GtkStyle* previous_style, + GtkThemeProvider* provider); + + void LoadGtkValues(); + + // Sets the underlying theme colors/tints from a GTK color. + void SetThemeColorFromGtk(const char* id, GdkColor* color); + void SetThemeTintFromGtk(const char* id, GdkColor* color, + const skia::HSL& default_tint); + + // A GtkWidget that exists only so we can look at its properties (and take + // its colors). + GtkWidget* fake_window_; +}; + +#endif // CHROME_BROWSER_GTK_GTK_THEME_PROVIDER_H_ diff --git a/chrome/browser/gtk/location_bar_view_gtk.cc b/chrome/browser/gtk/location_bar_view_gtk.cc index 118287d..b10712a 100644 --- a/chrome/browser/gtk/location_bar_view_gtk.cc +++ b/chrome/browser/gtk/location_bar_view_gtk.cc @@ -15,6 +15,7 @@ #include "chrome/browser/alternate_nav_url_fetcher.h" #include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h" #include "chrome/browser/command_updater.h" +#include "chrome/browser/gtk/gtk_theme_provider.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/gtk_util.h" #include "chrome/common/page_transition_types.h" @@ -116,10 +117,17 @@ void LocationBarViewGtk::Init() { G_CALLBACK(&HandleExposeThunk), this); GtkWidget* align = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); - gtk_alignment_set_padding(GTK_ALIGNMENT(align), - kTopMargin + kBorderThickness, - kBottomMargin + kBorderThickness, - kEditLeftRightPadding, kEditLeftRightPadding); + // TODO(erg): Redo this so that it adjusts during theme changes. + if (GtkThemeProvider::UseSystemThemeGraphics(profile_)) { + gtk_alignment_set_padding(GTK_ALIGNMENT(align), + 0, 0, + kEditLeftRightPadding, kEditLeftRightPadding); + } else { + gtk_alignment_set_padding(GTK_ALIGNMENT(align), + kTopMargin + kBorderThickness, + kBottomMargin + kBorderThickness, + kEditLeftRightPadding, kEditLeftRightPadding); + } gtk_container_add(GTK_CONTAINER(align), location_entry_->widget()); gtk_box_pack_start(GTK_BOX(hbox_.get()), align, TRUE, TRUE, 0); diff --git a/chrome/browser/gtk/options/content_page_gtk.cc b/chrome/browser/gtk/options/content_page_gtk.cc index 49d1c3e..1130912 100644 --- a/chrome/browser/gtk/options/content_page_gtk.cc +++ b/chrome/browser/gtk/options/content_page_gtk.cc @@ -171,6 +171,12 @@ GtkWidget* ContentPageGtk::InitBrowsingDataGroup() { GtkWidget* ContentPageGtk::InitThemesGroup() { GtkWidget* hbox = gtk_hbox_new(FALSE, gtk_util::kLabelSpacing); + // GTK theme button. + GtkWidget* gtk_theme_button = gtk_button_new_with_label("GTK Theme"); + g_signal_connect(G_OBJECT(gtk_theme_button), "clicked", + G_CALLBACK(OnGtkThemeButtonClicked), this); + gtk_box_pack_start(GTK_BOX(hbox), gtk_theme_button, FALSE, FALSE, 0); + // Reset themes button. GtkWidget* themes_reset_button = gtk_button_new_with_label( l10n_util::GetStringUTF8(IDS_THEMES_RESET_BUTTON).c_str()); @@ -198,6 +204,14 @@ void ContentPageGtk::OnClearBrowsingDataButtonClicked(GtkButton* widget, } // static +void ContentPageGtk::OnGtkThemeButtonClicked(GtkButton* widget, + ContentPageGtk* page) { + page->UserMetricsRecordAction(L"Options_GtkThemeSet", + page->profile()->GetPrefs()); + page->profile()->SetNativeTheme(); +} + +// static void ContentPageGtk::OnResetDefaultThemeButtonClicked(GtkButton* widget, ContentPageGtk* page) { page->UserMetricsRecordAction(L"Options_ThemesReset", diff --git a/chrome/browser/gtk/options/content_page_gtk.h b/chrome/browser/gtk/options/content_page_gtk.h index 95b044e0..17f58e4 100644 --- a/chrome/browser/gtk/options/content_page_gtk.h +++ b/chrome/browser/gtk/options/content_page_gtk.h @@ -37,6 +37,10 @@ class ContentPageGtk : public OptionsPageBase { static void OnClearBrowsingDataButtonClicked(GtkButton* widget, ContentPageGtk* page); + // Callback for the GTK theme button. + static void OnGtkThemeButtonClicked(GtkButton* widget, + ContentPageGtk* page); + // Callback for reset default theme button. static void OnResetDefaultThemeButtonClicked(GtkButton* widget, ContentPageGtk* page); diff --git a/chrome/browser/gtk/tabs/tab_renderer_gtk.cc b/chrome/browser/gtk/tabs/tab_renderer_gtk.cc index 1a045ba..a8de38a 100755 --- a/chrome/browser/gtk/tabs/tab_renderer_gtk.cc +++ b/chrome/browser/gtk/tabs/tab_renderer_gtk.cc @@ -681,7 +681,7 @@ bool TabRendererGtk::ShouldShowCloseBox() const { CustomDrawButton* TabRendererGtk::MakeCloseButton() { CustomDrawButton* button = new CustomDrawButton(IDR_TAB_CLOSE, - IDR_TAB_CLOSE_P, IDR_TAB_CLOSE_H, IDR_TAB_CLOSE); + IDR_TAB_CLOSE_P, IDR_TAB_CLOSE_H, IDR_TAB_CLOSE, NULL); g_signal_connect(G_OBJECT(button->widget()), "clicked", G_CALLBACK(OnCloseButtonClicked), this); diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.cc b/chrome/browser/gtk/tabs/tab_strip_gtk.cc index 338c0e2d..bb32927 100755 --- a/chrome/browser/gtk/tabs/tab_strip_gtk.cc +++ b/chrome/browser/gtk/tabs/tab_strip_gtk.cc @@ -1571,7 +1571,7 @@ void TabStripGtk::SetTabBounds(TabGtk* tab, const gfx::Rect& bounds) { CustomDrawButton* TabStripGtk::MakeNewTabButton() { CustomDrawButton* button = new CustomDrawButton(IDR_NEWTAB_BUTTON, - IDR_NEWTAB_BUTTON_P, IDR_NEWTAB_BUTTON_H, 0); + IDR_NEWTAB_BUTTON_P, IDR_NEWTAB_BUTTON_H, 0, NULL); g_signal_connect(G_OBJECT(button->widget()), "clicked", G_CALLBACK(OnNewTabClicked), this); |