Home | History | Annotate | Download | only in gtk
      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