Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(41)

Side by Side Diff: chrome/browser/ui/gtk/gtk_theme_service.cc

Issue 9447096: gtk: Rename GtkThemeService to ThemeServiceGtk. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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/gtk/gtk_theme_service.h"
6
7 #include <gtk/gtk.h>
8
9 #include <set>
10 #include <string>
11
12 #include "base/debug/trace_event.h"
13 #include "base/environment.h"
14 #include "base/nix/xdg_util.h"
15 #include "base/stl_util.h"
16 #include "chrome/browser/prefs/pref_service.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/themes/theme_service_factory.h"
19 #include "chrome/browser/ui/browser_list.h"
20 #include "chrome/browser/ui/browser_window.h"
21 #include "chrome/browser/ui/gtk/chrome_gtk_frame.h"
22 #include "chrome/browser/ui/gtk/gtk_chrome_button.h"
23 #include "chrome/browser/ui/gtk/gtk_chrome_link_button.h"
24 #include "chrome/browser/ui/gtk/gtk_util.h"
25 #include "chrome/browser/ui/gtk/hover_controller_gtk.h"
26 #include "chrome/common/chrome_notification_types.h"
27 #include "chrome/common/pref_names.h"
28 #include "content/public/browser/notification_details.h"
29 #include "content/public/browser/notification_service.h"
30 #include "content/public/browser/notification_source.h"
31 #include "grit/theme_resources.h"
32 #include "grit/theme_resources_standard.h"
33 #include "grit/ui_resources.h"
34 #include "third_party/skia/include/core/SkBitmap.h"
35 #include "third_party/skia/include/core/SkCanvas.h"
36 #include "third_party/skia/include/core/SkColor.h"
37 #include "third_party/skia/include/core/SkShader.h"
38 #include "ui/base/gtk/gtk_hig_constants.h"
39 #include "ui/base/gtk/gtk_signal_registrar.h"
40 #include "ui/base/resource/resource_bundle.h"
41 #include "ui/gfx/canvas_skia.h"
42 #include "ui/gfx/color_utils.h"
43 #include "ui/gfx/gtk_util.h"
44 #include "ui/gfx/image/cairo_cached_surface.h"
45 #include "ui/gfx/image/image.h"
46 #include "ui/gfx/skbitmap_operations.h"
47 #include "ui/gfx/skia_util.h"
48 #include "ui/gfx/skia_utils_gtk.h"
49
50 namespace {
51
52 // The size of the rendered toolbar image.
53 const int kToolbarImageWidth = 64;
54 const int kToolbarImageHeight = 128;
55
56 // How much to tint the GTK+ color lighter at the top of the window.
57 const color_utils::HSL kGtkFrameShift = { -1, -1, 0.58 };
58
59 // How much to tint the GTK+ color when an explicit frame color hasn't been
60 // specified.
61 const color_utils::HSL kDefaultFrameShift = { -1, -1, 0.4 };
62
63 // Values used as the new luminance and saturation values in the inactive tab
64 // text color.
65 const double kDarkInactiveLuminance = 0.85;
66 const double kLightInactiveLuminance = 0.15;
67 const double kHeavyInactiveSaturation = 0.7;
68 const double kLightInactiveSaturation = 0.3;
69
70 // Number of times that the background color should be counted when trying to
71 // calculate the border color in GTK theme mode.
72 const int kBgWeight = 3;
73
74 // Padding to left, top and bottom of vertical separators.
75 const int kSeparatorPadding = 2;
76
77 // Default color for links on the NTP when the GTK+ theme doesn't define a
78 // link color. Constant taken from gtklinkbutton.c.
79 const GdkColor kDefaultLinkColor = { 0, 0, 0, 0xeeee };
80
81 // Middle color of the separator gradient.
82 const double kMidSeparatorColor[] =
83 { 194.0 / 255.0, 205.0 / 255.0, 212.0 / 212.0 };
84 // Top color of the separator gradient.
85 const double kTopSeparatorColor[] =
86 { 222.0 / 255.0, 234.0 / 255.0, 248.0 / 255.0 };
87
88 // A list of images that we provide while in gtk mode.
89 const int kThemeImages[] = {
90 IDR_THEME_TOOLBAR,
91 IDR_THEME_TAB_BACKGROUND,
92 IDR_THEME_TAB_BACKGROUND_INCOGNITO,
93 IDR_THEME_FRAME,
94 IDR_THEME_FRAME_INACTIVE,
95 IDR_THEME_FRAME_INCOGNITO,
96 IDR_THEME_FRAME_INCOGNITO_INACTIVE,
97 };
98
99 // A list of icons used in the autocomplete view that should be tinted to the
100 // current gtk theme selection color so they stand out against the GtkEntry's
101 // base color.
102 const int kAutocompleteImages[] = {
103 IDR_OMNIBOX_EXTENSION_APP,
104 IDR_OMNIBOX_HTTP,
105 IDR_OMNIBOX_HTTP_DARK,
106 IDR_OMNIBOX_HISTORY,
107 IDR_OMNIBOX_HISTORY_DARK,
108 IDR_OMNIBOX_SEARCH,
109 IDR_OMNIBOX_SEARCH_DARK,
110 IDR_OMNIBOX_STAR,
111 IDR_OMNIBOX_STAR_DARK,
112 IDR_GEOLOCATION_ALLOWED_LOCATIONBAR_ICON,
113 IDR_GEOLOCATION_DENIED_LOCATIONBAR_ICON,
114 };
115
116 bool IsOverridableImage(int id) {
117 CR_DEFINE_STATIC_LOCAL(std::set<int>, images, ());
118 if (images.empty()) {
119 images.insert(kThemeImages, kThemeImages + arraysize(kThemeImages));
120 images.insert(kAutocompleteImages,
121 kAutocompleteImages + arraysize(kAutocompleteImages));
122
123 const std::set<int>& buttons = ThemeService::GetTintableToolbarButtons();
124 images.insert(buttons.begin(), buttons.end());
125 }
126
127 return images.count(id) > 0;
128 }
129
130 // Picks a button tint from a set of background colors. While
131 // |accent_gdk_color| will usually be the same color through a theme, this
132 // function will get called with the normal GtkLabel |text_color|/GtkWindow
133 // |background_color| pair and the GtkEntry |text_color|/|background_color|
134 // pair. While 3/4 of the time the resulting tint will be the same, themes that
135 // have a dark window background (with light text) and a light text entry (with
136 // dark text) will get better icons with this separated out.
137 void PickButtonTintFromColors(const GdkColor& accent_gdk_color,
138 const GdkColor& text_color,
139 const GdkColor& background_color,
140 color_utils::HSL* tint) {
141 SkColor accent_color = gfx::GdkColorToSkColor(accent_gdk_color);
142 color_utils::HSL accent_tint;
143 color_utils::SkColorToHSL(accent_color, &accent_tint);
144
145 color_utils::HSL text_tint;
146 color_utils::SkColorToHSL(gfx::GdkColorToSkColor(text_color), &text_tint);
147
148 color_utils::HSL background_tint;
149 color_utils::SkColorToHSL(gfx::GdkColorToSkColor(background_color),
150 &background_tint);
151
152 // If the accent color is gray, then our normal HSL tomfoolery will bring out
153 // whatever color is oddly dominant (for example, in rgb space [125, 128,
154 // 125] will tint green instead of gray). Slight differences (+/-10 (4%) to
155 // all color components) should be interpreted as this color being gray and
156 // we should switch into a special grayscale mode.
157 int rb_diff = abs(SkColorGetR(accent_color) - SkColorGetB(accent_color));
158 int rg_diff = abs(SkColorGetR(accent_color) - SkColorGetG(accent_color));
159 int bg_diff = abs(SkColorGetB(accent_color) - SkColorGetG(accent_color));
160 if (rb_diff < 10 && rg_diff < 10 && bg_diff < 10) {
161 // Our accent is white/gray/black. Only the luminance of the accent color
162 // matters.
163 tint->h = -1;
164
165 // Use the saturation of the text.
166 tint->s = text_tint.s;
167
168 // Use the luminance of the accent color UNLESS there isn't enough
169 // luminance contrast between the accent color and the base color.
170 if (fabs(accent_tint.l - background_tint.l) > 0.3)
171 tint->l = accent_tint.l;
172 else
173 tint->l = text_tint.l;
174 } else {
175 // Our accent is a color.
176 tint->h = accent_tint.h;
177
178 // Don't modify the saturation; the amount of color doesn't matter.
179 tint->s = -1;
180
181 // If the text wants us to darken the icon, don't change the luminance (the
182 // icons are already dark enough). Otherwise, lighten the icon by no more
183 // than 0.9 since we don't want a pure-white icon even if the text is pure
184 // white.
185 if (text_tint.l < 0.5)
186 tint->l = -1;
187 else if (text_tint.l <= 0.9)
188 tint->l = text_tint.l;
189 else
190 tint->l = 0.9;
191 }
192 }
193
194
195 // Builds and tints the image with |id| to the GtkStateType |state| and
196 // places the result in |icon_set|.
197 void BuildIconFromIDRWithColor(int id,
198 GtkStyle* style,
199 GtkStateType state,
200 GtkIconSet* icon_set) {
201 SkColor color = gfx::GdkColorToSkColor(style->fg[state]);
202 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
203 SkBitmap original = *rb.GetBitmapNamed(id);
204
205 SkBitmap fill_color;
206 fill_color.setConfig(SkBitmap::kARGB_8888_Config,
207 original.width(), original.height(), 0);
208 fill_color.allocPixels();
209 fill_color.eraseColor(color);
210 SkBitmap masked = SkBitmapOperations::CreateMaskedBitmap(
211 fill_color, original);
212
213 GtkIconSource* icon = gtk_icon_source_new();
214 GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&masked);
215 gtk_icon_source_set_pixbuf(icon, pixbuf);
216 g_object_unref(pixbuf);
217
218 gtk_icon_source_set_direction_wildcarded(icon, TRUE);
219 gtk_icon_source_set_size_wildcarded(icon, TRUE);
220
221 gtk_icon_source_set_state(icon, state);
222 // All fields default to wildcarding being on and setting a property doesn't
223 // turn off wildcarding. You need to do this yourself. This is stated once in
224 // the documentation in the gtk_icon_source_new() function, and no where else.
225 gtk_icon_source_set_state_wildcarded(
226 icon, state == GTK_STATE_NORMAL);
227
228 gtk_icon_set_add_source(icon_set, icon);
229 gtk_icon_source_free(icon);
230 }
231
232 // Applies an HSL shift to a GdkColor (instead of an SkColor)
233 void GdkColorHSLShift(const color_utils::HSL& shift, GdkColor* frame_color) {
234 SkColor shifted = color_utils::HSLShift(gfx::GdkColorToSkColor(*frame_color),
235 shift);
236 frame_color->pixel = 0;
237 frame_color->red = SkColorGetR(shifted) * ui::kSkiaToGDKMultiplier;
238 frame_color->green = SkColorGetG(shifted) * ui::kSkiaToGDKMultiplier;
239 frame_color->blue = SkColorGetB(shifted) * ui::kSkiaToGDKMultiplier;
240 }
241
242 } // namespace
243
244 GtkWidget* GtkThemeService::icon_widget_ = NULL;
245 gfx::Image* GtkThemeService::default_folder_icon_ = NULL;
246 gfx::Image* GtkThemeService::default_bookmark_icon_ = NULL;
247
248 // static
249 GtkThemeService* GtkThemeService::GetFrom(Profile* profile) {
250 return static_cast<GtkThemeService*>(
251 ThemeServiceFactory::GetForProfile(profile));
252 }
253
254 GtkThemeService::GtkThemeService()
255 : ThemeService(),
256 use_gtk_(false),
257 fake_window_(gtk_window_new(GTK_WINDOW_TOPLEVEL)),
258 fake_frame_(chrome_gtk_frame_new()),
259 signals_(new ui::GtkSignalRegistrar),
260 fullscreen_icon_set_(NULL) {
261 fake_label_.Own(gtk_label_new(""));
262 fake_entry_.Own(gtk_entry_new());
263 fake_menu_item_.Own(gtk_menu_item_new());
264
265 // Only realized widgets receive style-set notifications, which we need to
266 // broadcast new theme images and colors. Only realized widgets have style
267 // properties, too, which we query for some colors.
268 gtk_widget_realize(fake_frame_);
269 gtk_widget_realize(fake_window_);
270 signals_->Connect(fake_frame_, "style-set",
271 G_CALLBACK(&OnStyleSetThunk), this);
272 }
273
274 GtkThemeService::~GtkThemeService() {
275 gtk_widget_destroy(fake_window_);
276 gtk_widget_destroy(fake_frame_);
277 fake_label_.Destroy();
278 fake_entry_.Destroy();
279 fake_menu_item_.Destroy();
280
281 FreeIconSets();
282
283 // We have to call this because FreePlatformCached() in ~ThemeService
284 // doesn't call the right virutal FreePlatformCaches.
285 FreePlatformCaches();
286 }
287
288 void GtkThemeService::Init(Profile* profile) {
289 registrar_.Init(profile->GetPrefs());
290 registrar_.Add(prefs::kUsesSystemTheme, this);
291 #if defined(OS_CHROMEOS)
292 use_gtk_ = false;
293 #else
294 use_gtk_ = profile->GetPrefs()->GetBoolean(prefs::kUsesSystemTheme);
295 #endif
296 ThemeService::Init(profile);
297 }
298
299 SkBitmap* GtkThemeService::GetBitmapNamed(int id) const {
300 // TODO(erg): Remove this const cast. The gfx::Image interface returns its
301 // images const. GetBitmapNamed() also should but doesn't and has a million
302 // callsites.
303 return const_cast<SkBitmap*>(GetImageNamed(id)->ToSkBitmap());
304 }
305
306 const gfx::Image* GtkThemeService::GetImageNamed(int id) const {
307 // Try to get our cached version:
308 ImageCache::const_iterator it = gtk_images_.find(id);
309 if (it != gtk_images_.end())
310 return it->second;
311
312 if (use_gtk_ && IsOverridableImage(id)) {
313 gfx::Image* image = new gfx::Image(GenerateGtkThemeBitmap(id));
314 gtk_images_[id] = image;
315 return image;
316 }
317
318 return ThemeService::GetImageNamed(id);
319 }
320
321 SkColor GtkThemeService::GetColor(int id) const {
322 if (use_gtk_) {
323 ColorMap::const_iterator it = colors_.find(id);
324 if (it != colors_.end())
325 return it->second;
326 }
327
328 return ThemeService::GetColor(id);
329 }
330
331 bool GtkThemeService::HasCustomImage(int id) const {
332 if (use_gtk_)
333 return IsOverridableImage(id);
334
335 return ThemeService::HasCustomImage(id);
336 }
337
338 void GtkThemeService::InitThemesFor(NotificationObserver* observer) {
339 observer->Observe(chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
340 content::Source<ThemeService>(this),
341 content::NotificationService::NoDetails());
342 }
343
344 void GtkThemeService::SetTheme(const Extension* extension) {
345 profile()->GetPrefs()->SetBoolean(prefs::kUsesSystemTheme, false);
346 LoadDefaultValues();
347 ThemeService::SetTheme(extension);
348 }
349
350 void GtkThemeService::UseDefaultTheme() {
351 profile()->GetPrefs()->SetBoolean(prefs::kUsesSystemTheme, false);
352 LoadDefaultValues();
353 ThemeService::UseDefaultTheme();
354 }
355
356 void GtkThemeService::SetNativeTheme() {
357 profile()->GetPrefs()->SetBoolean(prefs::kUsesSystemTheme, true);
358 ClearAllThemeData();
359 LoadGtkValues();
360 NotifyThemeChanged();
361 }
362
363 bool GtkThemeService::UsingDefaultTheme() const {
364 return !use_gtk_ && ThemeService::UsingDefaultTheme();
365 }
366
367 bool GtkThemeService::UsingNativeTheme() const {
368 return use_gtk_;
369 }
370
371 void GtkThemeService::Observe(int type,
372 const content::NotificationSource& source,
373 const content::NotificationDetails& details) {
374 if ((type == chrome::NOTIFICATION_PREF_CHANGED) &&
375 (*content::Details<std::string>(details).ptr() ==
376 prefs::kUsesSystemTheme)) {
377 #if !defined(OS_CHROMEOS)
378 use_gtk_ = profile()->GetPrefs()->GetBoolean(prefs::kUsesSystemTheme);
379 #endif
380 } else {
381 ThemeService::Observe(type, source, details);
382 }
383 }
384
385 GtkWidget* GtkThemeService::BuildChromeButton() {
386 GtkWidget* button = HoverControllerGtk::CreateChromeButton();
387 gtk_chrome_button_set_use_gtk_rendering(GTK_CHROME_BUTTON(button), use_gtk_);
388 chrome_buttons_.push_back(button);
389
390 signals_->Connect(button, "destroy", G_CALLBACK(OnDestroyChromeButtonThunk),
391 this);
392 return button;
393 }
394
395 GtkWidget* GtkThemeService::BuildChromeLinkButton(const std::string& text) {
396 GtkWidget* link_button = gtk_chrome_link_button_new(text.c_str());
397 gtk_chrome_link_button_set_use_gtk_theme(
398 GTK_CHROME_LINK_BUTTON(link_button),
399 use_gtk_);
400 link_buttons_.push_back(link_button);
401
402 signals_->Connect(link_button, "destroy",
403 G_CALLBACK(OnDestroyChromeLinkButtonThunk), this);
404
405 return link_button;
406 }
407
408 GtkWidget* GtkThemeService::BuildLabel(const std::string& text,
409 GdkColor color) {
410 GtkWidget* label = gtk_label_new(text.empty() ? NULL : text.c_str());
411 if (!use_gtk_)
412 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &color);
413 labels_.insert(std::make_pair(label, color));
414
415 signals_->Connect(label, "destroy", G_CALLBACK(OnDestroyLabelThunk), this);
416
417 return label;
418 }
419
420 GtkWidget* GtkThemeService::CreateToolbarSeparator() {
421 GtkWidget* separator = gtk_vseparator_new();
422 GtkWidget* alignment = gtk_alignment_new(0, 0, 1, 1);
423 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment),
424 kSeparatorPadding, kSeparatorPadding, kSeparatorPadding, 0);
425 gtk_container_add(GTK_CONTAINER(alignment), separator);
426
427 signals_->Connect(separator, "expose-event",
428 G_CALLBACK(OnSeparatorExposeThunk), this);
429 return alignment;
430 }
431
432 GdkColor GtkThemeService::GetGdkColor(int id) const {
433 return gfx::SkColorToGdkColor(GetColor(id));
434 }
435
436 GdkColor GtkThemeService::GetBorderColor() const {
437 GtkStyle* style = gtk_rc_get_style(fake_window_);
438
439 GdkColor text;
440 GdkColor bg;
441 if (use_gtk_) {
442 text = style->text[GTK_STATE_NORMAL];
443 bg = style->bg[GTK_STATE_NORMAL];
444 } else {
445 text = GetGdkColor(COLOR_BOOKMARK_TEXT);
446 bg = GetGdkColor(COLOR_TOOLBAR);
447 }
448
449 // Creates a weighted average between the text and base color where
450 // the base color counts more than once.
451 GdkColor color;
452 color.pixel = 0;
453 color.red = (text.red + (bg.red * kBgWeight)) / (1 + kBgWeight);
454 color.green = (text.green + (bg.green * kBgWeight)) / (1 + kBgWeight);
455 color.blue = (text.blue + (bg.blue * kBgWeight)) / (1 + kBgWeight);
456
457 return color;
458 }
459
460 GtkIconSet* GtkThemeService::GetIconSetForId(int id) const {
461 if (id == IDR_FULLSCREEN_MENU_BUTTON)
462 return fullscreen_icon_set_;
463
464 return NULL;
465 }
466
467 void GtkThemeService::GetScrollbarColors(GdkColor* thumb_active_color,
468 GdkColor* thumb_inactive_color,
469 GdkColor* track_color) {
470 const GdkColor* theme_thumb_active = NULL;
471 const GdkColor* theme_thumb_inactive = NULL;
472 const GdkColor* theme_trough_color = NULL;
473 gtk_widget_style_get(GTK_WIDGET(fake_frame_),
474 "scrollbar-slider-prelight-color", &theme_thumb_active,
475 "scrollbar-slider-normal-color", &theme_thumb_inactive,
476 "scrollbar-trough-color", &theme_trough_color,
477 NULL);
478
479 // Ask the theme if the theme specifies all the scrollbar colors and short
480 // circuit the expensive painting/compositing if we have all of them.
481 if (theme_thumb_active && theme_thumb_inactive && theme_trough_color) {
482 *thumb_active_color = *theme_thumb_active;
483 *thumb_inactive_color = *theme_thumb_inactive;
484 *track_color = *theme_trough_color;
485 return;
486 }
487
488 // Create window containing scrollbar elements
489 GtkWidget* window = gtk_window_new(GTK_WINDOW_POPUP);
490 GtkWidget* fixed = gtk_fixed_new();
491 GtkWidget* scrollbar = gtk_hscrollbar_new(NULL);
492 gtk_container_add(GTK_CONTAINER(window), fixed);
493 gtk_container_add(GTK_CONTAINER(fixed), scrollbar);
494 gtk_widget_realize(window);
495 gtk_widget_realize(scrollbar);
496
497 // Draw scrollbar thumb part and track into offscreen image
498 const int kWidth = 100;
499 const int kHeight = 20;
500 GtkStyle* style = gtk_rc_get_style(scrollbar);
501 GdkWindow* gdk_window = gtk_widget_get_window(window);
502 GdkPixmap* pm = gdk_pixmap_new(gdk_window, kWidth, kHeight, -1);
503 GdkRectangle rect = { 0, 0, kWidth, kHeight };
504 unsigned char data[3 * kWidth * kHeight];
505 for (int i = 0; i < 3; ++i) {
506 if (i < 2) {
507 // Thumb part
508 gtk_paint_slider(style, pm,
509 i == 0 ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
510 GTK_SHADOW_OUT, &rect, scrollbar, "slider", 0, 0,
511 kWidth, kHeight, GTK_ORIENTATION_HORIZONTAL);
512 } else {
513 // Track
514 gtk_paint_box(style, pm, GTK_STATE_ACTIVE, GTK_SHADOW_IN, &rect,
515 scrollbar, "trough-upper", 0, 0, kWidth, kHeight);
516 }
517 GdkPixbuf* pb = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB,
518 FALSE, 8, kWidth, kHeight,
519 3 * kWidth, 0, 0);
520 gdk_pixbuf_get_from_drawable(pb, pm, NULL, 0, 0, 0, 0, kWidth, kHeight);
521
522 // Sample pixels
523 int components[3] = { 0 };
524 for (int y = 2; y < kHeight - 2; ++y) {
525 for (int c = 0; c < 3; ++c) {
526 // Sample a vertical slice of pixels at about one-thirds from the
527 // left edge. This allows us to avoid any fixed graphics that might be
528 // located at the edges or in the center of the scrollbar.
529 // Each pixel is made up of a red, green, and blue component; taking up
530 // a total of three bytes.
531 components[c] += data[3 * (kWidth / 3 + y * kWidth) + c];
532 }
533 }
534 GdkColor* color = i == 0 ? thumb_active_color :
535 i == 1 ? thumb_inactive_color :
536 track_color;
537 color->pixel = 0;
538 // We sampled pixels across the full height of the image, ignoring a two
539 // pixel border. In some themes, the border has a completely different
540 // color which we do not want to factor into our average color computation.
541 //
542 // We now need to scale the colors from the 0..255 range, to the wider
543 // 0..65535 range, and we need to actually compute the average color; so,
544 // we divide by the total number of pixels in the sample.
545 color->red = components[0] * 65535 / (255 * (kHeight - 4));
546 color->green = components[1] * 65535 / (255 * (kHeight - 4));
547 color->blue = components[2] * 65535 / (255 * (kHeight - 4));
548
549 g_object_unref(pb);
550 }
551 g_object_unref(pm);
552
553 gtk_widget_destroy(window);
554
555 // Override any of the default colors with ones that were specified by the
556 // theme.
557 if (theme_thumb_active)
558 *thumb_active_color = *theme_thumb_active;
559
560 if (theme_thumb_inactive)
561 *thumb_inactive_color = *theme_thumb_inactive;
562
563 if (theme_trough_color)
564 *track_color = *theme_trough_color;
565 }
566
567 // static
568 gfx::Image* GtkThemeService::GetFolderIcon(bool native) {
569 if (native) {
570 if (!icon_widget_)
571 icon_widget_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
572 // We never release our ref, so we will leak this on program shutdown.
573 if (!default_folder_icon_) {
574 GdkPixbuf* pixbuf = gtk_widget_render_icon(
575 icon_widget_, GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU, NULL);
576 if (pixbuf)
577 default_folder_icon_ = new gfx::Image(pixbuf);
578 }
579 if (default_folder_icon_)
580 return default_folder_icon_;
581 }
582
583 return &ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
584 IDR_BOOKMARK_BAR_FOLDER);
585 }
586
587 // static
588 gfx::Image* GtkThemeService::GetDefaultFavicon(bool native) {
589 if (native) {
590 if (!icon_widget_)
591 icon_widget_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
592 // We never release our ref, so we will leak this on program shutdown.
593 if (!default_bookmark_icon_) {
594 GdkPixbuf* pixbuf = gtk_widget_render_icon(
595 icon_widget_, GTK_STOCK_FILE, GTK_ICON_SIZE_MENU, NULL);
596 if (pixbuf)
597 default_bookmark_icon_ = new gfx::Image(pixbuf);
598 }
599 if (default_bookmark_icon_)
600 return default_bookmark_icon_;
601 }
602
603 return &ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
604 IDR_DEFAULT_FAVICON);
605 }
606
607 // static
608 bool GtkThemeService::DefaultUsesSystemTheme() {
609 #if defined(OS_CHROMEOS)
610 return false;
611 #else
612 scoped_ptr<base::Environment> env(base::Environment::Create());
613
614 switch (base::nix::GetDesktopEnvironment(env.get())) {
615 case base::nix::DESKTOP_ENVIRONMENT_GNOME:
616 case base::nix::DESKTOP_ENVIRONMENT_XFCE:
617 return true;
618 default:
619 return false;
620 }
621 #endif
622 }
623
624 void GtkThemeService::ClearAllThemeData() {
625 colors_.clear();
626 tints_.clear();
627
628 ThemeService::ClearAllThemeData();
629 }
630
631 void GtkThemeService::LoadThemePrefs() {
632 if (use_gtk_) {
633 LoadGtkValues();
634 } else {
635 LoadDefaultValues();
636 ThemeService::LoadThemePrefs();
637 }
638
639 RebuildMenuIconSets();
640 }
641
642 void GtkThemeService::NotifyThemeChanged() {
643 ThemeService::NotifyThemeChanged();
644
645 // Notify all GtkChromeButtons of their new rendering mode:
646 for (std::vector<GtkWidget*>::iterator it = chrome_buttons_.begin();
647 it != chrome_buttons_.end(); ++it) {
648 gtk_chrome_button_set_use_gtk_rendering(
649 GTK_CHROME_BUTTON(*it), use_gtk_);
650 }
651
652 for (std::vector<GtkWidget*>::iterator it = link_buttons_.begin();
653 it != link_buttons_.end(); ++it) {
654 gtk_chrome_link_button_set_use_gtk_theme(
655 GTK_CHROME_LINK_BUTTON(*it), use_gtk_);
656 }
657
658 for (std::map<GtkWidget*, GdkColor>::iterator it = labels_.begin();
659 it != labels_.end(); ++it) {
660 const GdkColor* color = use_gtk_ ? NULL : &it->second;
661 gtk_util::SetLabelColor(it->first, color);
662 }
663
664 Browser* browser = BrowserList::GetLastActive();
665 if (browser && browser->window()) {
666 GtkWindow* window = browser->window()->GetNativeHandle();
667 gtk_util::SetDefaultWindowIcon(window);
668 gtk_util::SetWindowIcon(window, browser->profile());
669 }
670 }
671
672 void GtkThemeService::FreePlatformCaches() {
673 ThemeService::FreePlatformCaches();
674 STLDeleteValues(&gtk_images_);
675 }
676
677 void GtkThemeService::OnStyleSet(GtkWidget* widget,
678 GtkStyle* previous_style) {
679 gfx::Image* default_folder_icon = default_folder_icon_;
680 gfx::Image* default_bookmark_icon = default_bookmark_icon_;
681 default_folder_icon_ = NULL;
682 default_bookmark_icon_ = NULL;
683
684 if (profile()->GetPrefs()->GetBoolean(prefs::kUsesSystemTheme)) {
685 ClearAllThemeData();
686 LoadGtkValues();
687 NotifyThemeChanged();
688 }
689
690 RebuildMenuIconSets();
691
692 // Free the old icons only after the theme change notification has gone
693 // through.
694 if (default_folder_icon)
695 delete default_folder_icon;
696 if (default_bookmark_icon)
697 delete default_bookmark_icon;
698 }
699
700 void GtkThemeService::LoadGtkValues() {
701 // Before we start setting images and values, we have to clear out old, stale
702 // values. (If we don't do this, we'll regress startup time in the case where
703 // someone installs a heavyweight theme, then goes back to GTK.)
704 profile()->GetPrefs()->ClearPref(prefs::kCurrentThemeImages);
705
706 GtkStyle* frame_style = gtk_rc_get_style(fake_frame_);
707
708 GtkStyle* window_style = gtk_rc_get_style(fake_window_);
709 SetThemeColorFromGtk(ThemeService::COLOR_CONTROL_BACKGROUND,
710 &window_style->bg[GTK_STATE_NORMAL]);
711
712 GdkColor toolbar_color = window_style->bg[GTK_STATE_NORMAL];
713 SetThemeColorFromGtk(ThemeService::COLOR_TOOLBAR, &toolbar_color);
714
715 GdkColor button_color = window_style->bg[GTK_STATE_SELECTED];
716 SetThemeTintFromGtk(ThemeService::TINT_BUTTONS, &button_color);
717
718 GtkStyle* label_style = gtk_rc_get_style(fake_label_.get());
719 GdkColor label_color = label_style->fg[GTK_STATE_NORMAL];
720 SetThemeColorFromGtk(ThemeService::COLOR_TAB_TEXT, &label_color);
721 SetThemeColorFromGtk(ThemeService::COLOR_BOOKMARK_TEXT, &label_color);
722
723 // Build the various icon tints.
724 GetNormalButtonTintHSL(&button_tint_);
725 GetNormalEntryForegroundHSL(&entry_tint_);
726 GetSelectedEntryForegroundHSL(&selected_entry_tint_);
727 GdkColor frame_color = BuildFrameColors(frame_style);
728
729 // The inactive frame color never occurs naturally in the theme, as it is a
730 // tinted version of |frame_color|. We generate another color based on the
731 // background tab color, with the lightness and saturation moved in the
732 // opposite direction. (We don't touch the hue, since there should be subtle
733 // hints of the color in the text.)
734 color_utils::HSL inactive_tab_text_hsl = tints_[TINT_BACKGROUND_TAB];
735 if (inactive_tab_text_hsl.l < 0.5)
736 inactive_tab_text_hsl.l = kDarkInactiveLuminance;
737 else
738 inactive_tab_text_hsl.l = kLightInactiveLuminance;
739
740 if (inactive_tab_text_hsl.s < 0.5)
741 inactive_tab_text_hsl.s = kHeavyInactiveSaturation;
742 else
743 inactive_tab_text_hsl.s = kLightInactiveSaturation;
744
745 colors_[ThemeService::COLOR_BACKGROUND_TAB_TEXT] =
746 color_utils::HSLToSkColor(inactive_tab_text_hsl, 255);
747
748 // We pick the text and background colors for the NTP out of the colors for a
749 // GtkEntry. We do this because GtkEntries background color is never the same
750 // as |toolbar_color|, is usually a white, and when it isn't a white,
751 // provides sufficient contrast to |toolbar_color|. Try this out with
752 // Darklooks, HighContrastInverse or ThinIce.
753 GtkStyle* entry_style = gtk_rc_get_style(fake_entry_.get());
754 GdkColor ntp_background = entry_style->base[GTK_STATE_NORMAL];
755 GdkColor ntp_foreground = entry_style->text[GTK_STATE_NORMAL];
756 SetThemeColorFromGtk(ThemeService::COLOR_NTP_BACKGROUND,
757 &ntp_background);
758 SetThemeColorFromGtk(ThemeService::COLOR_NTP_TEXT,
759 &ntp_foreground);
760
761 // The NTP header is the color that surrounds the current active thumbnail on
762 // the NTP, and acts as the border of the "Recent Links" box. It would be
763 // awesome if they were separated so we could use GetBorderColor() for the
764 // border around the "Recent Links" section, but matching the frame color is
765 // more important.
766 SetThemeColorFromGtk(ThemeService::COLOR_NTP_HEADER,
767 &frame_color);
768 SetThemeColorFromGtk(ThemeService::COLOR_NTP_SECTION,
769 &toolbar_color);
770 SetThemeColorFromGtk(ThemeService::COLOR_NTP_SECTION_TEXT,
771 &label_color);
772
773 // Override the link color if the theme provides it.
774 const GdkColor* link_color = NULL;
775 gtk_widget_style_get(GTK_WIDGET(fake_window_),
776 "link-color", &link_color, NULL);
777 if (!link_color)
778 link_color = &kDefaultLinkColor;
779
780 SetThemeColorFromGtk(ThemeService::COLOR_NTP_LINK,
781 link_color);
782 SetThemeColorFromGtk(ThemeService::COLOR_NTP_LINK_UNDERLINE,
783 link_color);
784 SetThemeColorFromGtk(ThemeService::COLOR_NTP_SECTION_LINK,
785 link_color);
786 SetThemeColorFromGtk(ThemeService::COLOR_NTP_SECTION_LINK_UNDERLINE,
787 link_color);
788
789 // Generate the colors that we pass to WebKit.
790 focus_ring_color_ = gfx::GdkColorToSkColor(frame_color);
791 GdkColor thumb_active_color, thumb_inactive_color, track_color;
792 GtkThemeService::GetScrollbarColors(&thumb_active_color,
793 &thumb_inactive_color,
794 &track_color);
795 thumb_active_color_ = gfx::GdkColorToSkColor(thumb_active_color);
796 thumb_inactive_color_ = gfx::GdkColorToSkColor(thumb_inactive_color);
797 track_color_ = gfx::GdkColorToSkColor(track_color);
798
799 // Some GTK themes only define the text selection colors on the GtkEntry
800 // class, so we need to use that for getting selection colors.
801 active_selection_bg_color_ =
802 gfx::GdkColorToSkColor(entry_style->base[GTK_STATE_SELECTED]);
803 active_selection_fg_color_ =
804 gfx::GdkColorToSkColor(entry_style->text[GTK_STATE_SELECTED]);
805 inactive_selection_bg_color_ =
806 gfx::GdkColorToSkColor(entry_style->base[GTK_STATE_ACTIVE]);
807 inactive_selection_fg_color_ =
808 gfx::GdkColorToSkColor(entry_style->text[GTK_STATE_ACTIVE]);
809 }
810
811 GdkColor GtkThemeService::BuildFrameColors(GtkStyle* frame_style) {
812 const GdkColor* theme_frame = NULL;
813 const GdkColor* theme_inactive_frame = NULL;
814 const GdkColor* theme_incognito_frame = NULL;
815 const GdkColor* theme_incognito_inactive_frame = NULL;
816 gtk_widget_style_get(GTK_WIDGET(fake_frame_),
817 "frame-color", &theme_frame,
818 "inactive-frame-color", &theme_inactive_frame,
819 "incognito-frame-color", &theme_incognito_frame,
820 "incognito-inactive-frame-color",
821 &theme_incognito_inactive_frame,
822 NULL);
823
824 GdkColor frame_color = BuildAndSetFrameColor(
825 &frame_style->bg[GTK_STATE_SELECTED],
826 theme_frame,
827 kDefaultFrameShift,
828 ThemeService::COLOR_FRAME,
829 ThemeService::TINT_FRAME);
830 SetThemeTintFromGtk(ThemeService::TINT_BACKGROUND_TAB, &frame_color);
831
832 BuildAndSetFrameColor(
833 &frame_style->bg[GTK_STATE_INSENSITIVE],
834 theme_inactive_frame,
835 kDefaultFrameShift,
836 ThemeService::COLOR_FRAME_INACTIVE,
837 ThemeService::TINT_FRAME_INACTIVE);
838
839 BuildAndSetFrameColor(
840 &frame_color,
841 theme_incognito_frame,
842 GetDefaultTint(ThemeService::TINT_FRAME_INCOGNITO),
843 ThemeService::COLOR_FRAME_INCOGNITO,
844 ThemeService::TINT_FRAME_INCOGNITO);
845
846 BuildAndSetFrameColor(
847 &frame_color,
848 theme_incognito_inactive_frame,
849 GetDefaultTint(ThemeService::TINT_FRAME_INCOGNITO_INACTIVE),
850 ThemeService::COLOR_FRAME_INCOGNITO_INACTIVE,
851 ThemeService::TINT_FRAME_INCOGNITO_INACTIVE);
852
853 return frame_color;
854 }
855
856 void GtkThemeService::LoadDefaultValues() {
857 focus_ring_color_ = SkColorSetARGB(255, 229, 151, 0);
858 thumb_active_color_ = SkColorSetRGB(244, 244, 244);
859 thumb_inactive_color_ = SkColorSetRGB(234, 234, 234);
860 track_color_ = SkColorSetRGB(211, 211, 211);
861
862 active_selection_bg_color_ = SkColorSetRGB(30, 144, 255);
863 active_selection_fg_color_ = SK_ColorWHITE;
864 inactive_selection_bg_color_ = SkColorSetRGB(200, 200, 200);
865 inactive_selection_fg_color_ = SkColorSetRGB(50, 50, 50);
866 }
867
868 void GtkThemeService::RebuildMenuIconSets() {
869 FreeIconSets();
870
871 GtkStyle* style = gtk_rc_get_style(fake_menu_item_.get());
872
873 fullscreen_icon_set_ = gtk_icon_set_new();
874 BuildIconFromIDRWithColor(IDR_FULLSCREEN_MENU_BUTTON,
875 style,
876 GTK_STATE_PRELIGHT,
877 fullscreen_icon_set_);
878 BuildIconFromIDRWithColor(IDR_FULLSCREEN_MENU_BUTTON,
879 style,
880 GTK_STATE_NORMAL,
881 fullscreen_icon_set_);
882 }
883
884 void GtkThemeService::SetThemeColorFromGtk(int id, const GdkColor* color) {
885 colors_[id] = gfx::GdkColorToSkColor(*color);
886 }
887
888 void GtkThemeService::SetThemeTintFromGtk(int id, const GdkColor* color) {
889 color_utils::HSL default_tint = GetDefaultTint(id);
890 color_utils::HSL hsl;
891 color_utils::SkColorToHSL(gfx::GdkColorToSkColor(*color), &hsl);
892
893 if (default_tint.s != -1)
894 hsl.s = default_tint.s;
895
896 if (default_tint.l != -1)
897 hsl.l = default_tint.l;
898
899 tints_[id] = hsl;
900 }
901
902 GdkColor GtkThemeService::BuildAndSetFrameColor(const GdkColor* base,
903 const GdkColor* gtk_base,
904 const color_utils::HSL& tint,
905 int color_id,
906 int tint_id) {
907 GdkColor out_color = *base;
908 if (gtk_base) {
909 // The theme author specified a color to use, use it without modification.
910 out_color = *gtk_base;
911 } else {
912 // Tint the basic color since this is a heuristic color instead of one
913 // specified by the theme author.
914 GdkColorHSLShift(tint, &out_color);
915 }
916 SetThemeColorFromGtk(color_id, &out_color);
917 SetThemeTintFromGtk(tint_id, &out_color);
918
919 return out_color;
920 }
921
922 void GtkThemeService::FreeIconSets() {
923 if (fullscreen_icon_set_) {
924 gtk_icon_set_unref(fullscreen_icon_set_);
925 fullscreen_icon_set_ = NULL;
926 }
927 }
928
929 SkBitmap* GtkThemeService::GenerateGtkThemeBitmap(int id) const {
930 switch (id) {
931 case IDR_THEME_TOOLBAR: {
932 GtkStyle* style = gtk_rc_get_style(fake_window_);
933 GdkColor* color = &style->bg[GTK_STATE_NORMAL];
934 SkBitmap* bitmap = new SkBitmap;
935 bitmap->setConfig(SkBitmap::kARGB_8888_Config,
936 kToolbarImageWidth, kToolbarImageHeight);
937 bitmap->allocPixels();
938 bitmap->eraseRGB(color->red >> 8, color->green >> 8, color->blue >> 8);
939 return bitmap;
940 }
941 case IDR_THEME_TAB_BACKGROUND:
942 return GenerateTabImage(IDR_THEME_FRAME);
943 case IDR_THEME_TAB_BACKGROUND_INCOGNITO:
944 return GenerateTabImage(IDR_THEME_FRAME_INCOGNITO);
945 case IDR_THEME_FRAME:
946 return GenerateFrameImage(ThemeService::COLOR_FRAME,
947 "frame-gradient-color");
948 case IDR_THEME_FRAME_INACTIVE:
949 return GenerateFrameImage(ThemeService::COLOR_FRAME_INACTIVE,
950 "inactive-frame-gradient-color");
951 case IDR_THEME_FRAME_INCOGNITO:
952 return GenerateFrameImage(ThemeService::COLOR_FRAME_INCOGNITO,
953 "incognito-frame-gradient-color");
954 case IDR_THEME_FRAME_INCOGNITO_INACTIVE: {
955 return GenerateFrameImage(
956 ThemeService::COLOR_FRAME_INCOGNITO_INACTIVE,
957 "incognito-inactive-frame-gradient-color");
958 }
959 // Icons that sit inside the omnibox shouldn't receive TINT_BUTTONS and
960 // instead should tint based on the foreground text entry color in GTK+
961 // mode because some themes that try to be dark *and* light have very
962 // different colors between the omnibox and the normal background area.
963 case IDR_OMNIBOX_EXTENSION_APP:
964 case IDR_OMNIBOX_HISTORY:
965 case IDR_OMNIBOX_HTTP:
966 case IDR_OMNIBOX_SEARCH:
967 case IDR_OMNIBOX_STAR:
968 case IDR_GEOLOCATION_ALLOWED_LOCATIONBAR_ICON:
969 case IDR_GEOLOCATION_DENIED_LOCATIONBAR_ICON: {
970 return GenerateTintedIcon(id, entry_tint_);
971 }
972 // In GTK mode, the dark versions of the omnibox icons only ever appear in
973 // the autocomplete popup and only against the current theme's GtkEntry
974 // base[GTK_STATE_SELECTED] color, so tint the icons so they won't collide
975 // with the selected color.
976 case IDR_OMNIBOX_EXTENSION_APP_DARK:
977 case IDR_OMNIBOX_HISTORY_DARK:
978 case IDR_OMNIBOX_HTTP_DARK:
979 case IDR_OMNIBOX_SEARCH_DARK:
980 case IDR_OMNIBOX_STAR_DARK: {
981 return GenerateTintedIcon(id, selected_entry_tint_);
982 }
983 default: {
984 return GenerateTintedIcon(id, button_tint_);
985 }
986 }
987 }
988
989 SkBitmap* GtkThemeService::GenerateFrameImage(
990 int color_id,
991 const char* gradient_name) const {
992 // We use two colors: the main color (passed in) and a lightened version of
993 // that color (which is supposed to match the light gradient at the top of
994 // several GTK+ themes, such as Ambiance, Clearlooks or Bluebird).
995 ColorMap::const_iterator it = colors_.find(color_id);
996 DCHECK(it != colors_.end());
997 SkColor base = it->second;
998
999 gfx::CanvasSkia canvas(gfx::Size(kToolbarImageWidth, kToolbarImageHeight),
1000 true);
1001
1002 int gradient_size;
1003 const GdkColor* gradient_top_color = NULL;
1004 gtk_widget_style_get(GTK_WIDGET(fake_frame_),
1005 "frame-gradient-size", &gradient_size,
1006 gradient_name, &gradient_top_color,
1007 NULL);
1008 if (gradient_size) {
1009 SkColor lighter = gradient_top_color ?
1010 gfx::GdkColorToSkColor(*gradient_top_color) :
1011 color_utils::HSLShift(base, kGtkFrameShift);
1012 SkShader* shader = gfx::CreateGradientShader(
1013 0, gradient_size, lighter, base);
1014 SkPaint paint;
1015 paint.setStyle(SkPaint::kFill_Style);
1016 paint.setAntiAlias(true);
1017 paint.setShader(shader);
1018 shader->unref();
1019
1020 canvas.DrawRect(gfx::Rect(0, 0, kToolbarImageWidth, gradient_size), paint);
1021 }
1022
1023 canvas.FillRect(gfx::Rect(0, gradient_size, kToolbarImageWidth,
1024 kToolbarImageHeight - gradient_size), base);
1025 return new SkBitmap(canvas.ExtractBitmap());
1026 }
1027
1028 SkBitmap* GtkThemeService::GenerateTabImage(int base_id) const {
1029 SkBitmap* base_image = GetBitmapNamed(base_id);
1030 SkBitmap bg_tint = SkBitmapOperations::CreateHSLShiftedBitmap(
1031 *base_image, GetTint(ThemeService::TINT_BACKGROUND_TAB));
1032 return new SkBitmap(SkBitmapOperations::CreateTiledBitmap(
1033 bg_tint, 0, 0, bg_tint.width(), bg_tint.height()));
1034 }
1035
1036 SkBitmap* GtkThemeService::GenerateTintedIcon(
1037 int base_id,
1038 const color_utils::HSL& tint) const {
1039 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
1040 return new SkBitmap(SkBitmapOperations::CreateHSLShiftedBitmap(
1041 *rb.GetBitmapNamed(base_id), tint));
1042 }
1043
1044 void GtkThemeService::GetNormalButtonTintHSL(
1045 color_utils::HSL* tint) const {
1046 GtkStyle* window_style = gtk_rc_get_style(fake_window_);
1047 const GdkColor accent_gdk_color = window_style->bg[GTK_STATE_SELECTED];
1048 const GdkColor base_color = window_style->base[GTK_STATE_NORMAL];
1049
1050 GtkStyle* label_style = gtk_rc_get_style(fake_label_.get());
1051 const GdkColor text_color = label_style->fg[GTK_STATE_NORMAL];
1052
1053 PickButtonTintFromColors(accent_gdk_color, text_color, base_color, tint);
1054 }
1055
1056 void GtkThemeService::GetNormalEntryForegroundHSL(
1057 color_utils::HSL* tint) const {
1058 GtkStyle* window_style = gtk_rc_get_style(fake_window_);
1059 const GdkColor accent_gdk_color = window_style->bg[GTK_STATE_SELECTED];
1060
1061 GtkStyle* style = gtk_rc_get_style(fake_entry_.get());
1062 const GdkColor text_color = style->text[GTK_STATE_NORMAL];
1063 const GdkColor base_color = style->base[GTK_STATE_NORMAL];
1064
1065 PickButtonTintFromColors(accent_gdk_color, text_color, base_color, tint);
1066 }
1067
1068 void GtkThemeService::GetSelectedEntryForegroundHSL(
1069 color_utils::HSL* tint) const {
1070 // The simplest of all the tints. We just use the selected text in the entry
1071 // since the icons tinted this way will only be displayed against
1072 // base[GTK_STATE_SELECTED].
1073 GtkStyle* style = gtk_rc_get_style(fake_entry_.get());
1074 const GdkColor color = style->text[GTK_STATE_SELECTED];
1075 color_utils::SkColorToHSL(gfx::GdkColorToSkColor(color), tint);
1076 }
1077
1078 void GtkThemeService::OnDestroyChromeButton(GtkWidget* button) {
1079 std::vector<GtkWidget*>::iterator it =
1080 find(chrome_buttons_.begin(), chrome_buttons_.end(), button);
1081 if (it != chrome_buttons_.end())
1082 chrome_buttons_.erase(it);
1083 }
1084
1085 void GtkThemeService::OnDestroyChromeLinkButton(GtkWidget* button) {
1086 std::vector<GtkWidget*>::iterator it =
1087 find(link_buttons_.begin(), link_buttons_.end(), button);
1088 if (it != link_buttons_.end())
1089 link_buttons_.erase(it);
1090 }
1091
1092 void GtkThemeService::OnDestroyLabel(GtkWidget* button) {
1093 std::map<GtkWidget*, GdkColor>::iterator it = labels_.find(button);
1094 if (it != labels_.end())
1095 labels_.erase(it);
1096 }
1097
1098 gboolean GtkThemeService::OnSeparatorExpose(GtkWidget* widget,
1099 GdkEventExpose* event) {
1100 UNSHIPPED_TRACE_EVENT0("ui::gtk", "GtkThemeService::OnSeparatorExpose");
1101 if (UsingNativeTheme())
1102 return FALSE;
1103
1104 cairo_t* cr = gdk_cairo_create(gtk_widget_get_window(widget));
1105 gdk_cairo_rectangle(cr, &event->area);
1106 cairo_clip(cr);
1107
1108 GdkColor bottom_color = GetGdkColor(ThemeService::COLOR_TOOLBAR);
1109 double bottom_color_rgb[] = {
1110 static_cast<double>(bottom_color.red / 257) / 255.0,
1111 static_cast<double>(bottom_color.green / 257) / 255.0,
1112 static_cast<double>(bottom_color.blue / 257) / 255.0, };
1113
1114 GtkAllocation allocation;
1115 gtk_widget_get_allocation(widget, &allocation);
1116
1117 cairo_pattern_t* pattern =
1118 cairo_pattern_create_linear(allocation.x, allocation.y,
1119 allocation.x,
1120 allocation.y + allocation.height);
1121 cairo_pattern_add_color_stop_rgb(
1122 pattern, 0.0,
1123 kTopSeparatorColor[0], kTopSeparatorColor[1], kTopSeparatorColor[2]);
1124 cairo_pattern_add_color_stop_rgb(
1125 pattern, 0.5,
1126 kMidSeparatorColor[0], kMidSeparatorColor[1], kMidSeparatorColor[2]);
1127 cairo_pattern_add_color_stop_rgb(
1128 pattern, 1.0,
1129 bottom_color_rgb[0], bottom_color_rgb[1], bottom_color_rgb[2]);
1130 cairo_set_source(cr, pattern);
1131
1132 double start_x = 0.5 + allocation.x;
1133 cairo_new_path(cr);
1134 cairo_set_line_width(cr, 1.0);
1135 cairo_move_to(cr, start_x, allocation.y);
1136 cairo_line_to(cr, start_x, allocation.y + allocation.height);
1137 cairo_stroke(cr);
1138 cairo_destroy(cr);
1139 cairo_pattern_destroy(pattern);
1140
1141 return TRUE;
1142 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/gtk/gtk_theme_service.h ('k') | chrome/browser/ui/gtk/gtk_theme_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698