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 | |
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
29 files changed, 665 insertions, 143 deletions
diff --git a/chrome/app/chrome_dll_main.cc b/chrome/app/chrome_dll_main.cc index de4d822..213a40f 100644 --- a/chrome/app/chrome_dll_main.cc +++ b/chrome/app/chrome_dll_main.cc @@ -176,6 +176,9 @@ static void GLibLogHandler(const gchar* log_domain, !GTK_CHECK_VERSION(2, 16, 1)) { // http://crbug.com/11133 LOG(ERROR) << "Bug 11133"; + } else if (strstr(message, "Theme file for default has no") || + strstr(message, "Theme directory")) { + LOG(ERROR) << "GTK theme error: " << message; } else { #ifdef NDEBUG LOG(ERROR) << log_domain << ": " << message; diff --git a/chrome/browser/browser_theme_provider.cc b/chrome/browser/browser_theme_provider.cc index 314b726..104007f 100644 --- a/chrome/browser/browser_theme_provider.cc +++ b/chrome/browser/browser_theme_provider.cc @@ -29,71 +29,78 @@ #include "app/win_util.h" #endif + +namespace themes { + // Strings used by themes to identify colors for different parts of our UI. -static const char* kColorFrame = "frame"; -static const char* kColorFrameInactive = "frame_inactive"; -static const char* kColorFrameIncognito = "frame_incognito"; -static const char* kColorFrameIncognitoInactive = - "frame_incognito_inactive"; -static const char* kColorToolbar = "toolbar"; -static const char* kColorTabText = "tab_text"; -static const char* kColorBackgroundTabText = "background_tab_text"; -static const char* kColorBookmarkText = "bookmark_text"; -static const char* kColorNTPBackground = "ntp_background"; -static const char* kColorNTPText = "ntp_text"; -static const char* kColorNTPLink = "ntp_link"; -static const char* kColorNTPSection = "ntp_section"; -static const char* kColorNTPSectionText = "ntp_section_text"; -static const char* kColorNTPSectionLink = "ntp_section_link"; -static const char* kColorControlBackground = "control_background"; -static const char* kColorButtonBackground = "button_background"; +const char* kColorFrame = "frame"; +const char* kColorFrameInactive = "frame_inactive"; +const char* kColorFrameIncognito = "frame_incognito"; +const char* kColorFrameIncognitoInactive = "frame_incognito_inactive"; +const char* kColorToolbar = "toolbar"; +const char* kColorTabText = "tab_text"; +const char* kColorBackgroundTabText = "background_tab_text"; +const char* kColorBookmarkText = "bookmark_text"; +const char* kColorNTPBackground = "ntp_background"; +const char* kColorNTPText = "ntp_text"; +const char* kColorNTPLink = "ntp_link"; +const char* kColorNTPSection = "ntp_section"; +const char* kColorNTPSectionText = "ntp_section_text"; +const char* kColorNTPSectionLink = "ntp_section_link"; +const char* kColorControlBackground = "control_background"; +const char* kColorButtonBackground = "button_background"; // Strings used by themes to identify tints to apply to different parts of // our UI. The frame tints apply to the frame color and produce the // COLOR_FRAME* colors. -static const char* kTintButtons = "buttons"; -static const char* kTintFrame = "frame"; -static const char* kTintFrameInactive = "frame_inactive"; -static const char* kTintFrameIncognito = "frame_incognito"; -static const char* kTintFrameIncognitoInactive = - "frame_incognito_inactive"; -static const char* kTintBackgroundTab = "background_tab"; +const char* kTintButtons = "buttons"; +const char* kTintFrame = "frame"; +const char* kTintFrameInactive = "frame_inactive"; +const char* kTintFrameIncognito = "frame_incognito"; +const char* kTintFrameIncognitoInactive = "frame_incognito_inactive"; +const char* kTintBackgroundTab = "background_tab"; // Strings used by themes to identify miscellaneous numerical properties. -static const char* kDisplayPropertyNTPAlignment = "ntp_background_alignment"; +const char* kDisplayPropertyNTPAlignment = "ntp_background_alignment"; // Strings used in alignment properties. -static const char* kAlignmentTop = "top"; -static const char* kAlignmentBottom = "bottom"; -static const char* kAlignmentLeft = "left"; -static const char* kAlignmentRight = "right"; +const char* kAlignmentTop = "top"; +const char* kAlignmentBottom = "bottom"; +const char* kAlignmentLeft = "left"; +const char* kAlignmentRight = "right"; // Default colors. -static const SkColor kDefaultColorFrame = SkColorSetRGB(77, 139, 217); -static const SkColor kDefaultColorFrameInactive = SkColorSetRGB(152, 188, 233); -static const SkColor kDefaultColorFrameIncognito = SkColorSetRGB(83, 106, 139); -static const SkColor kDefaultColorFrameIncognitoInactive = +const SkColor kDefaultColorFrame = SkColorSetRGB(77, 139, 217); +const SkColor kDefaultColorFrameInactive = SkColorSetRGB(152, 188, 233); +const SkColor kDefaultColorFrameIncognito = SkColorSetRGB(83, 106, 139); +const SkColor kDefaultColorFrameIncognitoInactive = SkColorSetRGB(126, 139, 156); -static const SkColor kDefaultColorToolbar = SkColorSetRGB(210, 225, 246); -static const SkColor kDefaultColorTabText = SkColorSetRGB(0, 0, 0); -static const SkColor kDefaultColorBackgroundTabText = SkColorSetRGB(64, 64, 64); -static const SkColor kDefaultColorBookmarkText = SkColorSetRGB(64, 64, 64); -static const SkColor kDefaultColorNTPBackground = SkColorSetRGB(255, 255, 255); -static const SkColor kDefaultColorNTPText = SkColorSetRGB(0, 0, 0); -static const SkColor kDefaultColorNTPLink = SkColorSetRGB(0, 0, 204); -static const SkColor kDefaultColorNTPSection = SkColorSetRGB(225, 236, 254); -static const SkColor kDefaultColorNTPSectionText = SkColorSetRGB(0, 0, 0); -static const SkColor kDefaultColorNTPSectionLink = SkColorSetRGB(0, 0, 204); -static const SkColor kDefaultColorControlBackground = NULL; -static const SkColor kDefaultColorButtonBackground = NULL; +const SkColor kDefaultColorToolbar = SkColorSetRGB(210, 225, 246); +const SkColor kDefaultColorTabText = SkColorSetRGB(0, 0, 0); +const SkColor kDefaultColorBackgroundTabText = SkColorSetRGB(64, 64, 64); +const SkColor kDefaultColorBookmarkText = SkColorSetRGB(64, 64, 64); +const SkColor kDefaultColorNTPBackground = SkColorSetRGB(255, 255, 255); +const SkColor kDefaultColorNTPText = SkColorSetRGB(0, 0, 0); +const SkColor kDefaultColorNTPLink = SkColorSetRGB(0, 0, 204); +const SkColor kDefaultColorNTPSection = SkColorSetRGB(225, 236, 254); +const SkColor kDefaultColorNTPSectionText = SkColorSetRGB(0, 0, 0); +const SkColor kDefaultColorNTPSectionLink = SkColorSetRGB(0, 0, 204); +const SkColor kDefaultColorControlBackground = NULL; +const SkColor kDefaultColorButtonBackground = NULL; // Default tints. -static const skia::HSL kDefaultTintButtons = { -1, -1, -1 }; -static const skia::HSL kDefaultTintFrame = { -1, -1, -1 }; -static const skia::HSL kDefaultTintFrameInactive = { -1, 0.5f, 0.72f }; -static const skia::HSL kDefaultTintFrameIncognito = { -1, 0.2f, 0.35f }; -static const skia::HSL kDefaultTintFrameIncognitoInactive = { -1, 0.3f, 0.6f }; -static const skia::HSL kDefaultTintBackgroundTab = { -1, 0.5, 0.75 }; +const skia::HSL kDefaultTintButtons = { -1, -1, -1 }; +const skia::HSL kDefaultTintFrame = { -1, -1, -1 }; +const skia::HSL kDefaultTintFrameInactive = { -1, 0.5f, 0.72f }; +const skia::HSL kDefaultTintFrameIncognito = { -1, 0.2f, 0.35f }; +const skia::HSL kDefaultTintFrameIncognitoInactive = { -1, 0.3f, 0.6f }; +const skia::HSL kDefaultTintBackgroundTab = { -1, 0.5, 0.75 }; +} // namespace themes + +// We really want every member of the previous namespace to be exposed +// here. The alternative is to list every member of namespace themes in a using +// directive. +using namespace themes; // Default display properties. static const int kDefaultDisplayPropertyNTPAlignment = @@ -288,19 +295,7 @@ void BrowserThemeProvider::SetTheme(Extension* extension) { } void BrowserThemeProvider::UseDefaultTheme() { - // Clear our image cache. - ClearCaches(); - - images_.clear(); - colors_.clear(); - tints_.clear(); - display_properties_.clear(); - - SaveImageData(NULL); - SaveColorData(); - SaveTintData(); - SaveDisplayPropertyData(); - + ClearAllThemeData(); NotifyThemeChanged(); UserMetrics::RecordAction(L"Themes_Reset", profile_); } @@ -560,6 +555,14 @@ std::string BrowserThemeProvider::AlignmentToString(int alignment) { return vertical_string; } +void BrowserThemeProvider::SetColor(const char* key, const SkColor& color) { + colors_[kColorFrame] = color; +} + +void BrowserThemeProvider::SetTint(const char* key, const skia::HSL& tint) { + tints_[key] = tint; +} + void BrowserThemeProvider::GenerateFrameColors() { // Generate any secondary frame colors that weren't provided. skia::HSL frame_hsl = { 0, 0, 0 }; @@ -613,6 +616,21 @@ void BrowserThemeProvider::GenerateFrameImages() { } } +void BrowserThemeProvider::ClearAllThemeData() { + // Clear our image cache. + ClearCaches(); + + images_.clear(); + colors_.clear(); + tints_.clear(); + display_properties_.clear(); + + SaveImageData(NULL); + SaveColorData(); + SaveTintData(); + SaveDisplayPropertyData(); +} + SkBitmap* BrowserThemeProvider::GenerateBitmap(int id) { if (id == IDR_THEME_TAB_BACKGROUND || id == IDR_THEME_TAB_BACKGROUND_INCOGNITO) { diff --git a/chrome/browser/browser_theme_provider.h b/chrome/browser/browser_theme_provider.h index b43a69c..b0c1b9c 100644 --- a/chrome/browser/browser_theme_provider.h +++ b/chrome/browser/browser_theme_provider.h @@ -20,6 +20,71 @@ class Extension; class Profile; class DictionaryValue; +namespace themes { + +// Strings used by themes to identify colors for different parts of our UI. +extern const char* kColorFrame; +extern const char* kColorFrameInactive; +extern const char* kColorFrameIncognito; +extern const char* kColorFrameIncognitoInactive; +extern const char* kColorToolbar; +extern const char* kColorTabText; +extern const char* kColorBackgroundTabText; +extern const char* kColorBookmarkText; +extern const char* kColorNTPBackground; +extern const char* kColorNTPText; +extern const char* kColorNTPLink; +extern const char* kColorNTPSection; +extern const char* kColorNTPSectionText; +extern const char* kColorNTPSectionLink; +extern const char* kColorControlBackground; +extern const char* kColorButtonBackground; + +// Strings used by themes to identify tints to apply to different parts of +// our UI. The frame tints apply to the frame color and produce the +// COLOR_FRAME* colors. +extern const char* kTintButtons; +extern const char* kTintFrame; +extern const char* kTintFrameInactive; +extern const char* kTintFrameIncognito; +extern const char* kTintFrameIncognitoInactive; +extern const char* kTintBackgroundTab; + +// Strings used by themes to identify miscellaneous numerical properties. +extern const char* kDisplayPropertyNTPAlignment; + +// Strings used in alignment properties. +extern const char* kAlignmentTop; +extern const char* kAlignmentBottom; +extern const char* kAlignmentLeft; +extern const char* kAlignmentRight; + +// Default colors. +extern const SkColor kDefaultColorFrame; +extern const SkColor kDefaultColorFrameInactive; +extern const SkColor kDefaultColorFrameIncognito; +extern const SkColor kDefaultColorFrameIncognitoInactive; +extern const SkColor kDefaultColorToolbar; +extern const SkColor kDefaultColorTabText; +extern const SkColor kDefaultColorBackgroundTabText; +extern const SkColor kDefaultColorBookmarkText; +extern const SkColor kDefaultColorNTPBackground; +extern const SkColor kDefaultColorNTPText; +extern const SkColor kDefaultColorNTPLink; +extern const SkColor kDefaultColorNTPSection; +extern const SkColor kDefaultColorNTPSectionText; +extern const SkColor kDefaultColorNTPSectionLink; +extern const SkColor kDefaultColorControlBackground; +extern const SkColor kDefaultColorButtonBackground; + +extern const skia::HSL kDefaultTintButtons; +extern const skia::HSL kDefaultTintFrame; +extern const skia::HSL kDefaultTintFrameInactive; +extern const skia::HSL kDefaultTintFrameIncognito; +extern const skia::HSL kDefaultTintFrameIncognitoInactive; +extern const skia::HSL kDefaultTintBackgroundTab; +} // namespace themes + class BrowserThemeProvider : public base::RefCounted<BrowserThemeProvider>, public NonThreadSafe, public ThemeProvider { @@ -78,10 +143,14 @@ class BrowserThemeProvider : public base::RefCounted<BrowserThemeProvider>, #endif // Set the current theme to the theme defined in |extension|. - void SetTheme(Extension* extension); + virtual void SetTheme(Extension* extension); // Reset the theme to default. - void UseDefaultTheme(); + virtual void UseDefaultTheme(); + + // Set the current theme to the native theme. On some platforms, the native + // theme is the default theme. + virtual void SetNativeTheme() { UseDefaultTheme(); } // Convert a bitfield alignment into a string like "top left". Public so that // it can be used to generate CSS values. Takes a bitfield of AlignmentMasks. @@ -91,6 +160,35 @@ class BrowserThemeProvider : public base::RefCounted<BrowserThemeProvider>, // AlignmentMasks static int StringToAlignment(const std::string &alignment); + protected: + // Sets an individual color value. + void SetColor(const char* id, const SkColor& color); + + // Sets an individual tint value. + void SetTint(const char* id, const skia::HSL& tint); + + // Generate any frame colors that weren't specified. + void GenerateFrameColors(); + + // Generate any frame images that weren't specified. The resulting images + // will be stored in our cache. + void GenerateFrameImages(); + + // Clears all the override fields and saves the dictionary. + void ClearAllThemeData(); + + // Load theme data from preferences. + virtual void LoadThemePrefs(); + + // Let all the browser views know that themes have changed. + void NotifyThemeChanged(); + + // Loads a bitmap from the theme, which may be tinted or + // otherwise modified, or an application default. + virtual SkBitmap* LoadThemeBitmap(int id); + + Profile* profile() { return profile_; } + private: typedef std::map<const int, std::string> ImageMap; typedef std::map<const std::string, SkColor> ColorMap; @@ -101,10 +199,6 @@ class BrowserThemeProvider : public base::RefCounted<BrowserThemeProvider>, // true on success. bool ReadThemeFileData(int id, std::vector<unsigned char>* raw_data); - // Loads a bitmap from the theme, which may be tinted or - // otherwise modified, or an application default. - SkBitmap* LoadThemeBitmap(int id); - // Returns the string key for the given tint |id| TINT_* enum value. const std::string GetTintKey(int id); @@ -139,13 +233,6 @@ class BrowserThemeProvider : public base::RefCounted<BrowserThemeProvider>, // strings, they are currently stored as integers. void SetDisplayPropertyData(DictionaryValue* display_properties); - // Generate any frame colors that weren't specified. - void GenerateFrameColors(); - - // Generate any frame images that weren't specified. The resulting images - // will be stored in our cache. - void GenerateFrameImages(); - // Create any images that aren't pregenerated (e.g. background tab images). SkBitmap* GenerateBitmap(int id); @@ -156,12 +243,6 @@ class BrowserThemeProvider : public base::RefCounted<BrowserThemeProvider>, void SaveTintData(); void SaveDisplayPropertyData(); - // Let all the browser views know that themes have changed. - void NotifyThemeChanged(); - - // Load theme data from preferences. - void LoadThemePrefs(); - SkColor FindColor(const char* id, SkColor default_color); // Frees generated images and clears the image cache. 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); diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc index 5d0ccec..0034792 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -45,6 +45,10 @@ #include "grit/locale_settings.h" #include "net/base/force_tls_state.h" +#if defined(OS_LINUX) +#include "chrome/browser/gtk/gtk_theme_provider.h" +#endif + using base::Time; using base::TimeDelta; @@ -116,6 +120,9 @@ void Profile::RegisterUserPrefs(PrefService* prefs) { prefs->RegisterBooleanPref(prefs::kEnableSpellCheck, true); prefs->RegisterBooleanPref(prefs::kEnableAutoSpellCorrect, true); prefs->RegisterBooleanPref(prefs::kEnableUserScripts, false); +#if defined(OS_LINUX) + prefs->RegisterBooleanPref(prefs::kUsesSystemTheme, false); +#endif prefs->RegisterStringPref(prefs::kCurrentThemeID, L""); prefs->RegisterDictionaryPref(prefs::kCurrentThemeImages); prefs->RegisterDictionaryPref(prefs::kCurrentThemeColors); @@ -287,6 +294,10 @@ class OffTheRecordProfileImpl : public Profile, GetOriginalProfile()->SetTheme(extension); } + virtual void SetNativeTheme() { + GetOriginalProfile()->SetNativeTheme(); + } + virtual void ClearTheme() { GetOriginalProfile()->ClearTheme(); } @@ -922,7 +933,11 @@ bool ProfileImpl::HasCreatedDownloadManager() const { void ProfileImpl::InitThemes() { if (!created_theme_provider_) { +#if defined(OS_LINUX) + scoped_refptr<BrowserThemeProvider> themes(new GtkThemeProvider); +#else scoped_refptr<BrowserThemeProvider> themes(new BrowserThemeProvider); +#endif themes->Init(this); created_theme_provider_ = true; theme_provider_.swap(themes); @@ -934,6 +949,11 @@ void ProfileImpl::SetTheme(Extension* extension) { theme_provider_.get()->SetTheme(extension); } +void ProfileImpl::SetNativeTheme() { + InitThemes(); + theme_provider_.get()->SetNativeTheme(); +} + void ProfileImpl::ClearTheme() { InitThemes(); theme_provider_.get()->UseDefaultTheme(); diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h index 7190cc7..302d222a 100644 --- a/chrome/browser/profile.h +++ b/chrome/browser/profile.h @@ -188,6 +188,9 @@ class Profile { // Set the theme to the specified extension. virtual void SetTheme(Extension* extension) = 0; + // Set the theme to the machine's native theme. + virtual void SetNativeTheme() = 0; + // Clear the theme and reset it to default. virtual void ClearTheme() = 0; @@ -340,6 +343,7 @@ class ProfileImpl : public Profile, virtual DownloadManager* GetDownloadManager(); virtual void InitThemes(); virtual void SetTheme(Extension* extension); + virtual void SetNativeTheme(); virtual void ClearTheme(); virtual ThemeProvider* GetThemeProvider(); virtual ThumbnailStore* GetThumbnailStore(); diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index bdd4e17..c4b25a7 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -995,6 +995,8 @@ 'browser/gtk/gtk_dnd_util.h', 'browser/gtk/gtk_floating_container.cc', 'browser/gtk/gtk_floating_container.h', + 'browser/gtk/gtk_theme_provider.cc', + 'browser/gtk/gtk_theme_provider.h', 'browser/gtk/hung_renderer_dialog_gtk.cc', 'browser/gtk/import_dialog_gtk.cc', 'browser/gtk/import_dialog_gtk.h', diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 159e643..426adb1 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -249,6 +249,10 @@ const wchar_t kPrintingPageHeaderRight[] = L"printing.page.header.right"; const wchar_t kPrintingPageFooterLeft[] = L"printing.page.footer.left"; const wchar_t kPrintingPageFooterCenter[] = L"printing.page.footer.center"; const wchar_t kPrintingPageFooterRight[] = L"printing.page.footer.right"; +#if defined(OS_LINUX) +// GTK specific preference on whether we should match the system GTK theme. +const wchar_t kUsesSystemTheme[] = L"extensions.theme.use_system"; +#endif const wchar_t kCurrentThemeID[] = L"extensions.theme.id"; const wchar_t kCurrentThemeImages[] = L"extensions.theme.images"; const wchar_t kCurrentThemeColors[] = L"extensions.theme.colors"; diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 5f561c4..96b2caf 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -7,6 +7,8 @@ #ifndef CHROME_COMMON_PREF_NAMES_H_ #define CHROME_COMMON_PREF_NAMES_H_ +#include "build/build_config.h" + namespace prefs { // Profile prefs @@ -89,6 +91,9 @@ extern const wchar_t kPrintingPageHeaderRight[]; extern const wchar_t kPrintingPageFooterLeft[]; extern const wchar_t kPrintingPageFooterCenter[]; extern const wchar_t kPrintingPageFooterRight[]; +#if defined(OS_LINUX) +extern const wchar_t kUsesSystemTheme[]; +#endif extern const wchar_t kCurrentThemeID[]; extern const wchar_t kCurrentThemeImages[]; extern const wchar_t kCurrentThemeColors[]; diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h index d791fdd..b360ac2 100644 --- a/chrome/test/testing_profile.h +++ b/chrome/test/testing_profile.h @@ -134,6 +134,7 @@ class TestingProfile : public Profile { } virtual void InitThemes() { } virtual void SetTheme(Extension* extension) { } + virtual void SetNativeTheme() { } virtual void ClearTheme() { } virtual ThemeProvider* GetThemeProvider() { return theme_provider_.get(); |