OLD | NEW |
| (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/libgtkui/gtk2_ui.h" | |
6 | |
7 #include <math.h> | |
8 #include <pango/pango.h> | |
9 #include <X11/Xcursor/Xcursor.h> | |
10 #include <set> | |
11 #include <utility> | |
12 | |
13 #include "base/command_line.h" | |
14 #include "base/debug/leak_annotations.h" | |
15 #include "base/environment.h" | |
16 #include "base/i18n/rtl.h" | |
17 #include "base/logging.h" | |
18 #include "base/macros.h" | |
19 #include "base/nix/mime_util_xdg.h" | |
20 #include "base/nix/xdg_util.h" | |
21 #include "base/stl_util.h" | |
22 #include "base/strings/string_split.h" | |
23 #include "base/strings/stringprintf.h" | |
24 #include "chrome/browser/themes/theme_properties.h" | |
25 #include "chrome/browser/ui/libgtkui/app_indicator_icon.h" | |
26 #include "chrome/browser/ui/libgtkui/gtk2_event_loop.h" | |
27 #include "chrome/browser/ui/libgtkui/gtk2_key_bindings_handler.h" | |
28 #include "chrome/browser/ui/libgtkui/gtk2_status_icon.h" | |
29 #include "chrome/browser/ui/libgtkui/gtk2_util.h" | |
30 #include "chrome/browser/ui/libgtkui/native_theme_gtk2.h" | |
31 #include "chrome/browser/ui/libgtkui/print_dialog_gtk2.h" | |
32 #include "chrome/browser/ui/libgtkui/printing_gtk2_util.h" | |
33 #include "chrome/browser/ui/libgtkui/select_file_dialog_impl.h" | |
34 #include "chrome/browser/ui/libgtkui/skia_utils_gtk2.h" | |
35 #include "chrome/browser/ui/libgtkui/unity_service.h" | |
36 #include "chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk2.h" | |
37 #include "chrome/grit/theme_resources.h" | |
38 #include "components/grit/components_scaled_resources.h" | |
39 #include "third_party/skia/include/core/SkBitmap.h" | |
40 #include "third_party/skia/include/core/SkCanvas.h" | |
41 #include "third_party/skia/include/core/SkColor.h" | |
42 #include "third_party/skia/include/core/SkShader.h" | |
43 #include "ui/base/resource/resource_bundle.h" | |
44 #include "ui/display/display.h" | |
45 #include "ui/gfx/canvas.h" | |
46 #include "ui/gfx/geometry/rect.h" | |
47 #include "ui/gfx/geometry/size.h" | |
48 #include "ui/gfx/image/image.h" | |
49 #include "ui/gfx/image/image_skia_source.h" | |
50 #include "ui/gfx/skbitmap_operations.h" | |
51 #include "ui/gfx/skia_util.h" | |
52 #include "ui/gfx/x/x11_types.h" | |
53 #include "ui/native_theme/native_theme.h" | |
54 #include "ui/resources/grit/ui_resources.h" | |
55 #include "ui/views/controls/button/blue_button.h" | |
56 #include "ui/views/controls/button/label_button.h" | |
57 #include "ui/views/controls/button/label_button_border.h" | |
58 #include "ui/views/linux_ui/window_button_order_observer.h" | |
59 #include "ui/views/resources/grit/views_resources.h" | |
60 | |
61 #if defined(ENABLE_BASIC_PRINTING) | |
62 #include "printing/printing_context_linux.h" | |
63 #endif | |
64 #if defined(USE_GCONF) | |
65 #include "chrome/browser/ui/libgtkui/gconf_listener.h" | |
66 #endif | |
67 | |
68 // A minimized port of GtkThemeService into something that can provide colors | |
69 // and images for aura. | |
70 // | |
71 // TODO(erg): There's still a lot that needs ported or done for the first time: | |
72 // | |
73 // - Render and inject the omnibox background. | |
74 // - Make sure to test with a light on dark theme, too. | |
75 | |
76 // Work around a header bug: | |
77 // linux/debian_wheezy_i386-sysroot/usr/include/linux/stddef.h redefines NULL | |
78 // to 0, which breaks -Wsentinel. Get back the normal definition of NULL. | |
79 // TODO(thakis): Remove this once we update sysroots. | |
80 #define __need_NULL | |
81 #include <stddef.h> | |
82 | |
83 namespace libgtkui { | |
84 | |
85 namespace { | |
86 | |
87 class GtkButtonImageSource : public gfx::ImageSkiaSource { | |
88 public: | |
89 GtkButtonImageSource(const char* idr_string, gfx::Size size) | |
90 : width_(size.width()), height_(size.height()) { | |
91 is_blue_ = !!strstr(idr_string, "IDR_BLUE"); | |
92 focus_ = !!strstr(idr_string, "_FOCUSED_"); | |
93 | |
94 if (strstr(idr_string, "_DISABLED")) { | |
95 state_ = ui::NativeTheme::kDisabled; | |
96 } else if (strstr(idr_string, "_HOVER")) { | |
97 state_ = ui::NativeTheme::kHovered; | |
98 } else if (strstr(idr_string, "_PRESSED")) { | |
99 state_ = ui::NativeTheme::kPressed; | |
100 } else { | |
101 state_ = ui::NativeTheme::kNormal; | |
102 } | |
103 } | |
104 | |
105 ~GtkButtonImageSource() override {} | |
106 | |
107 gfx::ImageSkiaRep GetImageForScale(float scale) override { | |
108 int width = width_ * scale; | |
109 int height = height_ * scale; | |
110 | |
111 SkBitmap border; | |
112 border.allocN32Pixels(width, height); | |
113 border.eraseColor(0); | |
114 | |
115 // Create a temporary GTK button to snapshot | |
116 GtkWidget* window = gtk_offscreen_window_new(); | |
117 GtkWidget* button = gtk_toggle_button_new(); | |
118 | |
119 if (state_ == ui::NativeTheme::kPressed) | |
120 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), true); | |
121 else if (state_ == ui::NativeTheme::kDisabled) | |
122 gtk_widget_set_sensitive(button, false); | |
123 | |
124 gtk_widget_set_size_request(button, width, height); | |
125 gtk_container_add(GTK_CONTAINER(window), button); | |
126 | |
127 if (is_blue_) | |
128 TurnButtonBlue(button); | |
129 | |
130 gtk_widget_show_all(window); | |
131 | |
132 cairo_surface_t* surface = cairo_image_surface_create_for_data( | |
133 static_cast<unsigned char*>(border.getAddr(0, 0)), | |
134 CAIRO_FORMAT_ARGB32, width, height, width * 4); | |
135 cairo_t* cr = cairo_create(surface); | |
136 | |
137 #if GTK_MAJOR_VERSION == 2 | |
138 if (focus_) | |
139 GTK_WIDGET_SET_FLAGS(button, GTK_HAS_FOCUS); | |
140 | |
141 int w, h; | |
142 GdkPixmap* pixmap; | |
143 | |
144 { | |
145 // http://crbug.com/346740 | |
146 ANNOTATE_SCOPED_MEMORY_LEAK; | |
147 pixmap = gtk_widget_get_snapshot(button, NULL); | |
148 } | |
149 | |
150 gdk_drawable_get_size(GDK_DRAWABLE(pixmap), &w, &h); | |
151 GdkColormap* colormap = gdk_drawable_get_colormap(pixmap); | |
152 GdkPixbuf* pixbuf = gdk_pixbuf_get_from_drawable( | |
153 NULL, GDK_DRAWABLE(pixmap), colormap, 0, 0, 0, 0, w, h); | |
154 | |
155 gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); | |
156 cairo_paint(cr); | |
157 | |
158 g_object_unref(pixbuf); | |
159 g_object_unref(pixmap); | |
160 #else | |
161 gtk_widget_draw(button, cr); | |
162 | |
163 // There's probably a better way to do this | |
164 if (focus_) | |
165 gtk_render_focus(gtk_widget_get_style_context(button), cr, 0, 0, | |
166 width, height); | |
167 #endif | |
168 | |
169 cairo_destroy(cr); | |
170 cairo_surface_destroy(surface); | |
171 | |
172 gtk_widget_destroy(window); | |
173 | |
174 return gfx::ImageSkiaRep(border, scale); | |
175 } | |
176 | |
177 private: | |
178 bool is_blue_; | |
179 bool focus_; | |
180 ui::NativeTheme::State state_; | |
181 int width_; | |
182 int height_; | |
183 | |
184 DISALLOW_COPY_AND_ASSIGN(GtkButtonImageSource); | |
185 }; | |
186 | |
187 class GtkButtonPainter : public views::Painter { | |
188 public: | |
189 explicit GtkButtonPainter(std::string idr) : idr_(idr) {} | |
190 ~GtkButtonPainter() override {} | |
191 | |
192 gfx::Size GetMinimumSize() const override { return gfx::Size(); } | |
193 void Paint(gfx::Canvas* canvas, const gfx::Size& size) override { | |
194 gfx::ImageSkiaSource* source = new GtkButtonImageSource(idr_.c_str(), size); | |
195 gfx::ImageSkia image(source, 1); | |
196 canvas->DrawImageInt(image, 0, 0); | |
197 } | |
198 | |
199 private: | |
200 std::string idr_; | |
201 | |
202 DISALLOW_COPY_AND_ASSIGN(GtkButtonPainter); | |
203 }; | |
204 | |
205 struct GObjectDeleter { | |
206 void operator()(void* ptr) { | |
207 g_object_unref(ptr); | |
208 } | |
209 }; | |
210 struct GtkIconInfoDeleter { | |
211 void operator()(GtkIconInfo* ptr) { | |
212 G_GNUC_BEGIN_IGNORE_DEPRECATIONS | |
213 gtk_icon_info_free(ptr); | |
214 G_GNUC_END_IGNORE_DEPRECATIONS | |
215 } | |
216 }; | |
217 typedef std::unique_ptr<GIcon, GObjectDeleter> ScopedGIcon; | |
218 typedef std::unique_ptr<GtkIconInfo, GtkIconInfoDeleter> ScopedGtkIconInfo; | |
219 typedef std::unique_ptr<GdkPixbuf, GObjectDeleter> ScopedGdkPixbuf; | |
220 | |
221 // Prefix for app indicator ids | |
222 const char kAppIndicatorIdPrefix[] = "chrome_app_indicator_"; | |
223 | |
224 // Number of app indicators used (used as part of app-indicator id). | |
225 int indicators_count; | |
226 | |
227 // The unknown content type. | |
228 const char* kUnknownContentType = "application/octet-stream"; | |
229 | |
230 // TODO(erg): ThemeService has a whole interface just for reading default | |
231 // constants. Figure out what to do with that more long term; for now, just | |
232 // copy the constants themselves here. | |
233 // | |
234 // Default tints. | |
235 const color_utils::HSL kDefaultTintFrameIncognito = { -1, 0.2f, 0.35f }; | |
236 const color_utils::HSL kDefaultTintFrameIncognitoInactive = { -1, 0.3f, 0.6f }; | |
237 | |
238 #if GTK_MAJOR_VERSION == 3 | |
239 const color_utils::HSL kDefaultTintFrameInactive = { -1, -1, 0.75f }; | |
240 #endif // GTK_MAJOR_VERSION == 3 | |
241 | |
242 // Picks a button tint from a set of background colors. While | |
243 // |accent_color| will usually be the same color through a theme, this | |
244 // function will get called with the normal GtkLabel |text_color|/GtkWindow | |
245 // |background_color| pair and the GtkEntry |text_color|/|background_color| | |
246 // pair. While 3/4 of the time the resulting tint will be the same, themes that | |
247 // have a dark window background (with light text) and a light text entry (with | |
248 // dark text) will get better icons with this separated out. | |
249 void PickButtonTintFromColors(SkColor accent_color, | |
250 SkColor text_color, | |
251 SkColor background_color, | |
252 color_utils::HSL* tint) { | |
253 color_utils::HSL accent_tint, text_tint, background_tint; | |
254 color_utils::SkColorToHSL(accent_color, &accent_tint); | |
255 color_utils::SkColorToHSL(text_color, &text_tint); | |
256 color_utils::SkColorToHSL(background_color, &background_tint); | |
257 | |
258 // 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, | |
260 // 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 | |
262 // we should switch into a special grayscale mode. | |
263 int rb_diff = abs(static_cast<int>(SkColorGetR(accent_color)) - | |
264 static_cast<int>(SkColorGetB(accent_color))); | |
265 int rg_diff = abs(static_cast<int>(SkColorGetR(accent_color)) - | |
266 static_cast<int>(SkColorGetG(accent_color))); | |
267 int bg_diff = abs(static_cast<int>(SkColorGetB(accent_color)) - | |
268 static_cast<int>(SkColorGetG(accent_color))); | |
269 if (rb_diff < 10 && rg_diff < 10 && bg_diff < 10) { | |
270 // Our accent is white/gray/black. Only the luminance of the accent color | |
271 // matters. | |
272 tint->h = -1; | |
273 | |
274 // Use the saturation of the text. | |
275 tint->s = text_tint.s; | |
276 | |
277 // Use the luminance of the accent color UNLESS there isn't enough | |
278 // luminance contrast between the accent color and the base color. | |
279 if (fabs(accent_tint.l - background_tint.l) > 0.3) | |
280 tint->l = accent_tint.l; | |
281 else | |
282 tint->l = text_tint.l; | |
283 } else { | |
284 // Our accent is a color. | |
285 tint->h = accent_tint.h; | |
286 | |
287 // Don't modify the saturation; the amount of color doesn't matter. | |
288 tint->s = -1; | |
289 | |
290 // If the text wants us to darken the icon, don't change the luminance (the | |
291 // icons are already dark enough). Otherwise, lighten the icon by no more | |
292 // than 0.9 since we don't want a pure-white icon even if the text is pure | |
293 // white. | |
294 if (text_tint.l < 0.5) | |
295 tint->l = -1; | |
296 else if (text_tint.l <= 0.9) | |
297 tint->l = text_tint.l; | |
298 else | |
299 tint->l = 0.9; | |
300 } | |
301 } | |
302 | |
303 // Returns a gfx::FontRenderParams corresponding to GTK's configuration. | |
304 gfx::FontRenderParams GetGtkFontRenderParams() { | |
305 GtkSettings* gtk_settings = gtk_settings_get_default(); | |
306 CHECK(gtk_settings); | |
307 gint antialias = 0; | |
308 gint hinting = 0; | |
309 gchar* hint_style = NULL; | |
310 gchar* rgba = NULL; | |
311 g_object_get(gtk_settings, | |
312 "gtk-xft-antialias", &antialias, | |
313 "gtk-xft-hinting", &hinting, | |
314 "gtk-xft-hintstyle", &hint_style, | |
315 "gtk-xft-rgba", &rgba, | |
316 NULL); | |
317 | |
318 gfx::FontRenderParams params; | |
319 params.antialiasing = antialias != 0; | |
320 | |
321 if (hinting == 0 || !hint_style || strcmp(hint_style, "hintnone") == 0) { | |
322 params.hinting = gfx::FontRenderParams::HINTING_NONE; | |
323 } else if (strcmp(hint_style, "hintslight") == 0) { | |
324 params.hinting = gfx::FontRenderParams::HINTING_SLIGHT; | |
325 } else if (strcmp(hint_style, "hintmedium") == 0) { | |
326 params.hinting = gfx::FontRenderParams::HINTING_MEDIUM; | |
327 } else if (strcmp(hint_style, "hintfull") == 0) { | |
328 params.hinting = gfx::FontRenderParams::HINTING_FULL; | |
329 } else { | |
330 LOG(WARNING) << "Unexpected gtk-xft-hintstyle \"" << hint_style << "\""; | |
331 params.hinting = gfx::FontRenderParams::HINTING_NONE; | |
332 } | |
333 | |
334 if (!rgba || strcmp(rgba, "none") == 0) { | |
335 params.subpixel_rendering = gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE; | |
336 } else if (strcmp(rgba, "rgb") == 0) { | |
337 params.subpixel_rendering = gfx::FontRenderParams::SUBPIXEL_RENDERING_RGB; | |
338 } else if (strcmp(rgba, "bgr") == 0) { | |
339 params.subpixel_rendering = gfx::FontRenderParams::SUBPIXEL_RENDERING_BGR; | |
340 } else if (strcmp(rgba, "vrgb") == 0) { | |
341 params.subpixel_rendering = gfx::FontRenderParams::SUBPIXEL_RENDERING_VRGB; | |
342 } else if (strcmp(rgba, "vbgr") == 0) { | |
343 params.subpixel_rendering = gfx::FontRenderParams::SUBPIXEL_RENDERING_VBGR; | |
344 } else { | |
345 LOG(WARNING) << "Unexpected gtk-xft-rgba \"" << rgba << "\""; | |
346 params.subpixel_rendering = gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE; | |
347 } | |
348 | |
349 g_free(hint_style); | |
350 g_free(rgba); | |
351 | |
352 return params; | |
353 } | |
354 | |
355 double GetDPI() { | |
356 // Linux chrome currently does not support dynamic DPI changes. | |
357 // Keep using the first value detected. | |
358 static double dpi = -1.f; | |
359 if (dpi < 0) { | |
360 const double kDefaultDPI = 96; | |
361 | |
362 if (display::Display::HasForceDeviceScaleFactor()) { | |
363 dpi = display::Display::GetForcedDeviceScaleFactor() * kDefaultDPI; | |
364 return dpi; | |
365 } | |
366 | |
367 GtkSettings* gtk_settings = gtk_settings_get_default(); | |
368 CHECK(gtk_settings); | |
369 gint gtk_dpi = -1; | |
370 g_object_get(gtk_settings, "gtk-xft-dpi", >k_dpi, NULL); | |
371 | |
372 // GTK multiplies the DPI by 1024 before storing it. | |
373 dpi = (gtk_dpi > 0) ? gtk_dpi / 1024.0 : kDefaultDPI; | |
374 | |
375 // DSF is always >=1.0 on win/cros and lower DSF has never been considered | |
376 // nor tested. | |
377 dpi = std::max(kDefaultDPI, dpi); | |
378 } | |
379 return dpi; | |
380 } | |
381 | |
382 // Queries GTK for its font DPI setting and returns the number of pixels in a | |
383 // point. | |
384 double GetPixelsInPoint(float device_scale_factor) { | |
385 double dpi = GetDPI(); | |
386 | |
387 // Take device_scale_factor into account — if Chrome already scales the | |
388 // entire UI up by 2x, we should not also scale up. | |
389 dpi /= device_scale_factor; | |
390 | |
391 // There are 72 points in an inch. | |
392 return dpi / 72.0; | |
393 } | |
394 | |
395 views::LinuxUI::NonClientMiddleClickAction GetDefaultMiddleClickAction() { | |
396 std::unique_ptr<base::Environment> env(base::Environment::Create()); | |
397 switch (base::nix::GetDesktopEnvironment(env.get())) { | |
398 case base::nix::DESKTOP_ENVIRONMENT_KDE4: | |
399 case base::nix::DESKTOP_ENVIRONMENT_KDE5: | |
400 // Starting with KDE 4.4, windows' titlebars can be dragged with the | |
401 // middle mouse button to create tab groups. We don't support that in | |
402 // Chrome, but at least avoid lowering windows in response to middle | |
403 // clicks to avoid surprising users who expect the KDE behavior. | |
404 return views::LinuxUI::MIDDLE_CLICK_ACTION_NONE; | |
405 default: | |
406 return views::LinuxUI::MIDDLE_CLICK_ACTION_LOWER; | |
407 } | |
408 } | |
409 | |
410 } // namespace | |
411 | |
412 Gtk2UI::Gtk2UI() | |
413 : default_font_size_pixels_(0), | |
414 default_font_style_(gfx::Font::NORMAL), | |
415 default_font_weight_(gfx::Font::Weight::NORMAL), | |
416 middle_click_action_(GetDefaultMiddleClickAction()), | |
417 device_scale_factor_(1.0) { | |
418 GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess()); | |
419 } | |
420 | |
421 Gtk2UI::~Gtk2UI() {} | |
422 | |
423 void OnThemeChanged(GObject* obj, GParamSpec* param, Gtk2UI* gtkui) { | |
424 gtkui->ResetStyle(); | |
425 } | |
426 | |
427 void Gtk2UI::Initialize() { | |
428 GtkSettings* settings = gtk_settings_get_default(); | |
429 g_signal_connect_after(settings, | |
430 "notify::gtk-theme-name", | |
431 G_CALLBACK(OnThemeChanged), | |
432 this); | |
433 g_signal_connect_after(settings, | |
434 "notify::gtk-icon-theme-name", | |
435 G_CALLBACK(OnThemeChanged), | |
436 this); | |
437 | |
438 LoadGtkValues(); | |
439 | |
440 LoadCursorTheme(); | |
441 | |
442 #if defined(ENABLE_BASIC_PRINTING) | |
443 printing::PrintingContextLinux::SetCreatePrintDialogFunction( | |
444 &PrintDialogGtk2::CreatePrintDialog); | |
445 printing::PrintingContextLinux::SetPdfPaperSizeFunction( | |
446 &GetPdfPaperSizeDeviceUnitsGtk); | |
447 #endif | |
448 | |
449 #if defined(USE_GCONF) | |
450 // We must build this after GTK gets initialized. | |
451 gconf_listener_.reset(new GConfListener(this)); | |
452 #endif // defined(USE_GCONF) | |
453 | |
454 indicators_count = 0; | |
455 | |
456 // Instantiate the singleton instance of Gtk2EventLoop. | |
457 Gtk2EventLoop::GetInstance(); | |
458 } | |
459 | |
460 bool Gtk2UI::GetTint(int id, color_utils::HSL* tint) const { | |
461 switch (id) { | |
462 // Tints for which the cross-platform default is fine. Before adding new | |
463 // values here, specifically verify they work well on Linux. | |
464 case ThemeProperties::TINT_BACKGROUND_TAB: | |
465 // TODO(estade): Return something useful for TINT_BUTTONS so that chrome:// | |
466 // page icons are colored appropriately. | |
467 case ThemeProperties::TINT_BUTTONS: | |
468 break; | |
469 default: | |
470 // Assume any tints not specifically verified on Linux aren't usable. | |
471 // TODO(pkasting): Try to remove values from |colors_| that could just be | |
472 // added to the group above instead. | |
473 NOTREACHED(); | |
474 } | |
475 return false; | |
476 } | |
477 | |
478 bool Gtk2UI::GetColor(int id, SkColor* color) const { | |
479 ColorMap::const_iterator it = colors_.find(id); | |
480 if (it != colors_.end()) { | |
481 *color = it->second; | |
482 return true; | |
483 } | |
484 | |
485 return false; | |
486 } | |
487 | |
488 SkColor Gtk2UI::GetFocusRingColor() const { | |
489 return focus_ring_color_; | |
490 } | |
491 | |
492 SkColor Gtk2UI::GetThumbActiveColor() const { | |
493 return thumb_active_color_; | |
494 } | |
495 | |
496 SkColor Gtk2UI::GetThumbInactiveColor() const { | |
497 return thumb_inactive_color_; | |
498 } | |
499 | |
500 SkColor Gtk2UI::GetTrackColor() const { | |
501 return track_color_; | |
502 } | |
503 | |
504 SkColor Gtk2UI::GetActiveSelectionBgColor() const { | |
505 return active_selection_bg_color_; | |
506 } | |
507 | |
508 SkColor Gtk2UI::GetActiveSelectionFgColor() const { | |
509 return active_selection_fg_color_; | |
510 } | |
511 | |
512 SkColor Gtk2UI::GetInactiveSelectionBgColor() const { | |
513 return inactive_selection_bg_color_; | |
514 } | |
515 | |
516 SkColor Gtk2UI::GetInactiveSelectionFgColor() const { | |
517 return inactive_selection_fg_color_; | |
518 } | |
519 | |
520 double Gtk2UI::GetCursorBlinkInterval() const { | |
521 // From http://library.gnome.org/devel/gtk/unstable/GtkSettings.html, this is | |
522 // the default value for gtk-cursor-blink-time. | |
523 static const gint kGtkDefaultCursorBlinkTime = 1200; | |
524 | |
525 // Dividing GTK's cursor blink cycle time (in milliseconds) by this value | |
526 // yields an appropriate value for | |
527 // content::RendererPreferences::caret_blink_interval. This matches the | |
528 // logic in the WebKit GTK port. | |
529 static const double kGtkCursorBlinkCycleFactor = 2000.0; | |
530 | |
531 gint cursor_blink_time = kGtkDefaultCursorBlinkTime; | |
532 gboolean cursor_blink = TRUE; | |
533 g_object_get(gtk_settings_get_default(), | |
534 "gtk-cursor-blink-time", &cursor_blink_time, | |
535 "gtk-cursor-blink", &cursor_blink, | |
536 NULL); | |
537 return cursor_blink ? (cursor_blink_time / kGtkCursorBlinkCycleFactor) : 0.0; | |
538 } | |
539 | |
540 ui::NativeTheme* Gtk2UI::GetNativeTheme(aura::Window* window) const { | |
541 ui::NativeTheme* native_theme_override = NULL; | |
542 if (!native_theme_overrider_.is_null()) | |
543 native_theme_override = native_theme_overrider_.Run(window); | |
544 | |
545 if (native_theme_override) | |
546 return native_theme_override; | |
547 | |
548 return NativeThemeGtk2::instance(); | |
549 } | |
550 | |
551 void Gtk2UI::SetNativeThemeOverride(const NativeThemeGetter& callback) { | |
552 native_theme_overrider_ = callback; | |
553 } | |
554 | |
555 bool Gtk2UI::GetDefaultUsesSystemTheme() const { | |
556 std::unique_ptr<base::Environment> env(base::Environment::Create()); | |
557 | |
558 switch (base::nix::GetDesktopEnvironment(env.get())) { | |
559 case base::nix::DESKTOP_ENVIRONMENT_GNOME: | |
560 case base::nix::DESKTOP_ENVIRONMENT_UNITY: | |
561 case base::nix::DESKTOP_ENVIRONMENT_XFCE: | |
562 return true; | |
563 case base::nix::DESKTOP_ENVIRONMENT_KDE3: | |
564 case base::nix::DESKTOP_ENVIRONMENT_KDE4: | |
565 case base::nix::DESKTOP_ENVIRONMENT_KDE5: | |
566 case base::nix::DESKTOP_ENVIRONMENT_OTHER: | |
567 return false; | |
568 } | |
569 // Unless GetDesktopEnvironment() badly misbehaves, this should never happen. | |
570 NOTREACHED(); | |
571 return false; | |
572 } | |
573 | |
574 void Gtk2UI::SetDownloadCount(int count) const { | |
575 if (unity::IsRunning()) | |
576 unity::SetDownloadCount(count); | |
577 } | |
578 | |
579 void Gtk2UI::SetProgressFraction(float percentage) const { | |
580 if (unity::IsRunning()) | |
581 unity::SetProgressFraction(percentage); | |
582 } | |
583 | |
584 bool Gtk2UI::IsStatusIconSupported() const { | |
585 return true; | |
586 } | |
587 | |
588 std::unique_ptr<views::StatusIconLinux> Gtk2UI::CreateLinuxStatusIcon( | |
589 const gfx::ImageSkia& image, | |
590 const base::string16& tool_tip) const { | |
591 if (AppIndicatorIcon::CouldOpen()) { | |
592 ++indicators_count; | |
593 return std::unique_ptr<views::StatusIconLinux>(new AppIndicatorIcon( | |
594 base::StringPrintf("%s%d", kAppIndicatorIdPrefix, indicators_count), | |
595 image, tool_tip)); | |
596 } else { | |
597 return std::unique_ptr<views::StatusIconLinux>( | |
598 new Gtk2StatusIcon(image, tool_tip)); | |
599 } | |
600 } | |
601 | |
602 gfx::Image Gtk2UI::GetIconForContentType( | |
603 const std::string& content_type, | |
604 int size) const { | |
605 // This call doesn't take a reference. | |
606 GtkIconTheme* theme = gtk_icon_theme_get_default(); | |
607 | |
608 std::string content_types[] = { | |
609 content_type, kUnknownContentType | |
610 }; | |
611 | |
612 for (size_t i = 0; i < arraysize(content_types); ++i) { | |
613 ScopedGIcon icon(g_content_type_get_icon(content_types[i].c_str())); | |
614 ScopedGtkIconInfo icon_info( | |
615 gtk_icon_theme_lookup_by_gicon( | |
616 theme, icon.get(), size, | |
617 static_cast<GtkIconLookupFlags>(GTK_ICON_LOOKUP_FORCE_SIZE))); | |
618 if (!icon_info) | |
619 continue; | |
620 ScopedGdkPixbuf pixbuf(gtk_icon_info_load_icon(icon_info.get(), NULL)); | |
621 if (!pixbuf) | |
622 continue; | |
623 | |
624 SkBitmap bitmap = GdkPixbufToImageSkia(pixbuf.get()); | |
625 DCHECK_EQ(size, bitmap.width()); | |
626 DCHECK_EQ(size, bitmap.height()); | |
627 gfx::ImageSkia image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bitmap); | |
628 image_skia.MakeThreadSafe(); | |
629 return gfx::Image(image_skia); | |
630 } | |
631 return gfx::Image(); | |
632 } | |
633 | |
634 std::unique_ptr<views::Border> Gtk2UI::CreateNativeBorder( | |
635 views::LabelButton* owning_button, | |
636 std::unique_ptr<views::LabelButtonBorder> border) { | |
637 if (owning_button->GetNativeTheme() != NativeThemeGtk2::instance()) | |
638 return std::move(border); | |
639 | |
640 std::unique_ptr<views::LabelButtonAssetBorder> gtk_border( | |
641 new views::LabelButtonAssetBorder(owning_button->style())); | |
642 | |
643 gtk_border->set_insets(border->GetInsets()); | |
644 | |
645 static struct { | |
646 const char* idr; | |
647 const char* idr_blue; | |
648 bool focus; | |
649 views::Button::ButtonState state; | |
650 } const paintstate[] = { | |
651 { "IDR_BUTTON_NORMAL", | |
652 "IDR_BLUE_BUTTON_NORMAL", | |
653 false, views::Button::STATE_NORMAL, }, | |
654 { "IDR_BUTTON_HOVER", | |
655 "IDR_BLUE_BUTTON_HOVER", | |
656 false, views::Button::STATE_HOVERED, }, | |
657 { "IDR_BUTTON_PRESSED", | |
658 "IDR_BLUE_BUTTON_PRESSED", | |
659 false, views::Button::STATE_PRESSED, }, | |
660 { "IDR_BUTTON_DISABLED", | |
661 "IDR_BLUE_BUTTON_DISABLED", | |
662 false, views::Button::STATE_DISABLED, }, | |
663 | |
664 { "IDR_BUTTON_FOCUSED_NORMAL", | |
665 "IDR_BLUE_BUTTON_FOCUSED_NORMAL", | |
666 true, views::Button::STATE_NORMAL, }, | |
667 { "IDR_BUTTON_FOCUSED_HOVER", | |
668 "IDR_BLUE_BUTTON_FOCUSED_HOVER", | |
669 true, views::Button::STATE_HOVERED, }, | |
670 { "IDR_BUTTON_FOCUSED_PRESSED", | |
671 "IDR_BLUE_BUTTON_FOCUSED_PRESSED", | |
672 true, views::Button::STATE_PRESSED, }, | |
673 { "IDR_BUTTON_DISABLED", | |
674 "IDR_BLUE_BUTTON_DISABLED", | |
675 true, views::Button::STATE_DISABLED, }, | |
676 }; | |
677 | |
678 bool is_blue = | |
679 owning_button->GetClassName() == views::BlueButton::kViewClassName; | |
680 | |
681 for (unsigned i = 0; i < arraysize(paintstate); i++) { | |
682 views::Painter* painter = nullptr; | |
683 | |
684 if (border->PaintsButtonState(paintstate[i].focus, paintstate[i].state)) { | |
685 std::string idr = is_blue ? paintstate[i].idr_blue : paintstate[i].idr; | |
686 painter = new GtkButtonPainter(idr); | |
687 } | |
688 | |
689 gtk_border->SetPainter(paintstate[i].focus, paintstate[i].state, painter); | |
690 } | |
691 | |
692 return std::move(gtk_border); | |
693 } | |
694 | |
695 void Gtk2UI::AddWindowButtonOrderObserver( | |
696 views::WindowButtonOrderObserver* observer) { | |
697 if (!leading_buttons_.empty() || !trailing_buttons_.empty()) { | |
698 observer->OnWindowButtonOrderingChange(leading_buttons_, | |
699 trailing_buttons_); | |
700 } | |
701 | |
702 observer_list_.AddObserver(observer); | |
703 } | |
704 | |
705 void Gtk2UI::RemoveWindowButtonOrderObserver( | |
706 views::WindowButtonOrderObserver* observer) { | |
707 observer_list_.RemoveObserver(observer); | |
708 } | |
709 | |
710 void Gtk2UI::SetWindowButtonOrdering( | |
711 const std::vector<views::FrameButton>& leading_buttons, | |
712 const std::vector<views::FrameButton>& trailing_buttons) { | |
713 leading_buttons_ = leading_buttons; | |
714 trailing_buttons_ = trailing_buttons; | |
715 | |
716 for (views::WindowButtonOrderObserver& observer : observer_list_) | |
717 observer.OnWindowButtonOrderingChange(leading_buttons_, trailing_buttons_); | |
718 } | |
719 | |
720 void Gtk2UI::SetNonClientMiddleClickAction(NonClientMiddleClickAction action) { | |
721 middle_click_action_ = action; | |
722 } | |
723 | |
724 std::unique_ptr<ui::LinuxInputMethodContext> Gtk2UI::CreateInputMethodContext( | |
725 ui::LinuxInputMethodContextDelegate* delegate, | |
726 bool is_simple) const { | |
727 return std::unique_ptr<ui::LinuxInputMethodContext>( | |
728 new X11InputMethodContextImplGtk2(delegate, is_simple)); | |
729 } | |
730 | |
731 gfx::FontRenderParams Gtk2UI::GetDefaultFontRenderParams() const { | |
732 static gfx::FontRenderParams params = GetGtkFontRenderParams(); | |
733 return params; | |
734 } | |
735 | |
736 void Gtk2UI::GetDefaultFontDescription( | |
737 std::string* family_out, | |
738 int* size_pixels_out, | |
739 int* style_out, | |
740 gfx::Font::Weight* weight_out, | |
741 gfx::FontRenderParams* params_out) const { | |
742 *family_out = default_font_family_; | |
743 *size_pixels_out = default_font_size_pixels_; | |
744 *style_out = default_font_style_; | |
745 *weight_out = default_font_weight_; | |
746 *params_out = default_font_render_params_; | |
747 } | |
748 | |
749 ui::SelectFileDialog* Gtk2UI::CreateSelectFileDialog( | |
750 ui::SelectFileDialog::Listener* listener, | |
751 ui::SelectFilePolicy* policy) const { | |
752 return SelectFileDialogImpl::Create(listener, policy); | |
753 } | |
754 | |
755 bool Gtk2UI::UnityIsRunning() { | |
756 return unity::IsRunning(); | |
757 } | |
758 | |
759 views::LinuxUI::NonClientMiddleClickAction | |
760 Gtk2UI::GetNonClientMiddleClickAction() { | |
761 return middle_click_action_; | |
762 } | |
763 | |
764 void Gtk2UI::NotifyWindowManagerStartupComplete() { | |
765 // TODO(port) Implement this using _NET_STARTUP_INFO_BEGIN/_NET_STARTUP_INFO | |
766 // from http://standards.freedesktop.org/startup-notification-spec/ instead. | |
767 gdk_notify_startup_complete(); | |
768 } | |
769 | |
770 bool Gtk2UI::MatchEvent(const ui::Event& event, | |
771 std::vector<ui::TextEditCommandAuraLinux>* commands) { | |
772 // Ensure that we have a keyboard handler. | |
773 if (!key_bindings_handler_) | |
774 key_bindings_handler_.reset(new Gtk2KeyBindingsHandler); | |
775 | |
776 return key_bindings_handler_->MatchEvent(event, commands); | |
777 } | |
778 | |
779 void Gtk2UI::SetScrollbarColors() { | |
780 thumb_active_color_ = SkColorSetRGB(244, 244, 244); | |
781 thumb_inactive_color_ = SkColorSetRGB(234, 234, 234); | |
782 track_color_ = SkColorSetRGB(211, 211, 211); | |
783 | |
784 NativeThemeGtk2::instance()->GetChromeStyleColor( | |
785 "scrollbar-slider-prelight-color", &thumb_active_color_); | |
786 NativeThemeGtk2::instance()->GetChromeStyleColor( | |
787 "scrollbar-slider-normal-color", &thumb_inactive_color_); | |
788 NativeThemeGtk2::instance()->GetChromeStyleColor("scrollbar-trough-color", | |
789 &track_color_); | |
790 } | |
791 | |
792 void Gtk2UI::LoadGtkValues() { | |
793 // TODO(erg): GtkThemeService had a comment here about having to muck with | |
794 // the raw Prefs object to remove prefs::kCurrentThemeImages or else we'd | |
795 // regress startup time. Figure out how to do that when we can't access the | |
796 // prefs system from here. | |
797 | |
798 NativeThemeGtk2* theme = NativeThemeGtk2::instance(); | |
799 | |
800 SkColor toolbar_color = | |
801 theme->GetSystemColor(ui::NativeTheme::kColorId_DialogBackground); | |
802 SkColor label_color = | |
803 theme->GetSystemColor(ui::NativeTheme::kColorId_LabelEnabledColor); | |
804 | |
805 colors_[ThemeProperties::COLOR_CONTROL_BACKGROUND] = toolbar_color; | |
806 colors_[ThemeProperties::COLOR_TOOLBAR] = toolbar_color; | |
807 | |
808 colors_[ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON] = | |
809 color_utils::DeriveDefaultIconColor(label_color); | |
810 | |
811 colors_[ThemeProperties::COLOR_TAB_TEXT] = label_color; | |
812 colors_[ThemeProperties::COLOR_BOOKMARK_TEXT] = label_color; | |
813 colors_[ThemeProperties::COLOR_BACKGROUND_TAB_TEXT] = | |
814 color_utils::BlendTowardOppositeLuma(label_color, 50); | |
815 | |
816 UpdateDefaultFont(); | |
817 | |
818 // Build the various icon tints. | |
819 GetNormalButtonTintHSL(&button_tint_); | |
820 GetNormalEntryForegroundHSL(&entry_tint_); | |
821 GetSelectedEntryForegroundHSL(&selected_entry_tint_); | |
822 | |
823 // We pick the text and background colors for the NTP out of the colors for a | |
824 // GtkEntry. We do this because GtkEntries background color is never the same | |
825 // as |toolbar_color|, is usually a white, and when it isn't a white, | |
826 // provides sufficient contrast to |toolbar_color|. Try this out with | |
827 // Darklooks, HighContrastInverse or ThinIce. | |
828 | |
829 SkColor ntp_background = | |
830 theme->GetSystemColor( | |
831 ui::NativeTheme::kColorId_TextfieldDefaultBackground); | |
832 SkColor ntp_foreground = | |
833 theme->GetSystemColor( | |
834 ui::NativeTheme::kColorId_TextfieldDefaultColor); | |
835 | |
836 colors_[ThemeProperties::COLOR_NTP_BACKGROUND] = ntp_background; | |
837 colors_[ThemeProperties::COLOR_NTP_TEXT] = ntp_foreground; | |
838 | |
839 // The NTP header is the color that surrounds the current active thumbnail on | |
840 // the NTP, and acts as the border of the "Recent Links" box. It would be | |
841 // awesome if they were separated so we could use GetBorderColor() for the | |
842 // border around the "Recent Links" section, but matching the frame color is | |
843 // more important. | |
844 | |
845 BuildFrameColors(); | |
846 SkColor frame_color = colors_[ThemeProperties::COLOR_FRAME]; | |
847 colors_[ThemeProperties::COLOR_NTP_HEADER] = frame_color; | |
848 colors_[ThemeProperties::COLOR_NTP_SECTION] = toolbar_color; | |
849 colors_[ThemeProperties::COLOR_NTP_SECTION_TEXT] = label_color; | |
850 | |
851 SkColor link_color = | |
852 theme->GetSystemColor(ui::NativeTheme::kColorId_LinkEnabled); | |
853 colors_[ThemeProperties::COLOR_NTP_LINK] = link_color; | |
854 colors_[ThemeProperties::COLOR_NTP_LINK_UNDERLINE] = link_color; | |
855 colors_[ThemeProperties::COLOR_NTP_SECTION_LINK] = link_color; | |
856 colors_[ThemeProperties::COLOR_NTP_SECTION_LINK_UNDERLINE] = link_color; | |
857 | |
858 // Generate the colors that we pass to WebKit. | |
859 focus_ring_color_ = frame_color; | |
860 | |
861 SetScrollbarColors(); | |
862 | |
863 // Some GTK themes only define the text selection colors on the GtkEntry | |
864 // class, so we need to use that for getting selection colors. | |
865 active_selection_bg_color_ = | |
866 theme->GetSystemColor( | |
867 ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused); | |
868 active_selection_fg_color_ = | |
869 theme->GetSystemColor( | |
870 ui::NativeTheme::kColorId_TextfieldSelectionColor); | |
871 inactive_selection_bg_color_ = | |
872 theme->GetSystemColor( | |
873 ui::NativeTheme::kColorId_TextfieldReadOnlyBackground); | |
874 inactive_selection_fg_color_ = | |
875 theme->GetSystemColor( | |
876 ui::NativeTheme::kColorId_TextfieldReadOnlyColor); | |
877 | |
878 colors_[ThemeProperties::COLOR_TAB_THROBBER_SPINNING] = | |
879 theme->GetSystemColor(ui::NativeTheme::kColorId_ThrobberSpinningColor); | |
880 colors_[ThemeProperties::COLOR_TAB_THROBBER_WAITING] = | |
881 theme->GetSystemColor(ui::NativeTheme::kColorId_ThrobberWaitingColor); | |
882 } | |
883 | |
884 void Gtk2UI::LoadCursorTheme() { | |
885 GtkSettings* settings = gtk_settings_get_default(); | |
886 | |
887 gchar* theme = nullptr; | |
888 gint size = 0; | |
889 g_object_get(settings, | |
890 "gtk-cursor-theme-name", &theme, | |
891 "gtk-cursor-theme-size", &size, | |
892 nullptr); | |
893 | |
894 if (theme) | |
895 XcursorSetTheme(gfx::GetXDisplay(), theme); | |
896 if (size) | |
897 XcursorSetDefaultSize(gfx::GetXDisplay(), size); | |
898 | |
899 g_free(theme); | |
900 } | |
901 | |
902 void Gtk2UI::BuildFrameColors() { | |
903 #if GTK_MAJOR_VERSION == 2 | |
904 NativeThemeGtk2* theme = NativeThemeGtk2::instance(); | |
905 color_utils::HSL kDefaultFrameShift = { -1, -1, 0.4 }; | |
906 SkColor frame_color = | |
907 theme->GetSystemColor(ui::NativeTheme::kColorId_WindowBackground); | |
908 frame_color = color_utils::HSLShift(frame_color, kDefaultFrameShift); | |
909 theme->GetChromeStyleColor("frame-color", &frame_color); | |
910 colors_[ThemeProperties::COLOR_FRAME] = frame_color; | |
911 | |
912 GtkStyle* style = gtk_rc_get_style(theme->GetWindow()); | |
913 SkColor temp_color = color_utils::HSLShift( | |
914 GdkColorToSkColor(style->bg[GTK_STATE_INSENSITIVE]), | |
915 kDefaultFrameShift); | |
916 theme->GetChromeStyleColor("inactive-frame-color", &temp_color); | |
917 colors_[ThemeProperties::COLOR_FRAME_INACTIVE] = temp_color; | |
918 | |
919 temp_color = color_utils::HSLShift( | |
920 frame_color, | |
921 kDefaultTintFrameIncognito); | |
922 theme->GetChromeStyleColor("incognito-frame-color", &temp_color); | |
923 colors_[ThemeProperties::COLOR_FRAME_INCOGNITO] = temp_color; | |
924 | |
925 temp_color = color_utils::HSLShift( | |
926 frame_color, | |
927 kDefaultTintFrameIncognitoInactive); | |
928 theme->GetChromeStyleColor("incognito-inactive-frame-color", &temp_color); | |
929 colors_[ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE] = temp_color; | |
930 #else | |
931 auto set_frame_color = [this](int color_id) { | |
932 // Render a GtkHeaderBar as our title bar, cropping out any curved edges | |
933 // on the left and right sides. Also remove the bottom border for good | |
934 // measure. | |
935 SkBitmap bitmap; | |
936 bitmap.allocN32Pixels(1, 1); | |
937 bitmap.eraseColor(0); | |
938 | |
939 static GtkWidget* menu = nullptr; | |
940 if (!menu) { | |
941 menu = gtk_menu_bar_new(); | |
942 gtk_widget_set_size_request(menu, 1, 1); | |
943 | |
944 GtkWidget* window = gtk_offscreen_window_new(); | |
945 gtk_container_add(GTK_CONTAINER(window), menu); | |
946 | |
947 gtk_widget_show_all(window); | |
948 } | |
949 | |
950 cairo_surface_t* surface = cairo_image_surface_create_for_data( | |
951 static_cast<unsigned char*>(bitmap.getAddr(0, 0)), CAIRO_FORMAT_ARGB32, | |
952 bitmap.width(), bitmap.height(), | |
953 cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, 1)); | |
954 cairo_t* cr = cairo_create(surface); | |
955 gtk_widget_draw(menu, cr); | |
956 cairo_destroy(cr); | |
957 cairo_surface_destroy(surface); | |
958 | |
959 switch (color_id) { | |
960 case ThemeProperties::COLOR_FRAME_INACTIVE: | |
961 bitmap = SkBitmapOperations::CreateHSLShiftedBitmap( | |
962 bitmap, kDefaultTintFrameInactive); | |
963 break; | |
964 case ThemeProperties::COLOR_FRAME_INCOGNITO: | |
965 bitmap = SkBitmapOperations::CreateHSLShiftedBitmap( | |
966 bitmap, kDefaultTintFrameIncognito); | |
967 break; | |
968 case ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE: | |
969 bitmap = SkBitmapOperations::CreateHSLShiftedBitmap( | |
970 bitmap, kDefaultTintFrameIncognitoInactive); | |
971 break; | |
972 } | |
973 | |
974 bitmap.lockPixels(); | |
975 colors_[color_id] = bitmap.getColor(0, 0); | |
976 bitmap.unlockPixels(); | |
977 }; | |
978 | |
979 set_frame_color(ThemeProperties::COLOR_FRAME); | |
980 set_frame_color(ThemeProperties::COLOR_FRAME_INACTIVE); | |
981 set_frame_color(ThemeProperties::COLOR_FRAME_INCOGNITO); | |
982 set_frame_color(ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE); | |
983 #endif | |
984 } | |
985 | |
986 void Gtk2UI::GetNormalButtonTintHSL(color_utils::HSL* tint) const { | |
987 NativeThemeGtk2* theme = NativeThemeGtk2::instance(); | |
988 | |
989 SkColor accent_color = | |
990 theme->GetSystemColor(ui::NativeTheme::kColorId_ProminentButtonColor); | |
991 SkColor text_color = | |
992 theme->GetSystemColor( | |
993 ui::NativeTheme::kColorId_LabelEnabledColor); | |
994 SkColor base_color = | |
995 theme->GetSystemColor(ui::NativeTheme::kColorId_DialogBackground); | |
996 | |
997 PickButtonTintFromColors(accent_color, text_color, base_color, tint); | |
998 } | |
999 | |
1000 void Gtk2UI::GetNormalEntryForegroundHSL(color_utils::HSL* tint) const { | |
1001 NativeThemeGtk2* theme = NativeThemeGtk2::instance(); | |
1002 | |
1003 SkColor accent_color = | |
1004 theme->GetSystemColor(ui::NativeTheme::kColorId_ProminentButtonColor); | |
1005 SkColor text_color = | |
1006 theme->GetSystemColor( | |
1007 ui::NativeTheme::kColorId_TextfieldDefaultColor); | |
1008 SkColor base_color = | |
1009 theme->GetSystemColor( | |
1010 ui::NativeTheme::kColorId_TextfieldDefaultBackground); | |
1011 | |
1012 PickButtonTintFromColors(accent_color, text_color, base_color, tint); | |
1013 } | |
1014 | |
1015 void Gtk2UI::GetSelectedEntryForegroundHSL(color_utils::HSL* tint) const { | |
1016 // The simplest of all the tints. We just use the selected text in the entry | |
1017 // since the icons tinted this way will only be displayed against | |
1018 // base[GTK_STATE_SELECTED]. | |
1019 SkColor color = | |
1020 NativeThemeGtk2::instance()->GetSystemColor( | |
1021 ui::NativeTheme::kColorId_TextfieldSelectionColor); | |
1022 | |
1023 color_utils::SkColorToHSL(color, tint); | |
1024 } | |
1025 | |
1026 void Gtk2UI::UpdateDefaultFont() { | |
1027 PangoContext* pc = gtk_widget_get_pango_context( | |
1028 NativeThemeGtk2::instance()->GetLabel()); | |
1029 const PangoFontDescription* desc = pango_context_get_font_description(pc); | |
1030 | |
1031 // Use gfx::FontRenderParams to select a family and determine the rendering | |
1032 // settings. | |
1033 gfx::FontRenderParamsQuery query; | |
1034 query.families = base::SplitString(pango_font_description_get_family(desc), | |
1035 ",", base::TRIM_WHITESPACE, | |
1036 base::SPLIT_WANT_ALL); | |
1037 | |
1038 if (pango_font_description_get_size_is_absolute(desc)) { | |
1039 // If the size is absolute, it's specified in Pango units. There are | |
1040 // PANGO_SCALE Pango units in a device unit (pixel). | |
1041 const int size_pixels = pango_font_description_get_size(desc) / PANGO_SCALE; | |
1042 default_font_size_pixels_ = size_pixels; | |
1043 query.pixel_size = size_pixels; | |
1044 } else { | |
1045 // Non-absolute sizes are in points (again scaled by PANGO_SIZE). | |
1046 // Round the value when converting to pixels to match GTK's logic. | |
1047 const double size_points = pango_font_description_get_size(desc) / | |
1048 static_cast<double>(PANGO_SCALE); | |
1049 default_font_size_pixels_ = static_cast<int>( | |
1050 GetPixelsInPoint(device_scale_factor_) * size_points + 0.5); | |
1051 query.point_size = static_cast<int>(size_points); | |
1052 } | |
1053 | |
1054 query.style = gfx::Font::NORMAL; | |
1055 query.weight = | |
1056 static_cast<gfx::Font::Weight>(pango_font_description_get_weight(desc)); | |
1057 // TODO(davemoore): What about PANGO_STYLE_OBLIQUE? | |
1058 if (pango_font_description_get_style(desc) == PANGO_STYLE_ITALIC) | |
1059 query.style |= gfx::Font::ITALIC; | |
1060 | |
1061 default_font_render_params_ = | |
1062 gfx::GetFontRenderParams(query, &default_font_family_); | |
1063 default_font_style_ = query.style; | |
1064 } | |
1065 | |
1066 void Gtk2UI::ResetStyle() { | |
1067 LoadGtkValues(); | |
1068 NativeThemeGtk2::instance()->NotifyObservers(); | |
1069 } | |
1070 | |
1071 void Gtk2UI::UpdateDeviceScaleFactor(float device_scale_factor) { | |
1072 device_scale_factor_ = device_scale_factor; | |
1073 UpdateDefaultFont(); | |
1074 } | |
1075 | |
1076 float Gtk2UI::GetDeviceScaleFactor() const { | |
1077 if (display::Display::HasForceDeviceScaleFactor()) | |
1078 return display::Display::GetForcedDeviceScaleFactor(); | |
1079 const int kCSSDefaultDPI = 96; | |
1080 const float scale = GetDPI() / kCSSDefaultDPI; | |
1081 | |
1082 // Blacklist scaling factors <130% (crbug.com/484400) and round | |
1083 // to 1 decimal to prevent rendering problems (crbug.com/485183). | |
1084 return scale < 1.3f ? 1.0f : roundf(scale * 10) / 10; | |
1085 } | |
1086 | |
1087 } // namespace libgtkui | |
1088 | |
1089 views::LinuxUI* BuildGtk2UI() { | |
1090 return new libgtkui::Gtk2UI; | |
1091 } | |
OLD | NEW |