Home | History | Annotate | Download | only in libgtk2ui
      1 // Copyright (c) 2013 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 #include "chrome/browser/ui/libgtk2ui/native_theme_gtk2.h"
      6 
      7 #include <gtk/gtk.h>
      8 
      9 #include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h"
     10 #include "ui/gfx/color_utils.h"
     11 #include "ui/gfx/path.h"
     12 #include "ui/gfx/rect.h"
     13 #include "ui/gfx/size.h"
     14 #include "ui/gfx/skia_util.h"
     15 #include "ui/native_theme/common_theme.h"
     16 
     17 namespace {
     18 
     19 // Theme colors returned by GetSystemColor().
     20 const SkColor kInvalidColorIdColor = SkColorSetRGB(255, 0, 128);
     21 // Tree
     22 const SkColor kTreeBackground = SK_ColorWHITE;
     23 const SkColor kTreeTextColor = SK_ColorBLACK;
     24 const SkColor kTreeSelectedTextColor = SK_ColorBLACK;
     25 const SkColor kTreeSelectionBackgroundColor = SkColorSetRGB(0xEE, 0xEE, 0xEE);
     26 const SkColor kTreeArrowColor = SkColorSetRGB(0x7A, 0x7A, 0x7A);
     27 // Table
     28 const SkColor kTableBackground = SK_ColorWHITE;
     29 const SkColor kTableTextColor = SK_ColorBLACK;
     30 const SkColor kTableSelectedTextColor = SK_ColorBLACK;
     31 const SkColor kTableSelectionBackgroundColor = SkColorSetRGB(0xEE, 0xEE, 0xEE);
     32 const SkColor kTableGroupingIndicatorColor = SkColorSetRGB(0xCC, 0xCC, 0xCC);
     33 
     34 }  // namespace
     35 
     36 
     37 namespace libgtk2ui {
     38 
     39 // static
     40 NativeThemeGtk2* NativeThemeGtk2::instance() {
     41   CR_DEFINE_STATIC_LOCAL(NativeThemeGtk2, s_native_theme, ());
     42   return &s_native_theme;
     43 }
     44 
     45 NativeThemeGtk2::NativeThemeGtk2()
     46     : fake_window_(NULL),
     47       fake_menu_item_(NULL) {
     48 }
     49 
     50 NativeThemeGtk2::~NativeThemeGtk2() {
     51   if (fake_window_)
     52     gtk_widget_destroy(fake_window_);
     53   fake_entry_.Destroy();
     54   fake_label_.Destroy();
     55   fake_button_.Destroy();
     56   fake_menu_.Destroy();
     57 }
     58 
     59 SkColor NativeThemeGtk2::GetSystemColor(ColorId color_id) const {
     60   switch (color_id) {
     61     // TODO(erg): Still need to fish the colors out of trees and tables.
     62 
     63     // Tree
     64     case kColorId_TreeBackground:
     65       return kTreeBackground;
     66     case kColorId_TreeText:
     67       return kTreeTextColor;
     68     case kColorId_TreeSelectedText:
     69     case kColorId_TreeSelectedTextUnfocused:
     70       return kTreeSelectedTextColor;
     71     case kColorId_TreeSelectionBackgroundFocused:
     72     case kColorId_TreeSelectionBackgroundUnfocused:
     73       return kTreeSelectionBackgroundColor;
     74     case kColorId_TreeArrow:
     75       return kTreeArrowColor;
     76 
     77     // Table
     78     case kColorId_TableBackground:
     79       return kTableBackground;
     80     case kColorId_TableText:
     81       return kTableTextColor;
     82     case kColorId_TableSelectedText:
     83     case kColorId_TableSelectedTextUnfocused:
     84       return kTableSelectedTextColor;
     85     case kColorId_TableSelectionBackgroundFocused:
     86     case kColorId_TableSelectionBackgroundUnfocused:
     87       return kTableSelectionBackgroundColor;
     88     case kColorId_TableGroupingIndicatorColor:
     89       return kTableGroupingIndicatorColor;
     90 
     91     default:
     92       // Fall through.
     93       break;
     94   }
     95 
     96   return GdkColorToSkColor(GetSystemGdkColor(color_id));
     97 }
     98 
     99 void NativeThemeGtk2::PaintMenuPopupBackground(
    100     SkCanvas* canvas,
    101     const gfx::Size& size,
    102     const MenuBackgroundExtraParams& menu_background) const {
    103   if (menu_background.corner_radius > 0) {
    104     SkPaint paint;
    105     paint.setStyle(SkPaint::kFill_Style);
    106     paint.setFlags(SkPaint::kAntiAlias_Flag);
    107     paint.setColor(GetSystemColor(kColorId_MenuBackgroundColor));
    108 
    109     gfx::Path path;
    110     SkRect rect = SkRect::MakeWH(SkIntToScalar(size.width()),
    111                                  SkIntToScalar(size.height()));
    112     SkScalar radius = SkIntToScalar(menu_background.corner_radius);
    113     SkScalar radii[8] = {radius, radius, radius, radius,
    114                          radius, radius, radius, radius};
    115     path.addRoundRect(rect, radii);
    116 
    117     canvas->drawPath(path, paint);
    118   } else {
    119     canvas->drawColor(GetSystemColor(kColorId_MenuBackgroundColor),
    120                       SkXfermode::kSrc_Mode);
    121   }
    122 }
    123 
    124 void NativeThemeGtk2::PaintMenuItemBackground(
    125     SkCanvas* canvas,
    126     State state,
    127     const gfx::Rect& rect,
    128     const MenuListExtraParams& menu_list) const {
    129   SkColor color;
    130   SkPaint paint;
    131   switch (state) {
    132     case NativeTheme::kNormal:
    133     case NativeTheme::kDisabled:
    134       color = GetSystemColor(NativeTheme::kColorId_MenuBackgroundColor);
    135       paint.setColor(color);
    136       break;
    137     case NativeTheme::kHovered:
    138       color = GetSystemColor(
    139           NativeTheme::kColorId_FocusedMenuItemBackgroundColor);
    140       paint.setColor(color);
    141       break;
    142     default:
    143       NOTREACHED() << "Invalid state " << state;
    144       break;
    145   }
    146   canvas->drawRect(gfx::RectToSkRect(rect), paint);
    147 }
    148 
    149 GdkColor NativeThemeGtk2::GetSystemGdkColor(ColorId color_id) const {
    150   switch (color_id) {
    151     // Windows
    152     case kColorId_WindowBackground:
    153       return GetWindowStyle()->bg[GTK_STATE_NORMAL];
    154 
    155     // Dialogs
    156     case kColorId_DialogBackground:
    157       return GetWindowStyle()->bg[GTK_STATE_NORMAL];
    158 
    159     // FocusableBorder
    160     case kColorId_FocusedBorderColor:
    161       return GetEntryStyle()->bg[GTK_STATE_SELECTED];
    162     case kColorId_UnfocusedBorderColor:
    163       return GetEntryStyle()->text_aa[GTK_STATE_NORMAL];
    164 
    165     // MenuItem
    166     case kColorId_EnabledMenuItemForegroundColor:
    167       return GetMenuItemStyle()->text[GTK_STATE_NORMAL];
    168     case kColorId_DisabledMenuItemForegroundColor:
    169       return GetMenuItemStyle()->text[GTK_STATE_INSENSITIVE];
    170     case kColorId_SelectedMenuItemForegroundColor:
    171       return GetMenuItemStyle()->text[GTK_STATE_SELECTED];
    172     case kColorId_FocusedMenuItemBackgroundColor:
    173       return GetMenuItemStyle()->bg[GTK_STATE_SELECTED];
    174     case kColorId_HoverMenuItemBackgroundColor:
    175       return GetMenuItemStyle()->bg[GTK_STATE_PRELIGHT];
    176     case kColorId_FocusedMenuButtonBorderColor:
    177       return GetEntryStyle()->bg[GTK_STATE_NORMAL];
    178     case kColorId_HoverMenuButtonBorderColor:
    179       return GetEntryStyle()->text_aa[GTK_STATE_PRELIGHT];
    180     case kColorId_MenuBorderColor:
    181     case kColorId_EnabledMenuButtonBorderColor:
    182     case kColorId_MenuSeparatorColor: {
    183       return GetMenuItemStyle()->text[GTK_STATE_INSENSITIVE];
    184     }
    185     case kColorId_MenuBackgroundColor:
    186       return GetMenuStyle()->bg[GTK_STATE_NORMAL];
    187 
    188     // Label
    189     case kColorId_LabelEnabledColor:
    190       return GetLabelStyle()->text[GTK_STATE_NORMAL];
    191     case kColorId_LabelDisabledColor:
    192       return GetLabelStyle()->text[GTK_STATE_INSENSITIVE];
    193     case kColorId_LabelBackgroundColor:
    194       return GetWindowStyle()->bg[GTK_STATE_NORMAL];
    195 
    196     // Button
    197     case kColorId_ButtonBackgroundColor:
    198       return GetButtonStyle()->bg[GTK_STATE_NORMAL];
    199     case kColorId_ButtonEnabledColor:
    200       return GetButtonStyle()->text[GTK_STATE_NORMAL];
    201     case kColorId_ButtonDisabledColor:
    202       return GetButtonStyle()->text[GTK_STATE_INSENSITIVE];
    203     case kColorId_ButtonHighlightColor:
    204       return GetButtonStyle()->base[GTK_STATE_SELECTED];
    205     case kColorId_ButtonHoverColor:
    206       return GetButtonStyle()->text[GTK_STATE_PRELIGHT];
    207 
    208     // Textfield
    209     case kColorId_TextfieldDefaultColor:
    210       return GetEntryStyle()->text[GTK_STATE_NORMAL];
    211     case kColorId_TextfieldDefaultBackground:
    212       return GetEntryStyle()->base[GTK_STATE_NORMAL];
    213     case kColorId_TextfieldReadOnlyColor:
    214       return GetEntryStyle()->text[GTK_STATE_INSENSITIVE];
    215     case kColorId_TextfieldReadOnlyBackground:
    216       return GetEntryStyle()->base[GTK_STATE_INSENSITIVE];
    217     case kColorId_TextfieldSelectionColor:
    218       return GetEntryStyle()->text[GTK_STATE_SELECTED];
    219     case kColorId_TextfieldSelectionBackgroundFocused:
    220       return GetEntryStyle()->base[GTK_STATE_SELECTED];
    221 
    222     // Tree
    223     // Table
    224 
    225     default:
    226       // Fall through
    227       break;
    228   }
    229 
    230   return SkColorToGdkColor(kInvalidColorIdColor);
    231 }
    232 
    233 GtkWidget* NativeThemeGtk2::GetRealizedWindow() const {
    234   if (!fake_window_) {
    235     fake_window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    236     gtk_widget_realize(fake_window_);
    237   }
    238 
    239   return fake_window_;
    240 }
    241 
    242 GtkStyle* NativeThemeGtk2::GetWindowStyle() const {
    243   return gtk_rc_get_style(GetRealizedWindow());
    244 }
    245 
    246 GtkStyle* NativeThemeGtk2::GetEntryStyle() const {
    247   if (!fake_entry_.get()) {
    248     fake_entry_.Own(gtk_entry_new());
    249 
    250     // The fake entry needs to be in the window so it can be realized sow e can
    251     // use the computed parts of the style.
    252     gtk_container_add(GTK_CONTAINER(GetRealizedWindow()), fake_entry_.get());
    253     gtk_widget_realize(fake_entry_.get());
    254   }
    255   return gtk_rc_get_style(fake_entry_.get());
    256 }
    257 
    258 GtkStyle* NativeThemeGtk2::GetLabelStyle() const {
    259   if (!fake_label_.get())
    260     fake_label_.Own(gtk_label_new(""));
    261 
    262   return gtk_rc_get_style(fake_label_.get());
    263 }
    264 
    265 GtkStyle* NativeThemeGtk2::GetButtonStyle() const {
    266   if (!fake_button_.get())
    267     fake_button_.Own(gtk_button_new());
    268 
    269   return gtk_rc_get_style(fake_button_.get());
    270 }
    271 
    272 GtkStyle* NativeThemeGtk2::GetMenuStyle() const {
    273   if (!fake_menu_.get())
    274     fake_menu_.Own(gtk_menu_new());
    275   return gtk_rc_get_style(fake_menu_.get());
    276 }
    277 
    278 GtkStyle* NativeThemeGtk2::GetMenuItemStyle() const {
    279   if (!fake_menu_item_) {
    280     if (!fake_menu_.get())
    281       fake_menu_.Own(gtk_menu_new());
    282 
    283     fake_menu_item_ = gtk_menu_item_new();
    284     gtk_menu_shell_append(GTK_MENU_SHELL(fake_menu_.get()), fake_menu_item_);
    285   }
    286 
    287   return gtk_rc_get_style(fake_menu_item_);
    288 }
    289 
    290 }  // namespace libgtk2ui
    291