1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_UI_GTK_GTK_THEME_SERVICE_H_ 6 #define CHROME_BROWSER_UI_GTK_GTK_THEME_SERVICE_H_ 7 8 #include <map> 9 #include <vector> 10 11 #include "base/compiler_specific.h" 12 #include "base/lazy_instance.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "base/prefs/pref_change_registrar.h" 15 #include "chrome/browser/themes/theme_service.h" 16 #include "ui/base/glib/glib_integers.h" 17 #include "ui/base/gtk/gtk_signal.h" 18 #include "ui/base/gtk/owned_widget_gtk.h" 19 #include "ui/gfx/color_utils.h" 20 21 class CustomThemeSupplier; 22 class Profile; 23 24 namespace content { 25 class NotificationObserver; 26 } 27 28 namespace extensions { 29 class Extension; 30 } 31 32 namespace gfx { 33 class CairoCachedSurface; 34 } 35 36 namespace ui { 37 class GtkSignalRegistrar; 38 } 39 40 typedef struct _GdkDisplay GdkDisplay; 41 typedef struct _GdkEventExpose GdkEventExpose; 42 typedef struct _GdkPixbuf GdkPixbuf; 43 typedef struct _GtkIconSet GtkIconSet; 44 typedef struct _GtkStyle GtkStyle; 45 typedef struct _GtkWidget GtkWidget; 46 47 // Specialization of ThemeService which supplies system colors. 48 class GtkThemeService : public ThemeService { 49 public: 50 // A list of integer keys for a separate PerDisplaySurfaceMap that keeps 51 // what would otherwise be static icons on the X11 server. 52 enum CairoDefaultIcon { 53 NATIVE_FAVICON = 1, 54 CHROME_FAVICON, 55 NATIVE_FOLDER, 56 CHROME_FOLDER 57 }; 58 59 // Returns GtkThemeService, casted from our superclass. 60 static GtkThemeService* GetFrom(Profile* profile); 61 62 GtkThemeService(); 63 virtual ~GtkThemeService(); 64 65 // Calls |observer|.Observe() for the browser theme with this provider as the 66 // source. 67 void InitThemesFor(content::NotificationObserver* observer); 68 69 // Overridden from ThemeService: 70 // 71 // Sets that we aren't using the system theme, then calls 72 // ThemeService's implementation. 73 virtual void Init(Profile* profile) OVERRIDE; 74 virtual gfx::ImageSkia* GetImageSkiaNamed(int id) const OVERRIDE; 75 virtual gfx::Image GetImageNamed(int id) const OVERRIDE; 76 virtual SkColor GetColor(int id) const OVERRIDE; 77 virtual bool HasCustomImage(int id) const OVERRIDE; 78 virtual void SetTheme(const extensions::Extension* extension) OVERRIDE; 79 virtual void UseDefaultTheme() OVERRIDE; 80 virtual void SetNativeTheme() OVERRIDE; 81 virtual bool UsingDefaultTheme() const OVERRIDE; 82 virtual bool UsingNativeTheme() const OVERRIDE; 83 virtual void SetCustomDefaultTheme( 84 scoped_refptr<CustomThemeSupplier> theme_supplier) OVERRIDE; 85 virtual bool ShouldInitWithNativeTheme() const OVERRIDE; 86 87 // Creates a GtkChromeButton instance, registered with this theme provider, 88 // with a "destroy" signal to remove it from our internal list when it goes 89 // away. 90 GtkWidget* BuildChromeButton(); 91 92 // Creates a GtkChromeLinkButton instance. We update its state as theme 93 // changes, and listen for its destruction. 94 GtkWidget* BuildChromeLinkButton(const std::string& text); 95 96 // Builds a GtkLabel that is |color| in chrome theme mode, and the normal 97 // text color in gtk-mode. Like the previous two calls, listens for the 98 // object's destruction. 99 GtkWidget* BuildLabel(const std::string& text, const GdkColor& color); 100 101 // Creates a theme-aware vertical separator widget. 102 GtkWidget* CreateToolbarSeparator(); 103 104 // A wrapper around ui::ThemeProvider::GetColor, transforming the result to a 105 // GdkColor. 106 GdkColor GetGdkColor(int id) const; 107 108 // A weighted average between the text color and the background color of a 109 // label. Used for borders between GTK stuff and the webcontent. 110 GdkColor GetBorderColor() const; 111 112 // Returns a set of icons tinted for different GtkStateTypes based on the 113 // label colors for the IDR resource |id|. 114 GtkIconSet* GetIconSetForId(int id) const; 115 116 // This method returns the colors webkit will use for the scrollbars. When no 117 // colors are specified by the GTK+ theme, this function averages of the 118 // thumb part and of the track colors. 119 void GetScrollbarColors(GdkColor* thumb_active_color, 120 GdkColor* thumb_inactive_color, 121 GdkColor* track_color); 122 123 // Expose the inner label. Only used for testing. 124 GtkWidget* fake_label() { return fake_label_.get(); } 125 126 // Returns colors that we pass to webkit to match the system theme. 127 SkColor get_focus_ring_color() const { return focus_ring_color_; } 128 SkColor get_thumb_active_color() const { return thumb_active_color_; } 129 SkColor get_thumb_inactive_color() const { return thumb_inactive_color_; } 130 SkColor get_track_color() const { return track_color_; } 131 SkColor get_active_selection_bg_color() const { 132 return active_selection_bg_color_; 133 } 134 SkColor get_active_selection_fg_color() const { 135 return active_selection_fg_color_; 136 } 137 SkColor get_inactive_selection_bg_color() const { 138 return inactive_selection_bg_color_; 139 } 140 SkColor get_inactive_selection_fg_color() const { 141 return inactive_selection_fg_color_; 142 } 143 SkColor get_location_bar_text_color() const { 144 return location_bar_text_color_; 145 } 146 SkColor get_location_bar_bg_color() const { 147 return location_bar_bg_color_; 148 } 149 150 // These functions return an image that is not owned by the caller and should 151 // not be deleted. If |native| is true, get the GTK_STOCK version of the 152 // icon. 153 static gfx::Image GetFolderIcon(bool native); 154 static gfx::Image GetDefaultFavicon(bool native); 155 156 // Whether we use the GTK theme by default in the current desktop 157 // environment. Returns true when we GTK defaults to on. 158 static bool DefaultUsesSystemTheme(); 159 160 private: 161 typedef std::map<int, SkColor> ColorMap; 162 typedef std::map<int, color_utils::HSL> TintMap; 163 typedef std::map<int, gfx::Image*> ImageCache; 164 165 // Load theme data from preferences, possibly picking colors from GTK. 166 virtual void LoadThemePrefs() OVERRIDE; 167 168 // Let all the browser views know that themes have changed. 169 virtual void NotifyThemeChanged() OVERRIDE; 170 171 // Additionally frees the CairoCachedSurfaces. 172 virtual void FreePlatformCaches() OVERRIDE; 173 174 // Gets the name of the current icon theme and passes it to our low level XDG 175 // integration. 176 void SetXDGIconTheme(); 177 178 // Extracts colors and tints from the GTK theme, both for the 179 // ThemeService interface and the colors we send to webkit. 180 void LoadGtkValues(); 181 182 // Reads in explicit theme frame colors from the ChromeGtkFrame style class 183 // or generates them per our fallback algorithm. 184 GdkColor BuildFrameColors(GtkStyle* frame_style); 185 186 // Sets the values that we send to webkit to safe defaults. 187 void LoadDefaultValues(); 188 189 // Builds all of the tinted menus images needed for custom buttons. This is 190 // always called on style-set even if we aren't using the gtk-theme because 191 // the menus are always rendered with gtk colors. 192 void RebuildMenuIconSets(); 193 194 // Sets the underlying theme colors/tints from a GTK color. 195 void SetThemeColorFromGtk(int id, const GdkColor* color); 196 void SetThemeTintFromGtk(int id, const GdkColor* color); 197 198 // Creates and returns a frame color, either using |gtk_base| verbatim if 199 // non-NULL, or tinting |base| with |tint|. Also sets |color_id| and 200 // |tint_id| to the returned color. 201 GdkColor BuildAndSetFrameColor(const GdkColor* base, 202 const GdkColor* gtk_base, 203 const color_utils::HSL& tint, 204 int color_id, 205 int tint_id); 206 207 // Frees all the created GtkIconSets we use for the chrome menu. 208 void FreeIconSets(); 209 210 // Lazily generates each bitmap used in the gtk theme. 211 SkBitmap GenerateGtkThemeBitmap(int id) const; 212 213 // Creates a GTK+ version of IDR_THEME_FRAME. Instead of tinting, this 214 // creates a theme configurable gradient ending with |color_id| at the 215 // bottom, and |gradient_name| at the top if that color is specified in the 216 // theme. 217 SkBitmap GenerateFrameImage(int color_id, 218 const char* gradient_name) const; 219 220 // Takes the base frame image |base_id| and tints it with |tint_id|. 221 SkBitmap GenerateTabImage(int base_id) const; 222 223 // Tints an icon based on tint. 224 SkBitmap GenerateTintedIcon(int base_id, 225 const color_utils::HSL& tint) const; 226 227 // Returns the tint for buttons that contrasts with the normal window 228 // background color. 229 void GetNormalButtonTintHSL(color_utils::HSL* tint) const; 230 231 // Returns a tint that's the color of the current normal text in an entry. 232 void GetNormalEntryForegroundHSL(color_utils::HSL* tint) const; 233 234 // Returns a tint that's the color of the current highlighted text in an 235 // entry. 236 void GetSelectedEntryForegroundHSL(color_utils::HSL* tint) const; 237 238 // Handles signal from GTK that our theme has been changed. 239 CHROMEGTK_CALLBACK_1(GtkThemeService, void, OnStyleSet, GtkStyle*); 240 241 // A notification from various GObject destructors that we should 242 // remove it from our internal list. 243 CHROMEGTK_CALLBACK_0(GtkThemeService, void, OnDestroyChromeButton); 244 CHROMEGTK_CALLBACK_0(GtkThemeService, void, OnDestroyChromeLinkButton); 245 CHROMEGTK_CALLBACK_0(GtkThemeService, void, OnDestroyLabel); 246 247 CHROMEGTK_CALLBACK_1(GtkThemeService, gboolean, OnSeparatorExpose, 248 GdkEventExpose*); 249 250 void OnUsesSystemThemeChanged(); 251 252 // Whether we should be using gtk rendering. 253 bool use_gtk_; 254 255 // GtkWidgets that exist only so we can look at their properties (and take 256 // their colors). 257 GtkWidget* fake_window_; 258 GtkWidget* fake_frame_; 259 ui::OwnedWidgetGtk fake_label_; 260 ui::OwnedWidgetGtk fake_entry_; 261 ui::OwnedWidgetGtk fake_menu_item_; 262 263 // A list of diferent types of widgets that we hold on to these to notify 264 // them of theme changes. We do not own these and listen for their 265 // destruction via OnDestory{ChromeButton,ChromeLinkButton,Label}. 266 std::vector<GtkWidget*> chrome_buttons_; 267 std::vector<GtkWidget*> link_buttons_; 268 std::map<GtkWidget*, GdkColor> labels_; 269 270 // Tracks all the signals we have connected to on various widgets. 271 scoped_ptr<ui::GtkSignalRegistrar> signals_; 272 273 // Tints and colors calculated by LoadGtkValues() that are given to the 274 // caller while |use_gtk_| is true. 275 ColorMap colors_; 276 TintMap tints_; 277 278 // Colors used to tint certain icons. 279 color_utils::HSL button_tint_; 280 color_utils::HSL entry_tint_; 281 color_utils::HSL selected_entry_tint_; 282 283 // Colors that we pass to WebKit. These are generated each time the theme 284 // changes. 285 SkColor focus_ring_color_; 286 SkColor thumb_active_color_; 287 SkColor thumb_inactive_color_; 288 SkColor track_color_; 289 SkColor active_selection_bg_color_; 290 SkColor active_selection_fg_color_; 291 SkColor inactive_selection_bg_color_; 292 SkColor inactive_selection_fg_color_; 293 SkColor location_bar_bg_color_; 294 SkColor location_bar_text_color_; 295 296 // A GtkIconSet that has the tinted icons for the NORMAL and PRELIGHT states 297 // of the IDR_FULLSCREEN_MENU_BUTTON tinted to the respective menu item label 298 // colors. 299 GtkIconSet* fullscreen_icon_set_; 300 301 // Image cache of lazily created images, created when requested by 302 // GetImageNamed(). 303 mutable ImageCache gtk_images_; 304 305 PrefChangeRegistrar registrar_; 306 307 // This is a dummy widget that only exists so we have something to pass to 308 // gtk_widget_render_icon(). 309 static GtkWidget* icon_widget_; 310 311 // The default folder icon and default bookmark icon for the GTK theme. 312 // These are static because the system can only have one theme at a time. 313 // They are cached when they are requested the first time, and cleared when 314 // the system theme changes. 315 static base::LazyInstance<gfx::Image> default_folder_icon_; 316 static base::LazyInstance<gfx::Image> default_bookmark_icon_; 317 }; 318 319 #endif // CHROME_BROWSER_UI_GTK_GTK_THEME_SERVICE_H_ 320