OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/libgtk2ui/gtk2_ui.h" | 5 #include "chrome/browser/ui/libgtk2ui/gtk2_ui.h" |
6 | 6 |
7 #include <math.h> | 7 #include <math.h> |
8 #include <set> | 8 #include <set> |
9 | 9 |
10 #include <pango/pango.h> | 10 #include <pango/pango.h> |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 // Number of app indicators used (used as part of app-indicator id). | 103 // Number of app indicators used (used as part of app-indicator id). |
104 int indicators_count; | 104 int indicators_count; |
105 | 105 |
106 // The unknown content type. | 106 // The unknown content type. |
107 const char* kUnknownContentType = "application/octet-stream"; | 107 const char* kUnknownContentType = "application/octet-stream"; |
108 | 108 |
109 // The size of the rendered toolbar image. | 109 // The size of the rendered toolbar image. |
110 const int kToolbarImageWidth = 64; | 110 const int kToolbarImageWidth = 64; |
111 const int kToolbarImageHeight = 128; | 111 const int kToolbarImageHeight = 128; |
112 | 112 |
113 // How much to tint the GTK+ color lighter at the top of the window. | 113 const color_utils::HSL kGtkFrameShift = { -1, -1, 0.8 }; |
114 const color_utils::HSL kGtkFrameShift = { -1, -1, 0.58 }; | |
115 | |
116 // How much to tint the GTK+ color when an explicit frame color hasn't been | |
117 // specified. | |
118 const color_utils::HSL kDefaultFrameShift = { -1, -1, 0.4 }; | |
119 | 114 |
120 // Values used as the new luminance and saturation values in the inactive tab | 115 // Values used as the new luminance and saturation values in the inactive tab |
121 // text color. | 116 // text color. |
122 const double kDarkInactiveLuminance = 0.85; | 117 const double kDarkInactiveLuminance = 0.85; |
123 const double kLightInactiveLuminance = 0.15; | 118 const double kLightInactiveLuminance = 0.15; |
124 const double kHeavyInactiveSaturation = 0.7; | 119 const double kHeavyInactiveSaturation = 0.7; |
125 const double kLightInactiveSaturation = 0.3; | 120 const double kLightInactiveSaturation = 0.3; |
126 | 121 |
127 // Default color for links on the NTP when the GTK+ theme doesn't define a | |
128 // link color. Constant taken from gtklinkbutton.c. | |
129 const GdkColor kDefaultLinkColor = { 0, 0, 0, 0xeeee }; | |
130 | |
131 const int kSkiaToGDKMultiplier = 257; | |
132 | |
133 // TODO(erg): ThemeService has a whole interface just for reading default | 122 // TODO(erg): ThemeService has a whole interface just for reading default |
134 // constants. Figure out what to do with that more long term; for now, just | 123 // constants. Figure out what to do with that more long term; for now, just |
135 // copy the constants themselves here. | 124 // copy the constants themselves here. |
136 // | 125 // |
137 // Default tints. | 126 // Default tints. |
138 const color_utils::HSL kDefaultTintButtons = { -1, -1, -1 }; | 127 const color_utils::HSL kDefaultTintButtons = { -1, -1, -1 }; |
139 const color_utils::HSL kDefaultTintFrame = { -1, -1, -1 }; | 128 const color_utils::HSL kDefaultTintFrame = { -1, -1, -1 }; |
140 const color_utils::HSL kDefaultTintFrameInactive = { -1, -1, 0.75f }; | 129 const color_utils::HSL kDefaultTintFrameInactive = { -1, -1, 0.75f }; |
141 const color_utils::HSL kDefaultTintFrameIncognito = { -1, 0.2f, 0.35f }; | 130 const color_utils::HSL kDefaultTintFrameIncognito = { -1, 0.2f, 0.35f }; |
142 const color_utils::HSL kDefaultTintFrameIncognitoInactive = { -1, 0.3f, 0.6f }; | 131 const color_utils::HSL kDefaultTintFrameIncognitoInactive = { -1, 0.3f, 0.6f }; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 IDR_OMNIBOX_STAR, | 166 IDR_OMNIBOX_STAR, |
178 IDR_OMNIBOX_STAR_DARK, | 167 IDR_OMNIBOX_STAR_DARK, |
179 IDR_OMNIBOX_TTS, | 168 IDR_OMNIBOX_TTS, |
180 IDR_OMNIBOX_TTS_DARK, | 169 IDR_OMNIBOX_TTS_DARK, |
181 }; | 170 }; |
182 | 171 |
183 // This table converts button ids into a pair of gtk-stock id and state. | 172 // This table converts button ids into a pair of gtk-stock id and state. |
184 struct IDRGtkMapping { | 173 struct IDRGtkMapping { |
185 int idr; | 174 int idr; |
186 const char* stock_id; | 175 const char* stock_id; |
187 GtkStateType gtk_state; | 176 bool enabled; |
188 } const kGtkIcons[] = { | 177 } const kGtkIcons[] = { |
189 { IDR_BACK, GTK_STOCK_GO_BACK, GTK_STATE_NORMAL }, | 178 { IDR_BACK, GTK_STOCK_GO_BACK, true }, |
190 { IDR_BACK_D, GTK_STOCK_GO_BACK, GTK_STATE_INSENSITIVE }, | 179 { IDR_BACK_D, GTK_STOCK_GO_BACK, false }, |
191 | 180 |
192 { IDR_FORWARD, GTK_STOCK_GO_FORWARD, GTK_STATE_NORMAL }, | 181 { IDR_FORWARD, GTK_STOCK_GO_FORWARD, true }, |
193 { IDR_FORWARD_D, GTK_STOCK_GO_FORWARD, GTK_STATE_INSENSITIVE }, | 182 { IDR_FORWARD_D, GTK_STOCK_GO_FORWARD, false }, |
194 | 183 |
195 { IDR_HOME, GTK_STOCK_HOME, GTK_STATE_NORMAL }, | 184 { IDR_HOME, GTK_STOCK_HOME, true }, |
196 | 185 |
197 { IDR_RELOAD, GTK_STOCK_REFRESH, GTK_STATE_NORMAL }, | 186 { IDR_RELOAD, GTK_STOCK_REFRESH, true }, |
198 { IDR_RELOAD_D, GTK_STOCK_REFRESH, GTK_STATE_INSENSITIVE }, | 187 { IDR_RELOAD_D, GTK_STOCK_REFRESH, false }, |
199 | 188 |
200 { IDR_STOP, GTK_STOCK_STOP, GTK_STATE_NORMAL }, | 189 { IDR_STOP, GTK_STOCK_STOP, true }, |
201 { IDR_STOP_D, GTK_STOCK_STOP, GTK_STATE_INSENSITIVE }, | 190 { IDR_STOP_D, GTK_STOCK_STOP, false }, |
202 }; | 191 }; |
203 | 192 |
204 // The image resources that will be tinted by the 'button' tint value. | 193 // The image resources that will be tinted by the 'button' tint value. |
205 const int kOtherToolbarButtonIDs[] = { | 194 const int kOtherToolbarButtonIDs[] = { |
206 IDR_TOOLBAR_BEZEL_HOVER, | 195 IDR_TOOLBAR_BEZEL_HOVER, |
207 IDR_TOOLBAR_BEZEL_PRESSED, | 196 IDR_TOOLBAR_BEZEL_PRESSED, |
208 IDR_BROWSER_ACTIONS_OVERFLOW, | 197 IDR_BROWSER_ACTIONS_OVERFLOW, |
209 | 198 |
210 // TODO(erg): The dropdown arrow should be tinted because we're injecting | 199 // TODO(erg): The dropdown arrow should be tinted because we're injecting |
211 // various background GTK colors, but the code that accesses them needs to be | 200 // various background GTK colors, but the code that accesses them needs to be |
(...skipping 14 matching lines...) Expand all Loading... |
226 images.insert(kGtkIcons[i].idr); | 215 images.insert(kGtkIcons[i].idr); |
227 | 216 |
228 images.insert(kOtherToolbarButtonIDs, | 217 images.insert(kOtherToolbarButtonIDs, |
229 kOtherToolbarButtonIDs + arraysize(kOtherToolbarButtonIDs)); | 218 kOtherToolbarButtonIDs + arraysize(kOtherToolbarButtonIDs)); |
230 } | 219 } |
231 | 220 |
232 return images.count(id) > 0; | 221 return images.count(id) > 0; |
233 } | 222 } |
234 | 223 |
235 // Picks a button tint from a set of background colors. While | 224 // Picks a button tint from a set of background colors. While |
236 // |accent_gdk_color| will usually be the same color through a theme, this | 225 // |accent_color| will usually be the same color through a theme, this |
237 // function will get called with the normal GtkLabel |text_color|/GtkWindow | 226 // function will get called with the normal GtkLabel |text_color|/GtkWindow |
238 // |background_color| pair and the GtkEntry |text_color|/|background_color| | 227 // |background_color| pair and the GtkEntry |text_color|/|background_color| |
239 // pair. While 3/4 of the time the resulting tint will be the same, themes that | 228 // pair. While 3/4 of the time the resulting tint will be the same, themes that |
240 // have a dark window background (with light text) and a light text entry (with | 229 // have a dark window background (with light text) and a light text entry (with |
241 // dark text) will get better icons with this separated out. | 230 // dark text) will get better icons with this separated out. |
242 void PickButtonTintFromColors(const GdkColor& accent_gdk_color, | 231 void PickButtonTintFromColors(SkColor accent_color, |
243 const GdkColor& text_color, | 232 SkColor text_color, |
244 const GdkColor& background_color, | 233 SkColor background_color, |
245 color_utils::HSL* tint) { | 234 color_utils::HSL* tint) { |
246 SkColor accent_color = GdkColorToSkColor(accent_gdk_color); | 235 color_utils::HSL accent_tint, text_tint, background_tint; |
247 color_utils::HSL accent_tint; | |
248 color_utils::SkColorToHSL(accent_color, &accent_tint); | 236 color_utils::SkColorToHSL(accent_color, &accent_tint); |
249 | 237 color_utils::SkColorToHSL(text_color, &text_tint); |
250 color_utils::HSL text_tint; | 238 color_utils::SkColorToHSL(background_color, &background_tint); |
251 color_utils::SkColorToHSL(GdkColorToSkColor(text_color), | |
252 &text_tint); | |
253 | |
254 color_utils::HSL background_tint; | |
255 color_utils::SkColorToHSL(GdkColorToSkColor(background_color), | |
256 &background_tint); | |
257 | 239 |
258 // If the accent color is gray, then our normal HSL tomfoolery will bring out | 240 // If the accent color is gray, then our normal HSL tomfoolery will bring out |
259 // whatever color is oddly dominant (for example, in rgb space [125, 128, | 241 // whatever color is oddly dominant (for example, in rgb space [125, 128, |
260 // 125] will tint green instead of gray). Slight differences (+/-10 (4%) to | 242 // 125] will tint green instead of gray). Slight differences (+/-10 (4%) to |
261 // all color components) should be interpreted as this color being gray and | 243 // all color components) should be interpreted as this color being gray and |
262 // we should switch into a special grayscale mode. | 244 // we should switch into a special grayscale mode. |
263 int rb_diff = abs(static_cast<int>(SkColorGetR(accent_color)) - | 245 int rb_diff = abs(static_cast<int>(SkColorGetR(accent_color)) - |
264 static_cast<int>(SkColorGetB(accent_color))); | 246 static_cast<int>(SkColorGetB(accent_color))); |
265 int rg_diff = abs(static_cast<int>(SkColorGetR(accent_color)) - | 247 int rg_diff = abs(static_cast<int>(SkColorGetR(accent_color)) - |
266 static_cast<int>(SkColorGetG(accent_color))); | 248 static_cast<int>(SkColorGetG(accent_color))); |
(...skipping 26 matching lines...) Expand all Loading... |
293 // white. | 275 // white. |
294 if (text_tint.l < 0.5) | 276 if (text_tint.l < 0.5) |
295 tint->l = -1; | 277 tint->l = -1; |
296 else if (text_tint.l <= 0.9) | 278 else if (text_tint.l <= 0.9) |
297 tint->l = text_tint.l; | 279 tint->l = text_tint.l; |
298 else | 280 else |
299 tint->l = 0.9; | 281 tint->l = 0.9; |
300 } | 282 } |
301 } | 283 } |
302 | 284 |
303 // Applies an HSL shift to a GdkColor (instead of an SkColor) | |
304 void GdkColorHSLShift(const color_utils::HSL& shift, GdkColor* frame_color) { | |
305 SkColor shifted = color_utils::HSLShift( | |
306 GdkColorToSkColor(*frame_color), shift); | |
307 | |
308 frame_color->pixel = 0; | |
309 frame_color->red = SkColorGetR(shifted) * kSkiaToGDKMultiplier; | |
310 frame_color->green = SkColorGetG(shifted) * kSkiaToGDKMultiplier; | |
311 frame_color->blue = SkColorGetB(shifted) * kSkiaToGDKMultiplier; | |
312 } | |
313 | |
314 // Copied Default blah sections from ThemeService. | 285 // Copied Default blah sections from ThemeService. |
315 color_utils::HSL GetDefaultTint(int id) { | 286 color_utils::HSL GetDefaultTint(int id) { |
316 switch (id) { | 287 switch (id) { |
317 case ThemeProperties::TINT_FRAME: | 288 case ThemeProperties::TINT_FRAME: |
318 return kDefaultTintFrame; | 289 return kDefaultTintFrame; |
319 case ThemeProperties::TINT_FRAME_INACTIVE: | 290 case ThemeProperties::TINT_FRAME_INACTIVE: |
320 return kDefaultTintFrameInactive; | 291 return kDefaultTintFrameInactive; |
321 case ThemeProperties::TINT_FRAME_INCOGNITO: | 292 case ThemeProperties::TINT_FRAME_INCOGNITO: |
322 return kDefaultTintFrameIncognito; | 293 return kDefaultTintFrameIncognito; |
323 case ThemeProperties::TINT_FRAME_INCOGNITO_INACTIVE: | 294 case ThemeProperties::TINT_FRAME_INCOGNITO_INACTIVE: |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 : default_font_size_pixels_(0), | 420 : default_font_size_pixels_(0), |
450 default_font_style_(gfx::Font::NORMAL), | 421 default_font_style_(gfx::Font::NORMAL), |
451 middle_click_action_(GetDefaultMiddleClickAction()), | 422 middle_click_action_(GetDefaultMiddleClickAction()), |
452 device_scale_factor_(1.0) { | 423 device_scale_factor_(1.0) { |
453 GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess()); | 424 GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess()); |
454 } | 425 } |
455 | 426 |
456 void Gtk2UI::Initialize() { | 427 void Gtk2UI::Initialize() { |
457 signals_.reset(new Gtk2SignalRegistrar); | 428 signals_.reset(new Gtk2SignalRegistrar); |
458 | 429 |
459 // Create our fake widgets. | 430 // Create fake frame. |
460 fake_window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
461 fake_frame_ = chrome_gtk_frame_new(); | 431 fake_frame_ = chrome_gtk_frame_new(); |
462 fake_label_.Own(gtk_label_new("")); | |
463 fake_entry_.Own(gtk_entry_new()); | |
464 | 432 |
465 // Only realized widgets receive style-set notifications, which we need to | 433 // Only realized widgets receive style-set notifications, which we need to |
466 // broadcast new theme images and colors. Only realized widgets have style | 434 // broadcast new theme images and colors. Only realized widgets have style |
467 // properties, too, which we query for some colors. | 435 // properties, too, which we query for some colors. |
468 gtk_widget_realize(fake_frame_); | 436 gtk_widget_realize(fake_frame_); |
469 gtk_widget_realize(fake_window_); | |
470 | |
471 signals_->Connect(fake_frame_, "style-set", | 437 signals_->Connect(fake_frame_, "style-set", |
472 G_CALLBACK(&OnStyleSetThunk), this); | 438 G_CALLBACK(&OnStyleSetThunk), this); |
473 | 439 |
474 LoadGtkValues(); | 440 LoadGtkValues(); |
475 | 441 |
476 printing::PrintingContextLinux::SetCreatePrintDialogFunction( | 442 printing::PrintingContextLinux::SetCreatePrintDialogFunction( |
477 &PrintDialogGtk2::CreatePrintDialog); | 443 &PrintDialogGtk2::CreatePrintDialog); |
478 printing::PrintingContextLinux::SetPdfPaperSizeFunction( | 444 printing::PrintingContextLinux::SetPdfPaperSizeFunction( |
479 &GetPdfPaperSizeDeviceUnitsGtk); | 445 &GetPdfPaperSizeDeviceUnitsGtk); |
480 | 446 |
481 #if defined(USE_GCONF) | 447 #if defined(USE_GCONF) |
482 // We must build this after GTK gets initialized. | 448 // We must build this after GTK gets initialized. |
483 gconf_listener_.reset(new GConfListener(this)); | 449 gconf_listener_.reset(new GConfListener(this)); |
484 #endif // defined(USE_GCONF) | 450 #endif // defined(USE_GCONF) |
485 | 451 |
486 indicators_count = 0; | 452 indicators_count = 0; |
487 | 453 |
488 // Instantiate the singleton instance of Gtk2EventLoop. | 454 // Instantiate the singleton instance of Gtk2EventLoop. |
489 Gtk2EventLoop::GetInstance(); | 455 Gtk2EventLoop::GetInstance(); |
490 } | 456 } |
491 | 457 |
492 Gtk2UI::~Gtk2UI() { | 458 Gtk2UI::~Gtk2UI() { |
493 gtk_widget_destroy(fake_window_); | |
494 gtk_widget_destroy(fake_frame_); | 459 gtk_widget_destroy(fake_frame_); |
495 fake_label_.Destroy(); | |
496 fake_entry_.Destroy(); | |
497 | |
498 ClearAllThemeData(); | 460 ClearAllThemeData(); |
499 } | 461 } |
500 | 462 |
501 gfx::Image Gtk2UI::GetThemeImageNamed(int id) const { | 463 gfx::Image Gtk2UI::GetThemeImageNamed(int id) const { |
502 // Try to get our cached version: | 464 // Try to get our cached version: |
503 ImageCache::const_iterator it = gtk_images_.find(id); | 465 ImageCache::const_iterator it = gtk_images_.find(id); |
504 if (it != gtk_images_.end()) | 466 if (it != gtk_images_.end()) |
505 return it->second; | 467 return it->second; |
506 | 468 |
507 if (IsOverridableImage(id)) { | 469 if (IsOverridableImage(id)) { |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
759 | 721 |
760 bool Gtk2UI::MatchEvent(const ui::Event& event, | 722 bool Gtk2UI::MatchEvent(const ui::Event& event, |
761 std::vector<ui::TextEditCommandAuraLinux>* commands) { | 723 std::vector<ui::TextEditCommandAuraLinux>* commands) { |
762 // Ensure that we have a keyboard handler. | 724 // Ensure that we have a keyboard handler. |
763 if (!key_bindings_handler_) | 725 if (!key_bindings_handler_) |
764 key_bindings_handler_.reset(new Gtk2KeyBindingsHandler); | 726 key_bindings_handler_.reset(new Gtk2KeyBindingsHandler); |
765 | 727 |
766 return key_bindings_handler_->MatchEvent(event, commands); | 728 return key_bindings_handler_->MatchEvent(event, commands); |
767 } | 729 } |
768 | 730 |
769 void Gtk2UI::GetScrollbarColors(GdkColor* thumb_active_color, | 731 void Gtk2UI::SetScrollbarColors() { |
770 GdkColor* thumb_inactive_color, | |
771 GdkColor* track_color) { | |
772 GdkColor* theme_thumb_active = NULL; | 732 GdkColor* theme_thumb_active = NULL; |
773 GdkColor* theme_thumb_inactive = NULL; | 733 GdkColor* theme_thumb_inactive = NULL; |
774 GdkColor* theme_trough_color = NULL; | 734 GdkColor* theme_trough_color = NULL; |
775 gtk_widget_style_get(GTK_WIDGET(fake_frame_), | 735 gtk_widget_style_get(GTK_WIDGET(fake_frame_), |
776 "scrollbar-slider-prelight-color", &theme_thumb_active, | 736 "scrollbar-slider-prelight-color", &theme_thumb_active, |
777 "scrollbar-slider-normal-color", &theme_thumb_inactive, | 737 "scrollbar-slider-normal-color", &theme_thumb_inactive, |
778 "scrollbar-trough-color", &theme_trough_color, | 738 "scrollbar-trough-color", &theme_trough_color, |
779 NULL); | 739 NULL); |
780 | 740 |
781 // Ask the theme if the theme specifies all the scrollbar colors and short | 741 // Ask the theme if the theme specifies all the scrollbar colors and short |
782 // circuit the expensive painting/compositing if we have all of them. | 742 // circuit the expensive painting/compositing if we have all of them. |
783 if (theme_thumb_active && theme_thumb_inactive && theme_trough_color) { | 743 if (theme_thumb_active && theme_thumb_inactive && theme_trough_color) { |
784 *thumb_active_color = *theme_thumb_active; | 744 thumb_active_color_ = GdkColorToSkColor(*theme_thumb_active); |
785 *thumb_inactive_color = *theme_thumb_inactive; | 745 thumb_inactive_color_ = GdkColorToSkColor(*theme_thumb_inactive); |
786 *track_color = *theme_trough_color; | 746 track_color_ = GdkColorToSkColor(*theme_trough_color); |
787 | 747 |
788 gdk_color_free(theme_thumb_active); | 748 gdk_color_free(theme_thumb_active); |
789 gdk_color_free(theme_thumb_inactive); | 749 gdk_color_free(theme_thumb_inactive); |
790 gdk_color_free(theme_trough_color); | 750 gdk_color_free(theme_trough_color); |
791 return; | 751 return; |
792 } | 752 } |
793 | |
794 // Create window containing scrollbar elements | |
795 GtkWidget* window = gtk_window_new(GTK_WINDOW_POPUP); | |
796 GtkWidget* fixed = gtk_fixed_new(); | |
797 GtkWidget* scrollbar = gtk_hscrollbar_new(NULL); | |
798 gtk_container_add(GTK_CONTAINER(window), fixed); | |
799 gtk_container_add(GTK_CONTAINER(fixed), scrollbar); | |
800 gtk_widget_realize(window); | |
801 gtk_widget_realize(scrollbar); | |
802 | |
803 // Draw scrollbar thumb part and track into offscreen image | |
804 const int kWidth = 100; | |
805 const int kHeight = 20; | |
806 GtkStyle* style = gtk_rc_get_style(scrollbar); | |
807 GdkWindow* gdk_window = gtk_widget_get_window(window); | |
808 GdkPixmap* pm = gdk_pixmap_new(gdk_window, kWidth, kHeight, -1); | |
809 GdkRectangle rect = { 0, 0, kWidth, kHeight }; | |
810 unsigned char data[3 * kWidth * kHeight]; | |
811 for (int i = 0; i < 3; ++i) { | |
812 if (i < 2) { | |
813 // Thumb part | |
814 gtk_paint_slider(style, pm, | |
815 i == 0 ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL, | |
816 GTK_SHADOW_OUT, &rect, scrollbar, "slider", 0, 0, | |
817 kWidth, kHeight, GTK_ORIENTATION_HORIZONTAL); | |
818 } else { | |
819 // Track | |
820 gtk_paint_box(style, pm, GTK_STATE_ACTIVE, GTK_SHADOW_IN, &rect, | |
821 scrollbar, "trough-upper", 0, 0, kWidth, kHeight); | |
822 } | |
823 GdkPixbuf* pb = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, | |
824 FALSE, 8, kWidth, kHeight, | |
825 3 * kWidth, 0, 0); | |
826 gdk_pixbuf_get_from_drawable(pb, pm, NULL, 0, 0, 0, 0, kWidth, kHeight); | |
827 | |
828 // Sample pixels | |
829 int components[3] = { 0 }; | |
830 for (int y = 2; y < kHeight - 2; ++y) { | |
831 for (int c = 0; c < 3; ++c) { | |
832 // Sample a vertical slice of pixels at about one-thirds from the | |
833 // left edge. This allows us to avoid any fixed graphics that might be | |
834 // located at the edges or in the center of the scrollbar. | |
835 // Each pixel is made up of a red, green, and blue component; taking up | |
836 // a total of three bytes. | |
837 components[c] += data[3 * (kWidth / 3 + y * kWidth) + c]; | |
838 } | |
839 } | |
840 GdkColor* color = i == 0 ? thumb_active_color : | |
841 i == 1 ? thumb_inactive_color : | |
842 track_color; | |
843 color->pixel = 0; | |
844 // We sampled pixels across the full height of the image, ignoring a two | |
845 // pixel border. In some themes, the border has a completely different | |
846 // color which we do not want to factor into our average color computation. | |
847 // | |
848 // We now need to scale the colors from the 0..255 range, to the wider | |
849 // 0..65535 range, and we need to actually compute the average color; so, | |
850 // we divide by the total number of pixels in the sample. | |
851 color->red = components[0] * 65535 / (255 * (kHeight - 4)); | |
852 color->green = components[1] * 65535 / (255 * (kHeight - 4)); | |
853 color->blue = components[2] * 65535 / (255 * (kHeight - 4)); | |
854 | |
855 g_object_unref(pb); | |
856 } | |
857 g_object_unref(pm); | |
858 | |
859 gtk_widget_destroy(window); | |
860 | |
861 // Override any of the default colors with ones that were specified by the | |
862 // theme. | |
863 if (theme_thumb_active) { | |
864 *thumb_active_color = *theme_thumb_active; | |
865 gdk_color_free(theme_thumb_active); | |
866 } | |
867 | |
868 if (theme_thumb_inactive) { | |
869 *thumb_inactive_color = *theme_thumb_inactive; | |
870 gdk_color_free(theme_thumb_inactive); | |
871 } | |
872 | |
873 if (theme_trough_color) { | |
874 *track_color = *theme_trough_color; | |
875 gdk_color_free(theme_trough_color); | |
876 } | |
877 } | 753 } |
878 | 754 |
879 void Gtk2UI::LoadGtkValues() { | 755 void Gtk2UI::LoadGtkValues() { |
880 // TODO(erg): GtkThemeService had a comment here about having to muck with | 756 // TODO(erg): GtkThemeService had a comment here about having to muck with |
881 // the raw Prefs object to remove prefs::kCurrentThemeImages or else we'd | 757 // the raw Prefs object to remove prefs::kCurrentThemeImages or else we'd |
882 // regress startup time. Figure out how to do that when we can't access the | 758 // regress startup time. Figure out how to do that when we can't access the |
883 // prefs system from here. | 759 // prefs system from here. |
884 | 760 |
885 GtkStyle* frame_style = gtk_rc_get_style(fake_frame_); | 761 SkColor toolbar_color = |
| 762 GET_BG_COLOR(NativeThemeGtk2::instance()->GetWindow(), NORMAL); |
| 763 SkColor button_color = |
| 764 GET_BG_COLOR(NativeThemeGtk2::instance()->GetWindow(), SELECTED); |
| 765 SkColor label_color = |
| 766 GET_FG_COLOR(NativeThemeGtk2::instance()->GetWindow(), NORMAL); |
886 | 767 |
887 GtkStyle* window_style = gtk_rc_get_style(fake_window_); | 768 colors_[ThemeProperties::COLOR_CONTROL_BACKGROUND] = toolbar_color; |
888 SetThemeColorFromGtk(ThemeProperties::COLOR_CONTROL_BACKGROUND, | 769 colors_[ThemeProperties::COLOR_TOOLBAR] = toolbar_color; |
889 &window_style->bg[GTK_STATE_NORMAL]); | |
890 | 770 |
891 GdkColor toolbar_color = window_style->bg[GTK_STATE_NORMAL]; | 771 SetThemeTint(ThemeProperties::TINT_BUTTONS, button_color); |
892 SetThemeColorFromGtk(ThemeProperties::COLOR_TOOLBAR, &toolbar_color); | |
893 | 772 |
894 GdkColor button_color = window_style->bg[GTK_STATE_SELECTED]; | 773 colors_[ThemeProperties::COLOR_TAB_TEXT] = label_color; |
895 SetThemeTintFromGtk(ThemeProperties::TINT_BUTTONS, &button_color); | 774 colors_[ThemeProperties::COLOR_BOOKMARK_TEXT] = label_color; |
| 775 colors_[ThemeProperties::COLOR_STATUS_BAR_TEXT] = label_color; |
896 | 776 |
897 GtkStyle* label_style = gtk_rc_get_style(fake_label_.get()); | 777 UpdateDefaultFont(); |
898 GdkColor label_color = label_style->fg[GTK_STATE_NORMAL]; | |
899 SetThemeColorFromGtk(ThemeProperties::COLOR_TAB_TEXT, &label_color); | |
900 SetThemeColorFromGtk(ThemeProperties::COLOR_BOOKMARK_TEXT, &label_color); | |
901 SetThemeColorFromGtk(ThemeProperties::COLOR_STATUS_BAR_TEXT, &label_color); | |
902 | |
903 UpdateDefaultFont(label_style->font_desc); | |
904 | 778 |
905 // Build the various icon tints. | 779 // Build the various icon tints. |
906 GetNormalButtonTintHSL(&button_tint_); | 780 GetNormalButtonTintHSL(&button_tint_); |
907 GetNormalEntryForegroundHSL(&entry_tint_); | 781 GetNormalEntryForegroundHSL(&entry_tint_); |
908 GetSelectedEntryForegroundHSL(&selected_entry_tint_); | 782 GetSelectedEntryForegroundHSL(&selected_entry_tint_); |
909 GdkColor frame_color = BuildFrameColors(frame_style); | 783 SkColor frame_color = BuildFrameColors(); |
910 | 784 |
911 // The inactive frame color never occurs naturally in the theme, as it is a | 785 // The inactive frame color never occurs naturally in the theme, as it is a |
912 // tinted version of |frame_color|. We generate another color based on the | 786 // tinted version of |frame_color|. We generate another color based on the |
913 // background tab color, with the lightness and saturation moved in the | 787 // background tab color, with the lightness and saturation moved in the |
914 // opposite direction. (We don't touch the hue, since there should be subtle | 788 // opposite direction. (We don't touch the hue, since there should be subtle |
915 // hints of the color in the text.) | 789 // hints of the color in the text.) |
916 color_utils::HSL inactive_tab_text_hsl = | 790 color_utils::HSL inactive_tab_text_hsl = |
917 tints_[ThemeProperties::TINT_BACKGROUND_TAB]; | 791 tints_[ThemeProperties::TINT_BACKGROUND_TAB]; |
918 if (inactive_tab_text_hsl.l < 0.5) | 792 if (inactive_tab_text_hsl.l < 0.5) |
919 inactive_tab_text_hsl.l = kDarkInactiveLuminance; | 793 inactive_tab_text_hsl.l = kDarkInactiveLuminance; |
920 else | 794 else |
921 inactive_tab_text_hsl.l = kLightInactiveLuminance; | 795 inactive_tab_text_hsl.l = kLightInactiveLuminance; |
922 | 796 |
923 if (inactive_tab_text_hsl.s < 0.5) | 797 if (inactive_tab_text_hsl.s < 0.5) |
924 inactive_tab_text_hsl.s = kHeavyInactiveSaturation; | 798 inactive_tab_text_hsl.s = kHeavyInactiveSaturation; |
925 else | 799 else |
926 inactive_tab_text_hsl.s = kLightInactiveSaturation; | 800 inactive_tab_text_hsl.s = kLightInactiveSaturation; |
927 | 801 |
928 colors_[ThemeProperties::COLOR_BACKGROUND_TAB_TEXT] = | 802 colors_[ThemeProperties::COLOR_BACKGROUND_TAB_TEXT] = |
929 color_utils::HSLToSkColor(inactive_tab_text_hsl, 255); | 803 color_utils::HSLToSkColor(inactive_tab_text_hsl, 255); |
930 | 804 |
931 // We pick the text and background colors for the NTP out of the colors for a | 805 // We pick the text and background colors for the NTP out of the colors for a |
932 // GtkEntry. We do this because GtkEntries background color is never the same | 806 // GtkEntry. We do this because GtkEntries background color is never the same |
933 // as |toolbar_color|, is usually a white, and when it isn't a white, | 807 // as |toolbar_color|, is usually a white, and when it isn't a white, |
934 // provides sufficient contrast to |toolbar_color|. Try this out with | 808 // provides sufficient contrast to |toolbar_color|. Try this out with |
935 // Darklooks, HighContrastInverse or ThinIce. | 809 // Darklooks, HighContrastInverse or ThinIce. |
936 GtkStyle* entry_style = gtk_rc_get_style(fake_entry_.get()); | 810 |
937 GdkColor ntp_background = entry_style->base[GTK_STATE_NORMAL]; | 811 SkColor ntp_background = |
938 GdkColor ntp_foreground = entry_style->text[GTK_STATE_NORMAL]; | 812 GET_BASE_COLOR(NativeThemeGtk2::instance()->GetEntry(), NORMAL); |
939 SetThemeColorFromGtk(ThemeProperties::COLOR_NTP_BACKGROUND, | 813 SkColor ntp_foreground = |
940 &ntp_background); | 814 GET_TEXT_COLOR(NativeThemeGtk2::instance()->GetEntry(), NORMAL); |
941 SetThemeColorFromGtk(ThemeProperties::COLOR_NTP_TEXT, | 815 |
942 &ntp_foreground); | 816 colors_[ThemeProperties::COLOR_NTP_BACKGROUND] = ntp_background; |
| 817 colors_[ThemeProperties::COLOR_NTP_TEXT] = ntp_foreground; |
943 | 818 |
944 // The NTP header is the color that surrounds the current active thumbnail on | 819 // The NTP header is the color that surrounds the current active thumbnail on |
945 // the NTP, and acts as the border of the "Recent Links" box. It would be | 820 // the NTP, and acts as the border of the "Recent Links" box. It would be |
946 // awesome if they were separated so we could use GetBorderColor() for the | 821 // awesome if they were separated so we could use GetBorderColor() for the |
947 // border around the "Recent Links" section, but matching the frame color is | 822 // border around the "Recent Links" section, but matching the frame color is |
948 // more important. | 823 // more important. |
949 SetThemeColorFromGtk(ThemeProperties::COLOR_NTP_HEADER, | |
950 &frame_color); | |
951 SetThemeColorFromGtk(ThemeProperties::COLOR_NTP_SECTION, | |
952 &toolbar_color); | |
953 SetThemeColorFromGtk(ThemeProperties::COLOR_NTP_SECTION_TEXT, | |
954 &label_color); | |
955 | 824 |
956 // Override the link color if the theme provides it. | 825 colors_[ThemeProperties::COLOR_NTP_HEADER] = frame_color; |
957 const GdkColor* link_color = NULL; | 826 colors_[ThemeProperties::COLOR_NTP_SECTION] = toolbar_color; |
958 gtk_widget_style_get(GTK_WIDGET(fake_window_), | 827 colors_[ThemeProperties::COLOR_NTP_SECTION_TEXT] = label_color; |
959 "link-color", &link_color, NULL); | |
960 | 828 |
961 bool is_default_link_color = false; | 829 // Default link color, taken from gtklinkbutton.c. |
962 if (!link_color) { | 830 SkColor link_color = SkColorSetRGB(0, 0, 0xee); |
963 link_color = &kDefaultLinkColor; | 831 |
964 is_default_link_color = true; | 832 GdkColor* theme_link_color = NULL; |
| 833 gtk_widget_style_get(NativeThemeGtk2::instance()->GetWindow(), |
| 834 "link-color", &theme_link_color, NULL); |
| 835 if (theme_link_color) { |
| 836 link_color = GdkColorToSkColor(*theme_link_color); |
| 837 gdk_color_free(theme_link_color); |
965 } | 838 } |
966 | 839 |
967 SetThemeColorFromGtk(ThemeProperties::COLOR_NTP_LINK, | 840 colors_[ThemeProperties::COLOR_NTP_LINK] = link_color; |
968 link_color); | 841 colors_[ThemeProperties::COLOR_NTP_LINK_UNDERLINE] = link_color; |
969 SetThemeColorFromGtk(ThemeProperties::COLOR_NTP_LINK_UNDERLINE, | 842 colors_[ThemeProperties::COLOR_NTP_SECTION_LINK] = link_color; |
970 link_color); | 843 colors_[ThemeProperties::COLOR_NTP_SECTION_LINK_UNDERLINE] = link_color; |
971 SetThemeColorFromGtk(ThemeProperties::COLOR_NTP_SECTION_LINK, | |
972 link_color); | |
973 SetThemeColorFromGtk(ThemeProperties::COLOR_NTP_SECTION_LINK_UNDERLINE, | |
974 link_color); | |
975 | |
976 if (!is_default_link_color) | |
977 gdk_color_free(const_cast<GdkColor*>(link_color)); | |
978 | 844 |
979 // Generate the colors that we pass to WebKit. | 845 // Generate the colors that we pass to WebKit. |
980 focus_ring_color_ = GdkColorToSkColor(frame_color); | 846 focus_ring_color_ = frame_color; |
981 | 847 |
982 GdkColor thumb_active_color, thumb_inactive_color, track_color; | 848 SetScrollbarColors(); |
983 Gtk2UI::GetScrollbarColors(&thumb_active_color, | |
984 &thumb_inactive_color, | |
985 &track_color); | |
986 thumb_active_color_ = GdkColorToSkColor(thumb_active_color); | |
987 thumb_inactive_color_ = GdkColorToSkColor(thumb_inactive_color); | |
988 track_color_ = GdkColorToSkColor(track_color); | |
989 | 849 |
990 // Some GTK themes only define the text selection colors on the GtkEntry | 850 // Some GTK themes only define the text selection colors on the GtkEntry |
991 // class, so we need to use that for getting selection colors. | 851 // class, so we need to use that for getting selection colors. |
992 active_selection_bg_color_ = | 852 active_selection_bg_color_ = |
993 GdkColorToSkColor(entry_style->base[GTK_STATE_SELECTED]); | 853 GET_BASE_COLOR(NativeThemeGtk2::instance()->GetEntry(), SELECTED); |
994 active_selection_fg_color_ = | 854 active_selection_fg_color_ = |
995 GdkColorToSkColor(entry_style->text[GTK_STATE_SELECTED]); | 855 GET_TEXT_COLOR(NativeThemeGtk2::instance()->GetEntry(), SELECTED); |
996 inactive_selection_bg_color_ = | 856 inactive_selection_bg_color_ = |
997 GdkColorToSkColor(entry_style->base[GTK_STATE_ACTIVE]); | 857 GET_BASE_COLOR(NativeThemeGtk2::instance()->GetEntry(), ACTIVE); |
998 inactive_selection_fg_color_ = | 858 inactive_selection_fg_color_ = |
999 GdkColorToSkColor(entry_style->text[GTK_STATE_ACTIVE]); | 859 GET_TEXT_COLOR(NativeThemeGtk2::instance()->GetEntry(), ACTIVE); |
1000 | 860 |
1001 colors_[ThemeProperties::COLOR_THROBBER_SPINNING] = | 861 colors_[ThemeProperties::COLOR_THROBBER_SPINNING] = |
1002 NativeThemeGtk2::instance()->GetSystemColor( | 862 NativeThemeGtk2::instance()->GetSystemColor( |
1003 ui::NativeTheme::kColorId_ThrobberSpinningColor); | 863 ui::NativeTheme::kColorId_ThrobberSpinningColor); |
1004 colors_[ThemeProperties::COLOR_THROBBER_WAITING] = | 864 colors_[ThemeProperties::COLOR_THROBBER_WAITING] = |
1005 NativeThemeGtk2::instance()->GetSystemColor( | 865 NativeThemeGtk2::instance()->GetSystemColor( |
1006 ui::NativeTheme::kColorId_ThrobberWaitingColor); | 866 ui::NativeTheme::kColorId_ThrobberWaitingColor); |
1007 } | 867 } |
1008 | 868 |
1009 GdkColor Gtk2UI::BuildFrameColors(GtkStyle* frame_style) { | 869 SkColor Gtk2UI::BuildFrameColors() { |
1010 GdkColor* theme_frame = NULL; | 870 GdkColor* theme_frame = NULL; |
1011 GdkColor* theme_inactive_frame = NULL; | 871 GdkColor* theme_inactive_frame = NULL; |
1012 GdkColor* theme_incognito_frame = NULL; | 872 GdkColor* theme_incognito_frame = NULL; |
1013 GdkColor* theme_incognito_inactive_frame = NULL; | 873 GdkColor* theme_incognito_inactive_frame = NULL; |
| 874 |
1014 gtk_widget_style_get(GTK_WIDGET(fake_frame_), | 875 gtk_widget_style_get(GTK_WIDGET(fake_frame_), |
1015 "frame-color", &theme_frame, | 876 "frame-color", &theme_frame, |
1016 "inactive-frame-color", &theme_inactive_frame, | 877 "inactive-frame-color", &theme_inactive_frame, |
1017 "incognito-frame-color", &theme_incognito_frame, | 878 "incognito-frame-color", &theme_incognito_frame, |
1018 "incognito-inactive-frame-color", | 879 "incognito-inactive-frame-color", |
1019 &theme_incognito_inactive_frame, | 880 &theme_incognito_inactive_frame, |
1020 NULL); | 881 NULL); |
1021 | 882 |
1022 GdkColor frame_color = BuildAndSetFrameColor( | 883 SkColor frame_color = GET_BG_COLOR(fake_frame_, NORMAL); |
1023 &frame_style->bg[GTK_STATE_SELECTED], | 884 SkColor temp_color; |
1024 theme_frame, | 885 SetThemeTint(ThemeProperties::TINT_BACKGROUND_TAB, frame_color); |
1025 kDefaultFrameShift, | 886 |
1026 ThemeProperties::COLOR_FRAME, | 887 |
1027 ThemeProperties::TINT_FRAME); | 888 temp_color = color_utils::HSLShift( |
1028 if (theme_frame) | 889 frame_color, |
| 890 GetDefaultTint(ThemeProperties::TINT_FRAME)); |
| 891 if (theme_frame) { |
| 892 temp_color = GdkColorToSkColor(*theme_frame); |
1029 gdk_color_free(theme_frame); | 893 gdk_color_free(theme_frame); |
1030 SetThemeTintFromGtk(ThemeProperties::TINT_BACKGROUND_TAB, &frame_color); | 894 } |
| 895 colors_[ThemeProperties::COLOR_FRAME] = temp_color; |
| 896 SetThemeTint(ThemeProperties::TINT_FRAME, temp_color); |
1031 | 897 |
1032 BuildAndSetFrameColor( | 898 |
1033 &frame_style->bg[GTK_STATE_INSENSITIVE], | 899 temp_color = color_utils::HSLShift( |
1034 theme_inactive_frame, | 900 frame_color, |
1035 kDefaultFrameShift, | 901 GetDefaultTint(ThemeProperties::TINT_FRAME_INACTIVE)); |
1036 ThemeProperties::COLOR_FRAME_INACTIVE, | 902 if (theme_inactive_frame) { |
1037 ThemeProperties::TINT_FRAME_INACTIVE); | 903 temp_color = GdkColorToSkColor(*theme_inactive_frame); |
1038 if (theme_inactive_frame) | |
1039 gdk_color_free(theme_inactive_frame); | 904 gdk_color_free(theme_inactive_frame); |
| 905 } |
| 906 colors_[ThemeProperties::COLOR_FRAME_INACTIVE] = temp_color; |
| 907 SetThemeTint(ThemeProperties::TINT_FRAME_INACTIVE, temp_color); |
1040 | 908 |
1041 BuildAndSetFrameColor( | 909 |
1042 &frame_color, | 910 temp_color = color_utils::HSLShift( |
1043 theme_incognito_frame, | 911 frame_color, |
1044 GetDefaultTint(ThemeProperties::TINT_FRAME_INCOGNITO), | 912 GetDefaultTint(ThemeProperties::TINT_FRAME_INCOGNITO)); |
1045 ThemeProperties::COLOR_FRAME_INCOGNITO, | 913 if (theme_incognito_frame) { |
1046 ThemeProperties::TINT_FRAME_INCOGNITO); | 914 temp_color = GdkColorToSkColor(*theme_incognito_frame); |
1047 if (theme_incognito_frame) | |
1048 gdk_color_free(theme_incognito_frame); | 915 gdk_color_free(theme_incognito_frame); |
| 916 } |
| 917 colors_[ThemeProperties::COLOR_FRAME_INCOGNITO] = temp_color; |
| 918 SetThemeTint(ThemeProperties::TINT_FRAME_INCOGNITO, temp_color); |
1049 | 919 |
1050 BuildAndSetFrameColor( | 920 |
1051 &frame_color, | 921 temp_color = color_utils::HSLShift( |
1052 theme_incognito_inactive_frame, | 922 frame_color, |
1053 GetDefaultTint(ThemeProperties::TINT_FRAME_INCOGNITO_INACTIVE), | 923 GetDefaultTint(ThemeProperties::TINT_FRAME_INCOGNITO_INACTIVE)); |
1054 ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE, | 924 if (theme_incognito_inactive_frame) { |
1055 ThemeProperties::TINT_FRAME_INCOGNITO_INACTIVE); | 925 temp_color = GdkColorToSkColor(*theme_incognito_inactive_frame); |
1056 if (theme_incognito_inactive_frame) | |
1057 gdk_color_free(theme_incognito_inactive_frame); | 926 gdk_color_free(theme_incognito_inactive_frame); |
| 927 } |
| 928 colors_[ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE] = temp_color; |
| 929 SetThemeTint(ThemeProperties::TINT_FRAME_INCOGNITO_INACTIVE, temp_color); |
| 930 |
1058 | 931 |
1059 return frame_color; | 932 return frame_color; |
1060 } | 933 } |
1061 | 934 |
1062 void Gtk2UI::SetThemeColorFromGtk(int id, const GdkColor* color) { | 935 void Gtk2UI::SetThemeTint(int id, SkColor color) { |
1063 colors_[id] = GdkColorToSkColor(*color); | |
1064 } | |
1065 | |
1066 void Gtk2UI::SetThemeTintFromGtk(int id, const GdkColor* color) { | |
1067 color_utils::HSL default_tint = GetDefaultTint(id); | 936 color_utils::HSL default_tint = GetDefaultTint(id); |
1068 color_utils::HSL hsl; | 937 color_utils::HSL hsl; |
1069 color_utils::SkColorToHSL(GdkColorToSkColor(*color), &hsl); | 938 color_utils::SkColorToHSL(color, &hsl); |
1070 | 939 |
1071 if (default_tint.s != -1) | 940 if (default_tint.s != -1) |
1072 hsl.s = default_tint.s; | 941 hsl.s = default_tint.s; |
1073 | 942 |
1074 if (default_tint.l != -1) | 943 if (default_tint.l != -1) |
1075 hsl.l = default_tint.l; | 944 hsl.l = default_tint.l; |
1076 | 945 |
1077 tints_[id] = hsl; | 946 tints_[id] = hsl; |
1078 } | 947 } |
1079 | 948 |
1080 GdkColor Gtk2UI::BuildAndSetFrameColor(const GdkColor* base, | |
1081 const GdkColor* gtk_base, | |
1082 const color_utils::HSL& tint, | |
1083 int color_id, | |
1084 int tint_id) { | |
1085 GdkColor out_color = *base; | |
1086 if (gtk_base) { | |
1087 // The theme author specified a color to use, use it without modification. | |
1088 out_color = *gtk_base; | |
1089 } else { | |
1090 // Tint the basic color since this is a heuristic color instead of one | |
1091 // specified by the theme author. | |
1092 GdkColorHSLShift(tint, &out_color); | |
1093 } | |
1094 SetThemeColorFromGtk(color_id, &out_color); | |
1095 SetThemeTintFromGtk(tint_id, &out_color); | |
1096 | |
1097 return out_color; | |
1098 } | |
1099 | |
1100 SkBitmap Gtk2UI::GenerateGtkThemeBitmap(int id) const { | 949 SkBitmap Gtk2UI::GenerateGtkThemeBitmap(int id) const { |
1101 switch (id) { | 950 switch (id) { |
1102 case IDR_THEME_TOOLBAR: { | 951 case IDR_THEME_TOOLBAR: { |
1103 GtkStyle* style = gtk_rc_get_style(fake_window_); | |
1104 GdkColor* color = &style->bg[GTK_STATE_NORMAL]; | |
1105 SkBitmap bitmap; | 952 SkBitmap bitmap; |
1106 bitmap.allocN32Pixels(kToolbarImageWidth, kToolbarImageHeight); | 953 bitmap.allocN32Pixels(kToolbarImageWidth, kToolbarImageHeight); |
1107 bitmap.eraseARGB(0xff, color->red >> 8, color->green >> 8, | 954 bitmap.eraseColor(GET_BG_COLOR(NativeThemeGtk2::instance()->GetWindow(), |
1108 color->blue >> 8); | 955 NORMAL)); |
1109 return bitmap; | 956 return bitmap; |
1110 } | 957 } |
1111 case IDR_THEME_TAB_BACKGROUND: | 958 case IDR_THEME_TAB_BACKGROUND: |
1112 case IDR_THEME_TAB_BACKGROUND_DESKTOP: | 959 case IDR_THEME_TAB_BACKGROUND_DESKTOP: |
1113 return GenerateTabImage(IDR_THEME_FRAME); | 960 return GenerateTabImage(IDR_THEME_FRAME); |
1114 case IDR_THEME_TAB_BACKGROUND_INCOGNITO: | 961 case IDR_THEME_TAB_BACKGROUND_INCOGNITO: |
1115 case IDR_THEME_TAB_BACKGROUND_INCOGNITO_DESKTOP: | 962 case IDR_THEME_TAB_BACKGROUND_INCOGNITO_DESKTOP: |
1116 return GenerateTabImage(IDR_THEME_FRAME_INCOGNITO); | 963 return GenerateTabImage(IDR_THEME_FRAME_INCOGNITO); |
1117 case IDR_FRAME: | 964 case IDR_FRAME: |
1118 case IDR_THEME_FRAME: | 965 case IDR_THEME_FRAME: |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1161 case IDR_FORWARD: | 1008 case IDR_FORWARD: |
1162 case IDR_FORWARD_D: | 1009 case IDR_FORWARD_D: |
1163 case IDR_HOME: | 1010 case IDR_HOME: |
1164 case IDR_RELOAD: | 1011 case IDR_RELOAD: |
1165 case IDR_RELOAD_D: | 1012 case IDR_RELOAD_D: |
1166 case IDR_STOP: | 1013 case IDR_STOP: |
1167 case IDR_STOP_D: { | 1014 case IDR_STOP_D: { |
1168 return GenerateGTKIcon(id); | 1015 return GenerateGTKIcon(id); |
1169 } | 1016 } |
1170 case IDR_TOOLBAR_BEZEL_HOVER: | 1017 case IDR_TOOLBAR_BEZEL_HOVER: |
1171 return GenerateToolbarBezel(GTK_STATE_PRELIGHT, IDR_TOOLBAR_BEZEL_HOVER); | 1018 return GenerateToolbarBezel(ui::NativeTheme::kHovered, IDR_TOOLBAR_BEZEL_H
OVER); |
1172 case IDR_TOOLBAR_BEZEL_PRESSED: | 1019 case IDR_TOOLBAR_BEZEL_PRESSED: |
1173 return GenerateToolbarBezel(GTK_STATE_ACTIVE, IDR_TOOLBAR_BEZEL_PRESSED); | 1020 return GenerateToolbarBezel(ui::NativeTheme::kPressed, IDR_TOOLBAR_BEZEL_P
RESSED); |
1174 default: { | 1021 default: { |
1175 return GenerateTintedIcon(id, button_tint_); | 1022 return GenerateTintedIcon(id, button_tint_); |
1176 } | 1023 } |
1177 } | 1024 } |
1178 | 1025 |
1179 return SkBitmap(); | 1026 return SkBitmap(); |
1180 } | 1027 } |
1181 | 1028 |
1182 SkBitmap Gtk2UI::GenerateFrameImage( | 1029 SkBitmap Gtk2UI::GenerateFrameImage( |
1183 int color_id, | 1030 int color_id, |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1231 SkBitmap Gtk2UI::GenerateTintedIcon( | 1078 SkBitmap Gtk2UI::GenerateTintedIcon( |
1232 int base_id, | 1079 int base_id, |
1233 const color_utils::HSL& tint) const { | 1080 const color_utils::HSL& tint) const { |
1234 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 1081 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
1235 return SkBitmapOperations::CreateHSLShiftedBitmap( | 1082 return SkBitmapOperations::CreateHSLShiftedBitmap( |
1236 rb.GetImageNamed(base_id).AsBitmap(), tint); | 1083 rb.GetImageNamed(base_id).AsBitmap(), tint); |
1237 } | 1084 } |
1238 | 1085 |
1239 SkBitmap Gtk2UI::GenerateGTKIcon(int base_id) const { | 1086 SkBitmap Gtk2UI::GenerateGTKIcon(int base_id) const { |
1240 const char* stock_id = NULL; | 1087 const char* stock_id = NULL; |
1241 GtkStateType gtk_state = GTK_STATE_NORMAL; | 1088 bool enabled = true; |
1242 for (unsigned int i = 0; i < arraysize(kGtkIcons); ++i) { | 1089 for (unsigned int i = 0; i < arraysize(kGtkIcons); ++i) { |
1243 if (kGtkIcons[i].idr == base_id) { | 1090 if (kGtkIcons[i].idr == base_id) { |
1244 stock_id = kGtkIcons[i].stock_id; | 1091 stock_id = kGtkIcons[i].stock_id; |
1245 gtk_state = kGtkIcons[i].gtk_state; | 1092 enabled = kGtkIcons[i].enabled; |
1246 break; | 1093 break; |
1247 } | 1094 } |
1248 } | 1095 } |
1249 DCHECK(stock_id); | 1096 DCHECK(stock_id); |
1250 | 1097 |
1251 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 1098 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
1252 SkBitmap default_bitmap = rb.GetImageNamed(base_id).AsBitmap(); | 1099 SkBitmap default_bitmap = rb.GetImageNamed(base_id).AsBitmap(); |
1253 | 1100 |
1254 gtk_widget_ensure_style(fake_frame_); | 1101 gtk_widget_ensure_style(fake_frame_); |
1255 GtkStyle* style = gtk_widget_get_style(fake_frame_); | 1102 GtkStyle* style = gtk_widget_get_style(fake_frame_); |
1256 GtkIconSet* icon_set = gtk_style_lookup_icon_set(style, stock_id); | 1103 GtkIconSet* icon_set = gtk_style_lookup_icon_set(style, stock_id); |
1257 if (!icon_set) | 1104 if (!icon_set) |
1258 return default_bitmap; | 1105 return default_bitmap; |
1259 | 1106 |
1260 // Ask GTK to render the icon to a buffer, which we will steal from. | 1107 // Ask GTK to render the icon to a buffer, which we will steal from. |
1261 GdkPixbuf* gdk_icon = gtk_icon_set_render_icon( | 1108 GdkPixbuf* gdk_icon = gtk_icon_set_render_icon( |
1262 icon_set, | 1109 icon_set, |
1263 style, | 1110 style, |
1264 base::i18n::IsRTL() ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR, | 1111 base::i18n::IsRTL() ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR, |
1265 gtk_state, | 1112 enabled ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE, |
1266 GTK_ICON_SIZE_SMALL_TOOLBAR, | 1113 GTK_ICON_SIZE_SMALL_TOOLBAR, |
1267 fake_frame_, | 1114 fake_frame_, |
1268 NULL); | 1115 NULL); |
1269 | 1116 |
1270 if (!gdk_icon) { | 1117 if (!gdk_icon) { |
1271 // This can theoretically happen if an icon theme doesn't provide a | 1118 // This can theoretically happen if an icon theme doesn't provide a |
1272 // specific image. This should realistically never happen, but I bet there | 1119 // specific image. This should realistically never happen, but I bet there |
1273 // are some theme authors who don't reliably provide all icons. | 1120 // are some theme authors who don't reliably provide all icons. |
1274 return default_bitmap; | 1121 return default_bitmap; |
1275 } | 1122 } |
1276 | 1123 |
1277 SkBitmap retval; | 1124 SkBitmap retval; |
1278 retval.allocN32Pixels(default_bitmap.width(), default_bitmap.height()); | 1125 retval.allocN32Pixels(default_bitmap.width(), default_bitmap.height()); |
1279 retval.eraseColor(0); | 1126 retval.eraseColor(0); |
1280 | 1127 |
1281 const SkBitmap icon = GdkPixbufToImageSkia(gdk_icon); | 1128 const SkBitmap icon = GdkPixbufToImageSkia(gdk_icon); |
1282 g_object_unref(gdk_icon); | 1129 g_object_unref(gdk_icon); |
1283 | 1130 |
1284 SkCanvas canvas(retval); | 1131 SkCanvas canvas(retval); |
1285 | 1132 |
1286 if (gtk_state == GTK_STATE_ACTIVE || gtk_state == GTK_STATE_PRELIGHT) { | |
1287 SkBitmap border = DrawGtkButtonBorder(gtk_state, | |
1288 false, | |
1289 false, | |
1290 default_bitmap.width(), | |
1291 default_bitmap.height()); | |
1292 canvas.drawBitmap(border, 0, 0); | |
1293 } | |
1294 | |
1295 canvas.drawBitmap(icon, | 1133 canvas.drawBitmap(icon, |
1296 (default_bitmap.width() / 2) - (icon.width() / 2), | 1134 (default_bitmap.width() / 2) - (icon.width() / 2), |
1297 (default_bitmap.height() / 2) - (icon.height() / 2)); | 1135 (default_bitmap.height() / 2) - (icon.height() / 2)); |
1298 | 1136 |
1299 return retval; | 1137 return retval; |
1300 } | 1138 } |
1301 | 1139 |
1302 SkBitmap Gtk2UI::GenerateToolbarBezel(int gtk_state, int sizing_idr) const { | 1140 SkBitmap Gtk2UI::GenerateToolbarBezel( |
| 1141 ui::NativeTheme::State state, |
| 1142 int sizing_idr) const { |
1303 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 1143 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
1304 SkBitmap default_bitmap = | 1144 SkBitmap default_bitmap = |
1305 rb.GetImageNamed(sizing_idr).AsBitmap(); | 1145 rb.GetImageNamed(sizing_idr).AsBitmap(); |
1306 | 1146 |
1307 SkBitmap retval; | 1147 return DrawGtkButtonBorder( |
1308 retval.allocN32Pixels(default_bitmap.width(), default_bitmap.height()); | 1148 state, |
1309 retval.eraseColor(0); | |
1310 | |
1311 SkCanvas canvas(retval); | |
1312 SkBitmap border = DrawGtkButtonBorder( | |
1313 gtk_state, | |
1314 false, | |
1315 false, | |
1316 default_bitmap.width(), | 1149 default_bitmap.width(), |
1317 default_bitmap.height()); | 1150 default_bitmap.height()); |
1318 canvas.drawBitmap(border, 0, 0); | |
1319 | |
1320 return retval; | |
1321 } | 1151 } |
1322 | 1152 |
1323 void Gtk2UI::GetNormalButtonTintHSL(color_utils::HSL* tint) const { | 1153 void Gtk2UI::GetNormalButtonTintHSL(color_utils::HSL* tint) const { |
1324 GtkStyle* window_style = gtk_rc_get_style(fake_window_); | 1154 SkColor accent_color = |
1325 const GdkColor accent_gdk_color = window_style->bg[GTK_STATE_SELECTED]; | 1155 GET_BG_COLOR(NativeThemeGtk2::instance()->GetWindow(), SELECTED); |
1326 const GdkColor base_color = window_style->base[GTK_STATE_NORMAL]; | 1156 SkColor text_color = |
| 1157 GET_FG_COLOR(NativeThemeGtk2::instance()->GetLabel(), NORMAL); |
| 1158 SkColor base_color = |
| 1159 GET_BASE_COLOR(NativeThemeGtk2::instance()->GetWindow(), NORMAL); |
1327 | 1160 |
1328 GtkStyle* label_style = gtk_rc_get_style(fake_label_.get()); | 1161 PickButtonTintFromColors(accent_color, text_color, base_color, tint); |
1329 const GdkColor text_color = label_style->fg[GTK_STATE_NORMAL]; | |
1330 | |
1331 PickButtonTintFromColors(accent_gdk_color, text_color, base_color, tint); | |
1332 } | 1162 } |
1333 | 1163 |
1334 void Gtk2UI::GetNormalEntryForegroundHSL(color_utils::HSL* tint) const { | 1164 void Gtk2UI::GetNormalEntryForegroundHSL(color_utils::HSL* tint) const { |
1335 GtkStyle* window_style = gtk_rc_get_style(fake_window_); | 1165 SkColor accent_color = |
1336 const GdkColor accent_gdk_color = window_style->bg[GTK_STATE_SELECTED]; | 1166 GET_BG_COLOR(NativeThemeGtk2::instance()->GetWindow(), SELECTED); |
| 1167 SkColor text_color = |
| 1168 GET_TEXT_COLOR(NativeThemeGtk2::instance()->GetEntry(), NORMAL); |
| 1169 SkColor base_color = |
| 1170 GET_BASE_COLOR(NativeThemeGtk2::instance()->GetEntry(), NORMAL); |
1337 | 1171 |
1338 GtkStyle* style = gtk_rc_get_style(fake_entry_.get()); | 1172 PickButtonTintFromColors(accent_color, text_color, base_color, tint); |
1339 const GdkColor text_color = style->text[GTK_STATE_NORMAL]; | |
1340 const GdkColor base_color = style->base[GTK_STATE_NORMAL]; | |
1341 | |
1342 PickButtonTintFromColors(accent_gdk_color, text_color, base_color, tint); | |
1343 } | 1173 } |
1344 | 1174 |
1345 void Gtk2UI::GetSelectedEntryForegroundHSL(color_utils::HSL* tint) const { | 1175 void Gtk2UI::GetSelectedEntryForegroundHSL(color_utils::HSL* tint) const { |
1346 // The simplest of all the tints. We just use the selected text in the entry | 1176 // The simplest of all the tints. We just use the selected text in the entry |
1347 // since the icons tinted this way will only be displayed against | 1177 // since the icons tinted this way will only be displayed against |
1348 // base[GTK_STATE_SELECTED]. | 1178 // base[GTK_STATE_SELECTED]. |
1349 GtkStyle* style = gtk_rc_get_style(fake_entry_.get()); | 1179 SkColor color = |
1350 const GdkColor color = style->text[GTK_STATE_SELECTED]; | 1180 GET_TEXT_COLOR(NativeThemeGtk2::instance()->GetEntry(), SELECTED); |
1351 color_utils::SkColorToHSL(GdkColorToSkColor(color), tint); | 1181 |
| 1182 color_utils::SkColorToHSL(color, tint); |
1352 } | 1183 } |
1353 | 1184 |
1354 SkBitmap Gtk2UI::DrawGtkButtonBorder(int gtk_state, | 1185 SkBitmap Gtk2UI::DrawGtkButtonBorder(ui::NativeTheme::State state, |
1355 bool focused, | |
1356 bool call_to_action, | |
1357 int width, | 1186 int width, |
1358 int height) const { | 1187 int height) const { |
| 1188 SkBitmap border; |
| 1189 border.allocN32Pixels(width, height); |
| 1190 border.eraseColor(0); |
| 1191 |
1359 // Create a temporary GTK button to snapshot | 1192 // Create a temporary GTK button to snapshot |
1360 GtkWidget* window = gtk_offscreen_window_new(); | 1193 GtkWidget* window = gtk_offscreen_window_new(); |
1361 GtkWidget* button = gtk_button_new(); | 1194 GtkWidget* button = gtk_toggle_button_new(); |
| 1195 |
| 1196 if (state == ui::NativeTheme::kPressed) |
| 1197 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), true); |
| 1198 else if (state == ui::NativeTheme::kDisabled) |
| 1199 gtk_widget_set_sensitive(button, false); |
| 1200 |
1362 gtk_widget_set_size_request(button, width, height); | 1201 gtk_widget_set_size_request(button, width, height); |
1363 gtk_container_add(GTK_CONTAINER(window), button); | 1202 gtk_container_add(GTK_CONTAINER(window), button); |
1364 gtk_widget_realize(window); | 1203 gtk_widget_show_all(window); |
1365 gtk_widget_realize(button); | |
1366 gtk_widget_show(button); | |
1367 gtk_widget_show(window); | |
1368 | 1204 |
1369 if (call_to_action) | 1205 cairo_surface_t* surface = cairo_image_surface_create_for_data( |
1370 GTK_WIDGET_SET_FLAGS(button, GTK_HAS_DEFAULT); | 1206 static_cast<unsigned char*>(border.getAddr(0, 0)), |
| 1207 CAIRO_FORMAT_ARGB32, |
| 1208 width, height, |
| 1209 width * 4); |
| 1210 cairo_t* cr = cairo_create(surface); |
1371 | 1211 |
1372 if (focused) { | 1212 #if GTK_MAJOR_VERSION == 2 |
1373 // We can't just use gtk_widget_grab_focus() here because that sets | |
1374 // gtk_widget_is_focus(), but not gtk_widget_has_focus(), which is what the | |
1375 // GtkButton's paint checks. | |
1376 GTK_WIDGET_SET_FLAGS(button, GTK_HAS_FOCUS); | |
1377 } | |
1378 | |
1379 gtk_widget_set_state(button, static_cast<GtkStateType>(gtk_state)); | |
1380 | |
1381 GdkPixmap* pixmap; | |
1382 { | |
1383 // http://crbug.com/346740 | |
1384 ANNOTATE_SCOPED_MEMORY_LEAK; | |
1385 pixmap = gtk_widget_get_snapshot(button, NULL); | |
1386 } | |
1387 int w, h; | 1213 int w, h; |
| 1214 GdkPixmap* pixmap = gtk_widget_get_snapshot(button, NULL); |
1388 gdk_drawable_get_size(GDK_DRAWABLE(pixmap), &w, &h); | 1215 gdk_drawable_get_size(GDK_DRAWABLE(pixmap), &w, &h); |
1389 DCHECK_EQ(w, width); | |
1390 DCHECK_EQ(h, height); | |
1391 | |
1392 // We render the Pixmap to a Pixbuf. This can be slow, as we're scrapping | |
1393 // bits from X. | |
1394 GdkColormap* colormap = gdk_drawable_get_colormap(pixmap); | 1216 GdkColormap* colormap = gdk_drawable_get_colormap(pixmap); |
1395 GdkPixbuf* pixbuf = gdk_pixbuf_get_from_drawable(NULL, | 1217 GdkPixbuf* pixbuf = gdk_pixbuf_get_from_drawable(NULL, |
1396 GDK_DRAWABLE(pixmap), | 1218 GDK_DRAWABLE(pixmap), |
1397 colormap, | 1219 colormap, |
1398 0, 0, 0, 0, w, h); | 1220 0, 0, 0, 0, w, h); |
1399 | 1221 |
1400 // Finally, we convert our pixbuf into a type we can use. | 1222 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); |
1401 SkBitmap border = GdkPixbufToImageSkia(pixbuf); | 1223 cairo_paint(cr); |
| 1224 |
1402 g_object_unref(pixbuf); | 1225 g_object_unref(pixbuf); |
1403 g_object_unref(pixmap); | 1226 g_object_unref(pixmap); |
| 1227 #else |
| 1228 gtk_widget_draw(button, cr); |
| 1229 #endif |
| 1230 |
| 1231 cairo_destroy(cr); |
| 1232 cairo_surface_destroy(surface); |
| 1233 |
| 1234 |
1404 gtk_widget_destroy(window); | 1235 gtk_widget_destroy(window); |
1405 | 1236 |
1406 return border; | 1237 return border; |
1407 } | 1238 } |
1408 | 1239 |
1409 void Gtk2UI::ClearAllThemeData() { | 1240 void Gtk2UI::ClearAllThemeData() { |
1410 gtk_images_.clear(); | 1241 gtk_images_.clear(); |
1411 } | 1242 } |
1412 | 1243 |
1413 void Gtk2UI::UpdateDefaultFont(const PangoFontDescription* desc) { | 1244 void Gtk2UI::UpdateDefaultFont() { |
| 1245 GtkStyle* style = gtk_rc_get_style(NativeThemeGtk2::instance()->GetLabel()); |
| 1246 const PangoFontDescription* desc = style->font_desc; |
| 1247 |
1414 // Use gfx::FontRenderParams to select a family and determine the rendering | 1248 // Use gfx::FontRenderParams to select a family and determine the rendering |
1415 // settings. | 1249 // settings. |
1416 gfx::FontRenderParamsQuery query; | 1250 gfx::FontRenderParamsQuery query; |
1417 query.families = base::SplitString(pango_font_description_get_family(desc), | 1251 query.families = base::SplitString(pango_font_description_get_family(desc), |
1418 ",", base::TRIM_WHITESPACE, | 1252 ",", base::TRIM_WHITESPACE, |
1419 base::SPLIT_WANT_ALL); | 1253 base::SPLIT_WANT_ALL); |
1420 | 1254 |
1421 if (pango_font_description_get_size_is_absolute(desc)) { | 1255 if (pango_font_description_get_size_is_absolute(desc)) { |
1422 // If the size is absolute, it's specified in Pango units. There are | 1256 // If the size is absolute, it's specified in Pango units. There are |
1423 // PANGO_SCALE Pango units in a device unit (pixel). | 1257 // PANGO_SCALE Pango units in a device unit (pixel). |
(...skipping 24 matching lines...) Expand all Loading... |
1448 } | 1282 } |
1449 | 1283 |
1450 void Gtk2UI::OnStyleSet(GtkWidget* widget, GtkStyle* previous_style) { | 1284 void Gtk2UI::OnStyleSet(GtkWidget* widget, GtkStyle* previous_style) { |
1451 ClearAllThemeData(); | 1285 ClearAllThemeData(); |
1452 LoadGtkValues(); | 1286 LoadGtkValues(); |
1453 NativeThemeGtk2::instance()->NotifyObservers(); | 1287 NativeThemeGtk2::instance()->NotifyObservers(); |
1454 } | 1288 } |
1455 | 1289 |
1456 void Gtk2UI::UpdateDeviceScaleFactor(float device_scale_factor) { | 1290 void Gtk2UI::UpdateDeviceScaleFactor(float device_scale_factor) { |
1457 device_scale_factor_ = device_scale_factor; | 1291 device_scale_factor_ = device_scale_factor; |
1458 GtkStyle* label_style = gtk_rc_get_style(fake_label_.get()); | 1292 UpdateDefaultFont(); |
1459 UpdateDefaultFont(label_style->font_desc); | |
1460 } | 1293 } |
1461 | 1294 |
1462 float Gtk2UI::GetDeviceScaleFactor() const { | 1295 float Gtk2UI::GetDeviceScaleFactor() const { |
1463 if (gfx::Display::HasForceDeviceScaleFactor()) | 1296 if (gfx::Display::HasForceDeviceScaleFactor()) |
1464 return gfx::Display::GetForcedDeviceScaleFactor(); | 1297 return gfx::Display::GetForcedDeviceScaleFactor(); |
1465 // Linux chrome does not support dynamnic scale factor change. Use the | 1298 // Linux chrome does not support dynamnic scale factor change. Use the |
1466 // value obtanied during startup. The value is rounded to 1 decimal, e.g. | 1299 // value obtanied during startup. The value is rounded to 1 decimal, e.g. |
1467 // to 1.4, for safety. | 1300 // to 1.4, for safety. |
1468 static float device_scale_factor = | 1301 static float device_scale_factor = |
1469 roundf(GetGnomeTextScalingFactor() * 10) / 10; | 1302 roundf(GetGnomeTextScalingFactor() * 10) / 10; |
1470 return device_scale_factor; | 1303 return device_scale_factor; |
1471 } | 1304 } |
1472 | 1305 |
1473 } // namespace libgtk2ui | 1306 } // namespace libgtk2ui |
1474 | 1307 |
1475 views::LinuxUI* BuildGtk2UI() { | 1308 views::LinuxUI* BuildGtk2UI() { |
1476 return new libgtk2ui::Gtk2UI; | 1309 return new libgtk2ui::Gtk2UI; |
1477 } | 1310 } |
OLD | NEW |