• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
instance()41 NativeThemeGtk2* NativeThemeGtk2::instance() {
42   CR_DEFINE_STATIC_LOCAL(NativeThemeGtk2, s_native_theme, ());
43   return &s_native_theme;
44 }
45 
NativeThemeGtk2()46 NativeThemeGtk2::NativeThemeGtk2()
47     : fake_window_(NULL),
48       fake_menu_item_(NULL) {
49 }
50 
~NativeThemeGtk2()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 
GetSystemColor(ColorId color_id) const60 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 
PaintMenuPopupBackground(SkCanvas * canvas,const gfx::Size & size,const MenuBackgroundExtraParams & menu_background) const100 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 
PaintMenuItemBackground(SkCanvas * canvas,State state,const gfx::Rect & rect,const MenuListExtraParams & menu_list) const125 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 
GetSystemGdkColor(ColorId color_id) const150 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 
GetRealizedWindow() const234 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 
GetWindowStyle() const243 GtkStyle* NativeThemeGtk2::GetWindowStyle() const {
244   return gtk_rc_get_style(GetRealizedWindow());
245 }
246 
GetEntryStyle() const247 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 
GetLabelStyle() const259 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 
GetButtonStyle() const266 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 
GetMenuStyle() const273 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 
GetMenuItemStyle() const279 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