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