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