| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/libgtk2ui/native_theme_gtk2.h" |
| |
| #include <gtk/gtk.h> |
| |
| #include "chrome/browser/ui/libgtk2ui/chrome_gtk_menu_subclasses.h" |
| #include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h" |
| #include "ui/gfx/color_utils.h" |
| #include "ui/gfx/path.h" |
| #include "ui/gfx/rect.h" |
| #include "ui/gfx/size.h" |
| #include "ui/gfx/skia_util.h" |
| #include "ui/native_theme/common_theme.h" |
| |
| namespace { |
| |
| // Theme colors returned by GetSystemColor(). |
| const SkColor kInvalidColorIdColor = SkColorSetRGB(255, 0, 128); |
| // Tree |
| const SkColor kTreeBackground = SK_ColorWHITE; |
| const SkColor kTreeTextColor = SK_ColorBLACK; |
| const SkColor kTreeSelectedTextColor = SK_ColorBLACK; |
| const SkColor kTreeSelectionBackgroundColor = SkColorSetRGB(0xEE, 0xEE, 0xEE); |
| const SkColor kTreeArrowColor = SkColorSetRGB(0x7A, 0x7A, 0x7A); |
| // Table |
| const SkColor kTableBackground = SK_ColorWHITE; |
| const SkColor kTableTextColor = SK_ColorBLACK; |
| const SkColor kTableSelectedTextColor = SK_ColorBLACK; |
| const SkColor kTableSelectionBackgroundColor = SkColorSetRGB(0xEE, 0xEE, 0xEE); |
| const SkColor kTableGroupingIndicatorColor = SkColorSetRGB(0xCC, 0xCC, 0xCC); |
| |
| } // namespace |
| |
| |
| namespace libgtk2ui { |
| |
| // static |
| NativeThemeGtk2* NativeThemeGtk2::instance() { |
| CR_DEFINE_STATIC_LOCAL(NativeThemeGtk2, s_native_theme, ()); |
| return &s_native_theme; |
| } |
| |
| NativeThemeGtk2::NativeThemeGtk2() |
| : fake_window_(NULL), |
| fake_menu_item_(NULL) { |
| } |
| |
| NativeThemeGtk2::~NativeThemeGtk2() { |
| if (fake_window_) |
| gtk_widget_destroy(fake_window_); |
| fake_entry_.Destroy(); |
| fake_label_.Destroy(); |
| fake_button_.Destroy(); |
| fake_menu_.Destroy(); |
| } |
| |
| SkColor NativeThemeGtk2::GetSystemColor(ColorId color_id) const { |
| switch (color_id) { |
| // TODO(erg): Still need to fish the colors out of trees and tables. |
| |
| // Tree |
| case kColorId_TreeBackground: |
| return kTreeBackground; |
| case kColorId_TreeText: |
| return kTreeTextColor; |
| case kColorId_TreeSelectedText: |
| case kColorId_TreeSelectedTextUnfocused: |
| return kTreeSelectedTextColor; |
| case kColorId_TreeSelectionBackgroundFocused: |
| case kColorId_TreeSelectionBackgroundUnfocused: |
| return kTreeSelectionBackgroundColor; |
| case kColorId_TreeArrow: |
| return kTreeArrowColor; |
| |
| // Table |
| case kColorId_TableBackground: |
| return kTableBackground; |
| case kColorId_TableText: |
| return kTableTextColor; |
| case kColorId_TableSelectedText: |
| case kColorId_TableSelectedTextUnfocused: |
| return kTableSelectedTextColor; |
| case kColorId_TableSelectionBackgroundFocused: |
| case kColorId_TableSelectionBackgroundUnfocused: |
| return kTableSelectionBackgroundColor; |
| case kColorId_TableGroupingIndicatorColor: |
| return kTableGroupingIndicatorColor; |
| |
| default: |
| // Fall through. |
| break; |
| } |
| |
| return GdkColorToSkColor(GetSystemGdkColor(color_id)); |
| } |
| |
| void NativeThemeGtk2::PaintMenuPopupBackground( |
| SkCanvas* canvas, |
| const gfx::Size& size, |
| const MenuBackgroundExtraParams& menu_background) const { |
| if (menu_background.corner_radius > 0) { |
| SkPaint paint; |
| paint.setStyle(SkPaint::kFill_Style); |
| paint.setFlags(SkPaint::kAntiAlias_Flag); |
| paint.setColor(GetSystemColor(kColorId_MenuBackgroundColor)); |
| |
| gfx::Path path; |
| SkRect rect = SkRect::MakeWH(SkIntToScalar(size.width()), |
| SkIntToScalar(size.height())); |
| SkScalar radius = SkIntToScalar(menu_background.corner_radius); |
| SkScalar radii[8] = {radius, radius, radius, radius, |
| radius, radius, radius, radius}; |
| path.addRoundRect(rect, radii); |
| |
| canvas->drawPath(path, paint); |
| } else { |
| canvas->drawColor(GetSystemColor(kColorId_MenuBackgroundColor), |
| SkXfermode::kSrc_Mode); |
| } |
| } |
| |
| void NativeThemeGtk2::PaintMenuItemBackground( |
| SkCanvas* canvas, |
| State state, |
| const gfx::Rect& rect, |
| const MenuListExtraParams& menu_list) const { |
| SkColor color; |
| SkPaint paint; |
| switch (state) { |
| case NativeTheme::kNormal: |
| case NativeTheme::kDisabled: |
| color = GetSystemColor(NativeTheme::kColorId_MenuBackgroundColor); |
| paint.setColor(color); |
| break; |
| case NativeTheme::kHovered: |
| color = GetSystemColor( |
| NativeTheme::kColorId_FocusedMenuItemBackgroundColor); |
| paint.setColor(color); |
| break; |
| default: |
| NOTREACHED() << "Invalid state " << state; |
| break; |
| } |
| canvas->drawRect(gfx::RectToSkRect(rect), paint); |
| } |
| |
| GdkColor NativeThemeGtk2::GetSystemGdkColor(ColorId color_id) const { |
| switch (color_id) { |
| // Windows |
| case kColorId_WindowBackground: |
| return GetWindowStyle()->bg[GTK_STATE_NORMAL]; |
| |
| // Dialogs |
| case kColorId_DialogBackground: |
| return GetWindowStyle()->bg[GTK_STATE_NORMAL]; |
| |
| // FocusableBorder |
| case kColorId_FocusedBorderColor: |
| return GetEntryStyle()->bg[GTK_STATE_SELECTED]; |
| case kColorId_UnfocusedBorderColor: |
| return GetEntryStyle()->text_aa[GTK_STATE_NORMAL]; |
| |
| // MenuItem |
| case kColorId_EnabledMenuItemForegroundColor: |
| return GetMenuItemStyle()->text[GTK_STATE_NORMAL]; |
| case kColorId_DisabledMenuItemForegroundColor: |
| return GetMenuItemStyle()->text[GTK_STATE_INSENSITIVE]; |
| case kColorId_SelectedMenuItemForegroundColor: |
| return GetMenuItemStyle()->text[GTK_STATE_SELECTED]; |
| case kColorId_FocusedMenuItemBackgroundColor: |
| return GetMenuItemStyle()->bg[GTK_STATE_SELECTED]; |
| case kColorId_HoverMenuItemBackgroundColor: |
| return GetMenuItemStyle()->bg[GTK_STATE_PRELIGHT]; |
| case kColorId_FocusedMenuButtonBorderColor: |
| return GetEntryStyle()->bg[GTK_STATE_NORMAL]; |
| case kColorId_HoverMenuButtonBorderColor: |
| return GetEntryStyle()->text_aa[GTK_STATE_PRELIGHT]; |
| case kColorId_MenuBorderColor: |
| case kColorId_EnabledMenuButtonBorderColor: |
| case kColorId_MenuSeparatorColor: { |
| return GetMenuItemStyle()->text[GTK_STATE_INSENSITIVE]; |
| } |
| case kColorId_MenuBackgroundColor: |
| return GetMenuStyle()->bg[GTK_STATE_NORMAL]; |
| |
| // Label |
| case kColorId_LabelEnabledColor: |
| return GetLabelStyle()->text[GTK_STATE_NORMAL]; |
| case kColorId_LabelDisabledColor: |
| return GetLabelStyle()->text[GTK_STATE_INSENSITIVE]; |
| case kColorId_LabelBackgroundColor: |
| return GetWindowStyle()->bg[GTK_STATE_NORMAL]; |
| |
| // Button |
| case kColorId_ButtonBackgroundColor: |
| return GetButtonStyle()->bg[GTK_STATE_NORMAL]; |
| case kColorId_ButtonEnabledColor: |
| return GetButtonStyle()->text[GTK_STATE_NORMAL]; |
| case kColorId_ButtonDisabledColor: |
| return GetButtonStyle()->text[GTK_STATE_INSENSITIVE]; |
| case kColorId_ButtonHighlightColor: |
| return GetButtonStyle()->base[GTK_STATE_SELECTED]; |
| case kColorId_ButtonHoverColor: |
| return GetButtonStyle()->text[GTK_STATE_PRELIGHT]; |
| |
| // Textfield |
| case kColorId_TextfieldDefaultColor: |
| return GetEntryStyle()->text[GTK_STATE_NORMAL]; |
| case kColorId_TextfieldDefaultBackground: |
| return GetEntryStyle()->base[GTK_STATE_NORMAL]; |
| case kColorId_TextfieldReadOnlyColor: |
| return GetEntryStyle()->text[GTK_STATE_INSENSITIVE]; |
| case kColorId_TextfieldReadOnlyBackground: |
| return GetEntryStyle()->base[GTK_STATE_INSENSITIVE]; |
| case kColorId_TextfieldSelectionColor: |
| return GetEntryStyle()->text[GTK_STATE_SELECTED]; |
| case kColorId_TextfieldSelectionBackgroundFocused: |
| return GetEntryStyle()->base[GTK_STATE_SELECTED]; |
| |
| // Tree |
| // Table |
| |
| default: |
| // Fall through |
| break; |
| } |
| |
| return SkColorToGdkColor(kInvalidColorIdColor); |
| } |
| |
| GtkWidget* NativeThemeGtk2::GetRealizedWindow() const { |
| if (!fake_window_) { |
| fake_window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL); |
| gtk_widget_realize(fake_window_); |
| } |
| |
| return fake_window_; |
| } |
| |
| GtkStyle* NativeThemeGtk2::GetWindowStyle() const { |
| return gtk_rc_get_style(GetRealizedWindow()); |
| } |
| |
| GtkStyle* NativeThemeGtk2::GetEntryStyle() const { |
| if (!fake_entry_.get()) { |
| fake_entry_.Own(gtk_entry_new()); |
| |
| // The fake entry needs to be in the window so it can be realized sow e can |
| // use the computed parts of the style. |
| gtk_container_add(GTK_CONTAINER(GetRealizedWindow()), fake_entry_.get()); |
| gtk_widget_realize(fake_entry_.get()); |
| } |
| return gtk_rc_get_style(fake_entry_.get()); |
| } |
| |
| GtkStyle* NativeThemeGtk2::GetLabelStyle() const { |
| if (!fake_label_.get()) |
| fake_label_.Own(gtk_label_new("")); |
| |
| return gtk_rc_get_style(fake_label_.get()); |
| } |
| |
| GtkStyle* NativeThemeGtk2::GetButtonStyle() const { |
| if (!fake_button_.get()) |
| fake_button_.Own(gtk_button_new()); |
| |
| return gtk_rc_get_style(fake_button_.get()); |
| } |
| |
| GtkStyle* NativeThemeGtk2::GetMenuStyle() const { |
| if (!fake_menu_.get()) |
| fake_menu_.Own(gtk_menu_new()); |
| return gtk_rc_get_style(fake_menu_.get()); |
| } |
| |
| GtkStyle* NativeThemeGtk2::GetMenuItemStyle() const { |
| if (!fake_menu_item_) { |
| if (!fake_menu_.get()) |
| fake_menu_.Own(gtk_custom_menu_new()); |
| |
| fake_menu_item_ = gtk_custom_menu_item_new(); |
| gtk_menu_shell_append(GTK_MENU_SHELL(fake_menu_.get()), fake_menu_item_); |
| } |
| |
| return gtk_rc_get_style(fake_menu_item_); |
| } |
| |
| } // namespace libgtk2ui |