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