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