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