Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* vim:expandtab:shiftwidth=4:tabstop=4:
3 : */
4 : /* This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 :
8 : // for strtod()
9 : #include <stdlib.h>
10 :
11 : #include "nsLookAndFeel.h"
12 :
13 : #include <gtk/gtk.h>
14 : #include <gdk/gdk.h>
15 :
16 : #include <pango/pango.h>
17 : #include <pango/pango-fontmap.h>
18 :
19 : #include <fontconfig/fontconfig.h>
20 : #include "gfxPlatformGtk.h"
21 : #include "ScreenHelperGTK.h"
22 :
23 : #include "gtkdrawing.h"
24 : #include "nsStyleConsts.h"
25 : #include "gfxFontConstants.h"
26 : #include "WidgetUtils.h"
27 :
28 : #include <dlfcn.h>
29 :
30 : #include "mozilla/gfx/2D.h"
31 :
32 : #if MOZ_WIDGET_GTK != 2
33 : #include <cairo-gobject.h>
34 : #include "WidgetStyleCache.h"
35 : #include "prenv.h"
36 : #endif
37 :
38 : using mozilla::LookAndFeel;
39 :
40 : #define GDK_COLOR_TO_NS_RGB(c) \
41 : ((nscolor) NS_RGB(c.red>>8, c.green>>8, c.blue>>8))
42 : #define GDK_RGBA_TO_NS_RGBA(c) \
43 : ((nscolor) NS_RGBA((int)((c).red*255), (int)((c).green*255), \
44 : (int)((c).blue*255), (int)((c).alpha*255)))
45 :
46 2 : nsLookAndFeel::nsLookAndFeel()
47 : : nsXPLookAndFeel(),
48 : #if (MOZ_WIDGET_GTK == 2)
49 : mStyle(nullptr),
50 : #endif
51 : mDefaultFontCached(false), mButtonFontCached(false),
52 : mFieldFontCached(false), mMenuFontCached(false),
53 2 : mInitialized(false)
54 : {
55 2 : }
56 :
57 0 : nsLookAndFeel::~nsLookAndFeel()
58 : {
59 : #if (MOZ_WIDGET_GTK == 2)
60 : g_object_unref(mStyle);
61 : #endif
62 0 : }
63 :
64 : #if MOZ_WIDGET_GTK != 2
65 : // Modifies color |*aDest| as if a pattern of color |aSource| was painted with
66 : // CAIRO_OPERATOR_OVER to a surface with color |*aDest|.
67 : static void
68 2 : ApplyColorOver(const GdkRGBA& aSource, GdkRGBA* aDest) {
69 2 : gdouble sourceCoef = aSource.alpha;
70 2 : gdouble destCoef = aDest->alpha * (1.0 - sourceCoef);
71 2 : gdouble resultAlpha = sourceCoef + destCoef;
72 2 : if (resultAlpha != 0.0) { // don't divide by zero
73 2 : destCoef /= resultAlpha;
74 2 : sourceCoef /= resultAlpha;
75 2 : aDest->red = sourceCoef * aSource.red + destCoef * aDest->red;
76 2 : aDest->green = sourceCoef * aSource.green + destCoef * aDest->green;
77 2 : aDest->blue = sourceCoef * aSource.blue + destCoef * aDest->blue;
78 2 : aDest->alpha = resultAlpha;
79 : }
80 2 : }
81 :
82 : static void
83 0 : GetLightAndDarkness(const GdkRGBA& aColor,
84 : double* aLightness, double* aDarkness)
85 : {
86 0 : double sum = aColor.red + aColor.green + aColor.blue;
87 0 : *aLightness = sum * aColor.alpha;
88 0 : *aDarkness = (3.0 - sum) * aColor.alpha;
89 0 : }
90 :
91 : static bool
92 0 : GetGradientColors(const GValue* aValue,
93 : GdkRGBA* aLightColor, GdkRGBA* aDarkColor)
94 : {
95 0 : if (!G_TYPE_CHECK_VALUE_TYPE(aValue, CAIRO_GOBJECT_TYPE_PATTERN))
96 0 : return false;
97 :
98 0 : auto pattern = static_cast<cairo_pattern_t*>(g_value_get_boxed(aValue));
99 0 : if (!pattern)
100 0 : return false;
101 :
102 : // Just picking the lightest and darkest colors as simple samples rather
103 : // than trying to blend, which could get messy if there are many stops.
104 0 : if (CAIRO_STATUS_SUCCESS !=
105 0 : cairo_pattern_get_color_stop_rgba(pattern, 0, nullptr, &aDarkColor->red,
106 : &aDarkColor->green, &aDarkColor->blue,
107 : &aDarkColor->alpha))
108 0 : return false;
109 :
110 : double maxLightness, maxDarkness;
111 0 : GetLightAndDarkness(*aDarkColor, &maxLightness, &maxDarkness);
112 0 : *aLightColor = *aDarkColor;
113 :
114 : GdkRGBA stop;
115 0 : for (int index = 1;
116 : CAIRO_STATUS_SUCCESS ==
117 0 : cairo_pattern_get_color_stop_rgba(pattern, index, nullptr,
118 : &stop.red, &stop.green,
119 : &stop.blue, &stop.alpha);
120 : ++index) {
121 : double lightness, darkness;
122 0 : GetLightAndDarkness(stop, &lightness, &darkness);
123 0 : if (lightness > maxLightness) {
124 0 : maxLightness = lightness;
125 0 : *aLightColor = stop;
126 : }
127 0 : if (darkness > maxDarkness) {
128 0 : maxDarkness = darkness;
129 0 : *aDarkColor = stop;
130 : }
131 : }
132 :
133 0 : return true;
134 : }
135 :
136 : static bool
137 2 : GetUnicoBorderGradientColors(GtkStyleContext* aContext,
138 : GdkRGBA* aLightColor, GdkRGBA* aDarkColor)
139 : {
140 : // Ubuntu 12.04 has GTK engine Unico-1.0.2, which overrides render_frame,
141 : // providing its own border code. Ubuntu 14.04 has
142 : // Unico-1.0.3+14.04.20140109, which does not override render_frame, and
143 : // so does not need special attention. The earlier Unico can be detected
144 : // by the -unico-border-gradient style property it registers.
145 : // gtk_style_properties_lookup_property() is checked first to avoid the
146 : // warning from gtk_style_context_get_property() when the property does
147 : // not exist. (gtk_render_frame() of GTK+ 3.16 no longer uses the
148 : // engine.)
149 2 : const char* propertyName = "-unico-border-gradient";
150 2 : if (!gtk_style_properties_lookup_property(propertyName, nullptr, nullptr))
151 2 : return false;
152 :
153 : // -unico-border-gradient is used only when the CSS node's engine is Unico.
154 : GtkThemingEngine* engine;
155 0 : GtkStateFlags state = gtk_style_context_get_state(aContext);
156 0 : gtk_style_context_get(aContext, state, "engine", &engine, nullptr);
157 0 : if (strcmp(g_type_name(G_TYPE_FROM_INSTANCE(engine)), "UnicoEngine") != 0)
158 0 : return false;
159 :
160 : // draw_border() of Unico engine uses -unico-border-gradient
161 : // in preference to border-color.
162 0 : GValue value = G_VALUE_INIT;
163 0 : gtk_style_context_get_property(aContext, propertyName, state, &value);
164 :
165 0 : bool result = GetGradientColors(&value, aLightColor, aDarkColor);
166 :
167 0 : g_value_unset(&value);
168 0 : return result;
169 : }
170 :
171 : // Sets |aLightColor| and |aDarkColor| to colors from |aContext|. Returns
172 : // true if |aContext| uses these colors to render a visible border.
173 : // If returning false, then the colors returned are a fallback from the
174 : // border-color value even though |aContext| does not use these colors to
175 : // render a border.
176 : static bool
177 2 : GetBorderColors(GtkStyleContext* aContext,
178 : GdkRGBA* aLightColor, GdkRGBA* aDarkColor)
179 : {
180 : // Determine whether the border on this style context is visible.
181 2 : GtkStateFlags state = gtk_style_context_get_state(aContext);
182 : GtkBorderStyle borderStyle;
183 : gtk_style_context_get(aContext, state, GTK_STYLE_PROPERTY_BORDER_STYLE,
184 2 : &borderStyle, nullptr);
185 4 : bool visible = borderStyle != GTK_BORDER_STYLE_NONE &&
186 4 : borderStyle != GTK_BORDER_STYLE_HIDDEN;
187 2 : if (visible) {
188 : // GTK has an initial value of zero for border-widths, and so themes
189 : // need to explicitly set border-widths to make borders visible.
190 : GtkBorder border;
191 2 : gtk_style_context_get_border(aContext, GTK_STATE_FLAG_NORMAL, &border);
192 4 : visible = border.top != 0 || border.right != 0 ||
193 2 : border.bottom != 0 || border.left != 0;
194 : }
195 :
196 4 : if (visible &&
197 2 : GetUnicoBorderGradientColors(aContext, aLightColor, aDarkColor))
198 0 : return true;
199 :
200 : // The initial value for the border-color is the foreground color, and so
201 : // this will usually return a color distinct from the background even if
202 : // there is no visible border detected.
203 2 : gtk_style_context_get_border_color(aContext, state, aDarkColor);
204 : // TODO GTK3 - update aLightColor
205 : // for GTK_BORDER_STYLE_INSET/OUTSET/GROVE/RIDGE border styles.
206 : // https://bugzilla.mozilla.org/show_bug.cgi?id=978172#c25
207 2 : *aLightColor = *aDarkColor;
208 2 : return visible;
209 : }
210 :
211 : static bool
212 2 : GetBorderColors(GtkStyleContext* aContext,
213 : nscolor* aLightColor, nscolor* aDarkColor)
214 : {
215 : GdkRGBA lightColor, darkColor;
216 2 : bool ret = GetBorderColors(aContext, &lightColor, &darkColor);
217 2 : *aLightColor = GDK_RGBA_TO_NS_RGBA(lightColor);
218 2 : *aDarkColor = GDK_RGBA_TO_NS_RGBA(darkColor);
219 2 : return ret;
220 : }
221 : #endif
222 :
223 : nsresult
224 54 : nsLookAndFeel::NativeGetColor(ColorID aID, nscolor& aColor)
225 : {
226 54 : EnsureInit();
227 :
228 : #if (MOZ_WIDGET_GTK == 3)
229 : GdkRGBA gdk_color;
230 : #endif
231 54 : nsresult res = NS_OK;
232 :
233 54 : switch (aID) {
234 : // These colors don't seem to be used for anything anymore in Mozilla
235 : // (except here at least TextSelectBackground and TextSelectForeground)
236 : // The CSS2 colors below are used.
237 : #if (MOZ_WIDGET_GTK == 2)
238 : case eColorID_WindowBackground:
239 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_NORMAL]);
240 : break;
241 : case eColorID_WindowForeground:
242 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_NORMAL]);
243 : break;
244 : case eColorID_WidgetBackground:
245 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
246 : break;
247 : case eColorID_WidgetForeground:
248 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_NORMAL]);
249 : break;
250 : case eColorID_WidgetSelectBackground:
251 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_SELECTED]);
252 : break;
253 : case eColorID_WidgetSelectForeground:
254 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_SELECTED]);
255 : break;
256 : #else
257 : case eColorID_WindowBackground:
258 : case eColorID_WidgetBackground:
259 : case eColorID_TextBackground:
260 : case eColorID_activecaption: // active window caption background
261 : case eColorID_appworkspace: // MDI background color
262 : case eColorID_background: // desktop background
263 : case eColorID_window:
264 : case eColorID_windowframe:
265 : case eColorID__moz_dialog:
266 : case eColorID__moz_combobox:
267 7 : aColor = sMozWindowBackground;
268 7 : break;
269 : case eColorID_WindowForeground:
270 : case eColorID_WidgetForeground:
271 : case eColorID_TextForeground:
272 : case eColorID_captiontext: // text in active window caption, size box, and scrollbar arrow box (!)
273 : case eColorID_windowtext:
274 : case eColorID__moz_dialogtext:
275 2 : aColor = sMozWindowText;
276 2 : break;
277 : case eColorID_WidgetSelectBackground:
278 : case eColorID_TextSelectBackground:
279 : case eColorID_IMESelectedRawTextBackground:
280 : case eColorID_IMESelectedConvertedTextBackground:
281 : case eColorID__moz_dragtargetzone:
282 : case eColorID__moz_cellhighlight:
283 : case eColorID__moz_html_cellhighlight:
284 : case eColorID_highlight: // preference selected item,
285 6 : aColor = sTextSelectedBackground;
286 6 : break;
287 : case eColorID_WidgetSelectForeground:
288 : case eColorID_TextSelectForeground:
289 : case eColorID_IMESelectedRawTextForeground:
290 : case eColorID_IMESelectedConvertedTextForeground:
291 : case eColorID_highlighttext:
292 : case eColorID__moz_cellhighlighttext:
293 : case eColorID__moz_html_cellhighlighttext:
294 6 : aColor = sTextSelectedText;
295 6 : break;
296 : #endif
297 : case eColorID_Widget3DHighlight:
298 0 : aColor = NS_RGB(0xa0,0xa0,0xa0);
299 0 : break;
300 : case eColorID_Widget3DShadow:
301 0 : aColor = NS_RGB(0x40,0x40,0x40);
302 0 : break;
303 : #if (MOZ_WIDGET_GTK == 2)
304 : case eColorID_TextBackground:
305 : // not used?
306 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_NORMAL]);
307 : break;
308 : case eColorID_TextForeground:
309 : // not used?
310 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_NORMAL]);
311 : break;
312 : case eColorID_TextSelectBackground:
313 : case eColorID_IMESelectedRawTextBackground:
314 : case eColorID_IMESelectedConvertedTextBackground:
315 : // still used
316 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_SELECTED]);
317 : break;
318 : case eColorID_TextSelectForeground:
319 : case eColorID_IMESelectedRawTextForeground:
320 : case eColorID_IMESelectedConvertedTextForeground:
321 : // still used
322 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_SELECTED]);
323 : break;
324 : #endif
325 : case eColorID_IMERawInputBackground:
326 : case eColorID_IMEConvertedTextBackground:
327 0 : aColor = NS_TRANSPARENT;
328 0 : break;
329 : case eColorID_IMERawInputForeground:
330 : case eColorID_IMEConvertedTextForeground:
331 0 : aColor = NS_SAME_AS_FOREGROUND_COLOR;
332 0 : break;
333 : case eColorID_IMERawInputUnderline:
334 : case eColorID_IMEConvertedTextUnderline:
335 0 : aColor = NS_SAME_AS_FOREGROUND_COLOR;
336 0 : break;
337 : case eColorID_IMESelectedRawTextUnderline:
338 : case eColorID_IMESelectedConvertedTextUnderline:
339 0 : aColor = NS_TRANSPARENT;
340 0 : break;
341 : case eColorID_SpellCheckerUnderline:
342 0 : aColor = NS_RGB(0xff, 0, 0);
343 0 : break;
344 :
345 : #if (MOZ_WIDGET_GTK == 2)
346 : // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
347 : case eColorID_activeborder:
348 : // active window border
349 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
350 : break;
351 : case eColorID_activecaption:
352 : // active window caption background
353 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
354 : break;
355 : case eColorID_appworkspace:
356 : // MDI background color
357 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
358 : break;
359 : case eColorID_background:
360 : // desktop background
361 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
362 : break;
363 : case eColorID_captiontext:
364 : // text in active window caption, size box, and scrollbar arrow box (!)
365 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_NORMAL]);
366 : break;
367 : case eColorID_graytext:
368 : // disabled text in windows, menus, etc.
369 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_INSENSITIVE]);
370 : break;
371 : case eColorID_highlight:
372 : // background of selected item
373 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_SELECTED]);
374 : break;
375 : case eColorID_highlighttext:
376 : // text of selected item
377 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_SELECTED]);
378 : break;
379 : case eColorID_inactiveborder:
380 : // inactive window border
381 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
382 : break;
383 : case eColorID_inactivecaption:
384 : // inactive window caption
385 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_INSENSITIVE]);
386 : break;
387 : case eColorID_inactivecaptiontext:
388 : // text in inactive window caption
389 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_INSENSITIVE]);
390 : break;
391 : #else
392 : // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
393 : case eColorID_activeborder: {
394 : // active window border
395 0 : GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_WINDOW);
396 : gtk_style_context_get_border_color(style,
397 0 : GTK_STATE_FLAG_NORMAL, &gdk_color);
398 0 : aColor = GDK_RGBA_TO_NS_RGBA(gdk_color);
399 0 : ReleaseStyleContext(style);
400 0 : break;
401 : }
402 : case eColorID_inactiveborder: {
403 : // inactive window border
404 0 : GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_WINDOW);
405 : gtk_style_context_get_border_color(style,
406 : GTK_STATE_FLAG_INSENSITIVE,
407 0 : &gdk_color);
408 0 : aColor = GDK_RGBA_TO_NS_RGBA(gdk_color);
409 0 : ReleaseStyleContext(style);
410 0 : break;
411 : }
412 : case eColorID_graytext: // disabled text in windows, menus, etc.
413 : case eColorID_inactivecaptiontext: // text in inactive window caption
414 2 : aColor = sMenuTextInactive;
415 2 : break;
416 : case eColorID_inactivecaption: {
417 : // inactive window caption
418 0 : GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_WINDOW);
419 : gtk_style_context_get_background_color(style,
420 : GTK_STATE_FLAG_INSENSITIVE,
421 0 : &gdk_color);
422 0 : aColor = GDK_RGBA_TO_NS_RGBA(gdk_color);
423 0 : ReleaseStyleContext(style);
424 0 : break;
425 : }
426 : #endif
427 : case eColorID_infobackground:
428 : // tooltip background color
429 0 : aColor = sInfoBackground;
430 0 : break;
431 : case eColorID_infotext:
432 : // tooltip text color
433 1 : aColor = sInfoText;
434 1 : break;
435 : case eColorID_menu:
436 : // menu background
437 1 : aColor = sMenuBackground;
438 1 : break;
439 : case eColorID_menutext:
440 : // menu text
441 1 : aColor = sMenuText;
442 1 : break;
443 : case eColorID_scrollbar:
444 : // scrollbar gray area
445 : #if (MOZ_WIDGET_GTK == 2)
446 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_ACTIVE]);
447 : #else
448 0 : aColor = sMozScrollbar;
449 : #endif
450 0 : break;
451 :
452 : case eColorID_threedlightshadow:
453 : // 3-D highlighted inner edge color
454 : // always same as background in GTK code
455 : case eColorID_threedface:
456 : case eColorID_buttonface:
457 : // 3-D face color
458 : #if (MOZ_WIDGET_GTK == 3)
459 4 : aColor = sMozWindowBackground;
460 : #else
461 : aColor = sButtonBackground;
462 : #endif
463 4 : break;
464 :
465 : case eColorID_buttontext:
466 : // text on push buttons
467 2 : aColor = sButtonText;
468 2 : break;
469 :
470 : case eColorID_buttonhighlight:
471 : // 3-D highlighted edge color
472 : case eColorID_threedhighlight:
473 : // 3-D highlighted outer edge color
474 2 : aColor = sFrameOuterLightBorder;
475 2 : break;
476 :
477 : case eColorID_buttonshadow:
478 : // 3-D shadow edge color
479 : case eColorID_threedshadow:
480 : // 3-D shadow inner edge color
481 2 : aColor = sFrameInnerDarkBorder;
482 2 : break;
483 :
484 : #if (MOZ_WIDGET_GTK == 2)
485 : case eColorID_threeddarkshadow:
486 : // 3-D shadow outer edge color
487 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->black);
488 : break;
489 :
490 : case eColorID_window:
491 : case eColorID_windowframe:
492 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
493 : break;
494 :
495 : case eColorID_windowtext:
496 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_NORMAL]);
497 : break;
498 :
499 : case eColorID__moz_eventreerow:
500 : case eColorID__moz_field:
501 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_NORMAL]);
502 : break;
503 : case eColorID__moz_fieldtext:
504 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_NORMAL]);
505 : break;
506 : case eColorID__moz_dialog:
507 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]);
508 : break;
509 : case eColorID__moz_dialogtext:
510 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_NORMAL]);
511 : break;
512 : case eColorID__moz_dragtargetzone:
513 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_SELECTED]);
514 : break;
515 : case eColorID__moz_buttondefault:
516 : // default button border color
517 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->black);
518 : break;
519 : case eColorID__moz_buttonhoverface:
520 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_PRELIGHT]);
521 : break;
522 : case eColorID__moz_buttonhovertext:
523 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_PRELIGHT]);
524 : break;
525 : case eColorID__moz_cellhighlight:
526 : case eColorID__moz_html_cellhighlight:
527 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_ACTIVE]);
528 : break;
529 : case eColorID__moz_cellhighlighttext:
530 : case eColorID__moz_html_cellhighlighttext:
531 : aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_ACTIVE]);
532 : break;
533 : #else
534 : case eColorID_threeddarkshadow:
535 : // Hardcode to black
536 1 : aColor = NS_RGB(0x00,0x00,0x00);
537 1 : break;
538 :
539 : case eColorID__moz_eventreerow:
540 : case eColorID__moz_field:
541 2 : aColor = sMozFieldBackground;
542 2 : break;
543 : case eColorID__moz_fieldtext:
544 2 : aColor = sMozFieldText;
545 2 : break;
546 : case eColorID__moz_buttondefault: {
547 : // default button border color
548 0 : GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_BUTTON);
549 : gtk_style_context_get_border_color(style,
550 0 : GTK_STATE_FLAG_NORMAL, &gdk_color);
551 0 : aColor = GDK_RGBA_TO_NS_RGBA(gdk_color);
552 0 : ReleaseStyleContext(style);
553 0 : break;
554 : }
555 : case eColorID__moz_buttonhoverface: {
556 2 : GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_BUTTON);
557 : gtk_style_context_get_background_color(style,
558 : GTK_STATE_FLAG_PRELIGHT,
559 2 : &gdk_color);
560 2 : aColor = GDK_RGBA_TO_NS_RGBA(gdk_color);
561 2 : ReleaseStyleContext(style);
562 2 : break;
563 : }
564 : case eColorID__moz_buttonhovertext:
565 2 : aColor = sButtonHoverText;
566 2 : break;
567 : #endif
568 : case eColorID__moz_menuhover:
569 1 : aColor = sMenuHover;
570 1 : break;
571 : case eColorID__moz_menuhovertext:
572 1 : aColor = sMenuHoverText;
573 1 : break;
574 : case eColorID__moz_oddtreerow:
575 1 : aColor = sOddCellBackground;
576 1 : break;
577 : case eColorID__moz_nativehyperlinktext:
578 1 : aColor = sNativeHyperLinkText;
579 1 : break;
580 : case eColorID__moz_comboboxtext:
581 2 : aColor = sComboBoxText;
582 2 : break;
583 : #if (MOZ_WIDGET_GTK == 2)
584 : case eColorID__moz_combobox:
585 : aColor = sComboBoxBackground;
586 : break;
587 : #endif
588 : case eColorID__moz_menubartext:
589 1 : aColor = sMenuBarText;
590 1 : break;
591 : case eColorID__moz_menubarhovertext:
592 1 : aColor = sMenuBarHoverText;
593 1 : break;
594 : case eColorID__moz_gtk_info_bar_text:
595 : #if (MOZ_WIDGET_GTK == 3)
596 1 : aColor = sInfoBarText;
597 : #else
598 : aColor = sInfoText;
599 : #endif
600 1 : break;
601 : default:
602 : /* default color is BLACK */
603 0 : aColor = 0;
604 0 : res = NS_ERROR_FAILURE;
605 0 : break;
606 : }
607 :
608 54 : return res;
609 : }
610 :
611 : #if (MOZ_WIDGET_GTK == 2)
612 : static void darken_gdk_color(GdkColor *src, GdkColor *dest)
613 : {
614 : gdouble red;
615 : gdouble green;
616 : gdouble blue;
617 :
618 : red = (gdouble) src->red / 65535.0;
619 : green = (gdouble) src->green / 65535.0;
620 : blue = (gdouble) src->blue / 65535.0;
621 :
622 : red *= 0.93;
623 : green *= 0.93;
624 : blue *= 0.93;
625 :
626 : dest->red = red * 65535.0;
627 : dest->green = green * 65535.0;
628 : dest->blue = blue * 65535.0;
629 : }
630 : #endif
631 :
632 8 : static int32_t CheckWidgetStyle(GtkWidget* aWidget, const char* aStyle, int32_t aResult) {
633 8 : gboolean value = FALSE;
634 8 : gtk_widget_style_get(aWidget, aStyle, &value, nullptr);
635 8 : return value ? aResult : 0;
636 : }
637 :
638 2 : static int32_t ConvertGTKStepperStyleToMozillaScrollArrowStyle(GtkWidget* aWidget)
639 : {
640 2 : if (!aWidget)
641 0 : return mozilla::LookAndFeel::eScrollArrowStyle_Single;
642 :
643 : return
644 2 : CheckWidgetStyle(aWidget, "has-backward-stepper",
645 2 : mozilla::LookAndFeel::eScrollArrow_StartBackward) |
646 2 : CheckWidgetStyle(aWidget, "has-forward-stepper",
647 2 : mozilla::LookAndFeel::eScrollArrow_EndForward) |
648 2 : CheckWidgetStyle(aWidget, "has-secondary-backward-stepper",
649 : mozilla::LookAndFeel::eScrollArrow_EndBackward) |
650 2 : CheckWidgetStyle(aWidget, "has-secondary-forward-stepper",
651 2 : mozilla::LookAndFeel::eScrollArrow_StartForward);
652 : }
653 :
654 : nsresult
655 937 : nsLookAndFeel::GetIntImpl(IntID aID, int32_t &aResult)
656 : {
657 937 : nsresult res = NS_OK;
658 :
659 : // Set these before they can get overrided in the nsXPLookAndFeel.
660 937 : switch (aID) {
661 : case eIntID_ScrollButtonLeftMouseButtonAction:
662 0 : aResult = 0;
663 0 : return NS_OK;
664 : case eIntID_ScrollButtonMiddleMouseButtonAction:
665 0 : aResult = 1;
666 0 : return NS_OK;
667 : case eIntID_ScrollButtonRightMouseButtonAction:
668 0 : aResult = 2;
669 0 : return NS_OK;
670 : default:
671 937 : break;
672 : }
673 :
674 937 : res = nsXPLookAndFeel::GetIntImpl(aID, aResult);
675 937 : if (NS_SUCCEEDED(res))
676 0 : return res;
677 937 : res = NS_OK;
678 :
679 : // We use delayed initialization by EnsureInit() here
680 : // to make sure mozilla::Preferences is available (Bug 115807).
681 : // eIntID_UseAccessibilityTheme is requested before user preferences
682 : // are read, and so EnsureInit(), which depends on preference values,
683 : // is deliberately delayed until required.
684 937 : switch (aID) {
685 : case eIntID_CaretBlinkTime:
686 : {
687 : GtkSettings *settings;
688 : gint blink_time;
689 : gboolean blink;
690 :
691 0 : settings = gtk_settings_get_default ();
692 : g_object_get (settings,
693 : "gtk-cursor-blink-time", &blink_time,
694 : "gtk-cursor-blink", &blink,
695 0 : nullptr);
696 :
697 0 : if (blink)
698 0 : aResult = (int32_t) blink_time;
699 : else
700 0 : aResult = 0;
701 0 : break;
702 : }
703 : case eIntID_CaretWidth:
704 0 : aResult = 1;
705 0 : break;
706 : case eIntID_ShowCaretDuringSelection:
707 28 : aResult = 0;
708 28 : break;
709 : case eIntID_SelectTextfieldsOnKeyFocus:
710 : {
711 : GtkWidget *entry;
712 : GtkSettings *settings;
713 : gboolean select_on_focus;
714 :
715 0 : entry = gtk_entry_new();
716 0 : g_object_ref_sink(entry);
717 0 : settings = gtk_widget_get_settings(entry);
718 : g_object_get(settings,
719 : "gtk-entry-select-on-focus",
720 : &select_on_focus,
721 0 : nullptr);
722 :
723 0 : if(select_on_focus)
724 0 : aResult = 1;
725 : else
726 0 : aResult = 0;
727 :
728 0 : gtk_widget_destroy(entry);
729 0 : g_object_unref(entry);
730 : }
731 0 : break;
732 : case eIntID_ScrollToClick:
733 : {
734 : GtkSettings *settings;
735 0 : gboolean warps_slider = FALSE;
736 :
737 0 : settings = gtk_settings_get_default ();
738 0 : if (g_object_class_find_property (G_OBJECT_GET_CLASS(settings),
739 : "gtk-primary-button-warps-slider")) {
740 : g_object_get (settings,
741 : "gtk-primary-button-warps-slider",
742 : &warps_slider,
743 0 : nullptr);
744 : }
745 :
746 0 : if (warps_slider)
747 0 : aResult = 1;
748 : else
749 0 : aResult = 0;
750 : }
751 0 : break;
752 : case eIntID_SubmenuDelay:
753 : {
754 : GtkSettings *settings;
755 : gint delay;
756 :
757 0 : settings = gtk_settings_get_default ();
758 0 : g_object_get (settings, "gtk-menu-popup-delay", &delay, nullptr);
759 0 : aResult = (int32_t) delay;
760 0 : break;
761 : }
762 : case eIntID_TooltipDelay:
763 : {
764 4 : aResult = 500;
765 4 : break;
766 : }
767 : case eIntID_MenusCanOverlapOSBar:
768 : // we want XUL popups to be able to overlap the task bar.
769 44 : aResult = 1;
770 44 : break;
771 : case eIntID_SkipNavigatingDisabledMenuItem:
772 0 : aResult = 1;
773 0 : break;
774 : case eIntID_DragThresholdX:
775 : case eIntID_DragThresholdY:
776 : {
777 0 : GtkWidget* box = gtk_hbox_new(FALSE, 5);
778 0 : gint threshold = 0;
779 0 : g_object_get(gtk_widget_get_settings(box),
780 : "gtk-dnd-drag-threshold", &threshold,
781 0 : nullptr);
782 0 : g_object_ref_sink(box);
783 :
784 0 : aResult = threshold;
785 : }
786 0 : break;
787 : case eIntID_ScrollArrowStyle: {
788 2 : GtkWidget* scrollbar = GetWidget(MOZ_GTK_SCROLLBAR_HORIZONTAL);
789 2 : aResult = ConvertGTKStepperStyleToMozillaScrollArrowStyle(scrollbar);
790 2 : break;
791 : }
792 : case eIntID_ScrollSliderStyle:
793 2 : aResult = eScrollThumbStyle_Proportional;
794 2 : break;
795 : case eIntID_TreeOpenDelay:
796 0 : aResult = 1000;
797 0 : break;
798 : case eIntID_TreeCloseDelay:
799 0 : aResult = 1000;
800 0 : break;
801 : case eIntID_TreeLazyScrollDelay:
802 0 : aResult = 150;
803 0 : break;
804 : case eIntID_TreeScrollDelay:
805 0 : aResult = 100;
806 0 : break;
807 : case eIntID_TreeScrollLinesMax:
808 0 : aResult = 3;
809 0 : break;
810 : case eIntID_DWMCompositor:
811 : case eIntID_WindowsClassic:
812 : case eIntID_WindowsDefaultTheme:
813 : case eIntID_WindowsThemeIdentifier:
814 : case eIntID_OperatingSystemVersionIdentifier:
815 6 : aResult = 0;
816 6 : res = NS_ERROR_NOT_IMPLEMENTED;
817 6 : break;
818 : case eIntID_TouchEnabled:
819 : #if MOZ_WIDGET_GTK == 3
820 2 : aResult = mozilla::widget::WidgetUtils::IsTouchDeviceSupportPresent();
821 2 : break;
822 : #else
823 : aResult = 0;
824 : res = NS_ERROR_NOT_IMPLEMENTED;
825 : #endif
826 : break;
827 : case eIntID_MacGraphiteTheme:
828 2 : aResult = 0;
829 2 : res = NS_ERROR_NOT_IMPLEMENTED;
830 2 : break;
831 : case eIntID_AlertNotificationOrigin:
832 0 : aResult = NS_ALERT_TOP;
833 0 : break;
834 : case eIntID_IMERawInputUnderlineStyle:
835 : case eIntID_IMEConvertedTextUnderlineStyle:
836 0 : aResult = NS_STYLE_TEXT_DECORATION_STYLE_SOLID;
837 0 : break;
838 : case eIntID_IMESelectedRawTextUnderlineStyle:
839 : case eIntID_IMESelectedConvertedTextUnderline:
840 0 : aResult = NS_STYLE_TEXT_DECORATION_STYLE_NONE;
841 0 : break;
842 : case eIntID_SpellCheckerUnderlineStyle:
843 0 : aResult = NS_STYLE_TEXT_DECORATION_STYLE_WAVY;
844 0 : break;
845 : case eIntID_MenuBarDrag:
846 2 : EnsureInit();
847 2 : aResult = sMenuSupportsDrag;
848 2 : break;
849 : case eIntID_ScrollbarButtonAutoRepeatBehavior:
850 0 : aResult = 1;
851 0 : break;
852 : case eIntID_SwipeAnimationEnabled:
853 2 : aResult = 0;
854 2 : break;
855 : case eIntID_ColorPickerAvailable:
856 2 : aResult = 1;
857 2 : break;
858 : case eIntID_ContextMenuOffsetVertical:
859 : case eIntID_ContextMenuOffsetHorizontal:
860 0 : aResult = 2;
861 0 : break;
862 : default:
863 841 : aResult = 0;
864 841 : res = NS_ERROR_FAILURE;
865 : }
866 :
867 937 : return res;
868 : }
869 :
870 : nsresult
871 0 : nsLookAndFeel::GetFloatImpl(FloatID aID, float &aResult)
872 : {
873 0 : nsresult res = NS_OK;
874 0 : res = nsXPLookAndFeel::GetFloatImpl(aID, aResult);
875 0 : if (NS_SUCCEEDED(res))
876 0 : return res;
877 0 : res = NS_OK;
878 :
879 0 : switch (aID) {
880 : case eFloatID_IMEUnderlineRelativeSize:
881 0 : aResult = 1.0f;
882 0 : break;
883 : case eFloatID_SpellCheckerUnderlineRelativeSize:
884 0 : aResult = 1.0f;
885 0 : break;
886 : case eFloatID_CaretAspectRatio:
887 0 : EnsureInit();
888 0 : aResult = sCaretRatio;
889 0 : break;
890 : default:
891 0 : aResult = -1.0;
892 0 : res = NS_ERROR_FAILURE;
893 : }
894 0 : return res;
895 : }
896 :
897 : static void
898 2 : GetSystemFontInfo(GtkWidget *aWidget,
899 : nsString *aFontName,
900 : gfxFontStyle *aFontStyle)
901 : {
902 2 : GtkSettings *settings = gtk_widget_get_settings(aWidget);
903 :
904 2 : aFontStyle->style = NS_FONT_STYLE_NORMAL;
905 :
906 : gchar *fontname;
907 2 : g_object_get(settings, "gtk-font-name", &fontname, nullptr);
908 :
909 : PangoFontDescription *desc;
910 2 : desc = pango_font_description_from_string(fontname);
911 :
912 2 : aFontStyle->systemFont = true;
913 :
914 2 : g_free(fontname);
915 :
916 2 : NS_NAMED_LITERAL_STRING(quote, "\"");
917 4 : NS_ConvertUTF8toUTF16 family(pango_font_description_get_family(desc));
918 2 : *aFontName = quote + family + quote;
919 :
920 2 : aFontStyle->weight = pango_font_description_get_weight(desc);
921 :
922 : // FIXME: Set aFontStyle->stretch correctly!
923 2 : aFontStyle->stretch = NS_FONT_STRETCH_NORMAL;
924 :
925 2 : float size = float(pango_font_description_get_size(desc)) / PANGO_SCALE;
926 :
927 : // |size| is now either pixels or pango-points (not Mozilla-points!)
928 :
929 2 : if (!pango_font_description_get_size_is_absolute(desc)) {
930 : // |size| is in pango-points, so convert to pixels.
931 2 : size *= float(gfxPlatformGtk::GetDPI()) / POINTS_PER_INCH_FLOAT;
932 : }
933 :
934 : // Scale fonts up on HiDPI displays.
935 : // This would be done automatically with cairo, but we manually manage
936 : // the display scale for platform consistency.
937 2 : size *= ScreenHelperGTK::GetGTKMonitorScaleFactor();
938 :
939 : // |size| is now pixels
940 :
941 2 : aFontStyle->size = size;
942 :
943 2 : pango_font_description_free(desc);
944 2 : }
945 :
946 : static void
947 2 : GetSystemFontInfo(LookAndFeel::FontID aID,
948 : nsString *aFontName,
949 : gfxFontStyle *aFontStyle)
950 : {
951 2 : if (aID == LookAndFeel::eFont_Widget) {
952 1 : GtkWidget *label = gtk_label_new("M");
953 1 : GtkWidget *parent = gtk_fixed_new();
954 1 : GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP);
955 :
956 1 : gtk_container_add(GTK_CONTAINER(parent), label);
957 1 : gtk_container_add(GTK_CONTAINER(window), parent);
958 :
959 1 : gtk_widget_ensure_style(label);
960 1 : GetSystemFontInfo(label, aFontName, aFontStyle);
961 1 : gtk_widget_destroy(window); // no unref, windows are different
962 :
963 1 : } else if (aID == LookAndFeel::eFont_Button) {
964 0 : GtkWidget *label = gtk_label_new("M");
965 0 : GtkWidget *parent = gtk_fixed_new();
966 0 : GtkWidget *button = gtk_button_new();
967 0 : GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP);
968 :
969 0 : gtk_container_add(GTK_CONTAINER(button), label);
970 0 : gtk_container_add(GTK_CONTAINER(parent), button);
971 0 : gtk_container_add(GTK_CONTAINER(window), parent);
972 :
973 0 : gtk_widget_ensure_style(label);
974 0 : GetSystemFontInfo(label, aFontName, aFontStyle);
975 0 : gtk_widget_destroy(window); // no unref, windows are different
976 :
977 1 : } else if (aID == LookAndFeel::eFont_Field) {
978 0 : GtkWidget *entry = gtk_entry_new();
979 0 : GtkWidget *parent = gtk_fixed_new();
980 0 : GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP);
981 :
982 0 : gtk_container_add(GTK_CONTAINER(parent), entry);
983 0 : gtk_container_add(GTK_CONTAINER(window), parent);
984 :
985 0 : gtk_widget_ensure_style(entry);
986 0 : GetSystemFontInfo(entry, aFontName, aFontStyle);
987 0 : gtk_widget_destroy(window); // no unref, windows are different
988 :
989 : } else {
990 1 : MOZ_ASSERT(aID == LookAndFeel::eFont_Menu, "unexpected font ID");
991 1 : GtkWidget *accel_label = gtk_accel_label_new("M");
992 1 : GtkWidget *menuitem = gtk_menu_item_new();
993 1 : GtkWidget *menu = gtk_menu_new();
994 1 : g_object_ref_sink(menu);
995 :
996 1 : gtk_container_add(GTK_CONTAINER(menuitem), accel_label);
997 1 : gtk_menu_shell_append((GtkMenuShell *)GTK_MENU(menu), menuitem);
998 :
999 1 : gtk_widget_ensure_style(accel_label);
1000 1 : GetSystemFontInfo(accel_label, aFontName, aFontStyle);
1001 1 : g_object_unref(menu);
1002 : }
1003 2 : }
1004 :
1005 : bool
1006 6 : nsLookAndFeel::GetFontImpl(FontID aID, nsString& aFontName,
1007 : gfxFontStyle& aFontStyle,
1008 : float aDevPixPerCSSPixel)
1009 : {
1010 6 : nsString *cachedFontName = nullptr;
1011 6 : gfxFontStyle *cachedFontStyle = nullptr;
1012 6 : bool *isCached = nullptr;
1013 :
1014 6 : switch (aID) {
1015 : case eFont_Menu: // css2
1016 : case eFont_PullDownMenu: // css3
1017 3 : cachedFontName = &mMenuFontName;
1018 3 : cachedFontStyle = &mMenuFontStyle;
1019 3 : isCached = &mMenuFontCached;
1020 3 : aID = eFont_Menu;
1021 3 : break;
1022 :
1023 : case eFont_Field: // css3
1024 : case eFont_List: // css3
1025 0 : cachedFontName = &mFieldFontName;
1026 0 : cachedFontStyle = &mFieldFontStyle;
1027 0 : isCached = &mFieldFontCached;
1028 0 : aID = eFont_Field;
1029 0 : break;
1030 :
1031 : case eFont_Button: // css3
1032 0 : cachedFontName = &mButtonFontName;
1033 0 : cachedFontStyle = &mButtonFontStyle;
1034 0 : isCached = &mButtonFontCached;
1035 0 : break;
1036 :
1037 : case eFont_Caption: // css2
1038 : case eFont_Icon: // css2
1039 : case eFont_MessageBox: // css2
1040 : case eFont_SmallCaption: // css2
1041 : case eFont_StatusBar: // css2
1042 : case eFont_Window: // css3
1043 : case eFont_Document: // css3
1044 : case eFont_Workspace: // css3
1045 : case eFont_Desktop: // css3
1046 : case eFont_Info: // css3
1047 : case eFont_Dialog: // css3
1048 : case eFont_Tooltips: // moz
1049 : case eFont_Widget: // moz
1050 3 : cachedFontName = &mDefaultFontName;
1051 3 : cachedFontStyle = &mDefaultFontStyle;
1052 3 : isCached = &mDefaultFontCached;
1053 3 : aID = eFont_Widget;
1054 3 : break;
1055 : }
1056 :
1057 6 : if (!*isCached) {
1058 2 : GetSystemFontInfo(aID, cachedFontName, cachedFontStyle);
1059 2 : *isCached = true;
1060 : }
1061 :
1062 6 : aFontName = *cachedFontName;
1063 6 : aFontStyle = *cachedFontStyle;
1064 6 : return true;
1065 : }
1066 :
1067 : void
1068 56 : nsLookAndFeel::EnsureInit()
1069 : {
1070 : GdkColor colorValue;
1071 : GdkColor *colorValuePtr;
1072 :
1073 56 : if (mInitialized)
1074 54 : return;
1075 2 : mInitialized = true;
1076 :
1077 : #if (MOZ_WIDGET_GTK == 2)
1078 : NS_ASSERTION(!mStyle, "already initialized");
1079 : // GtkInvisibles come with a refcount that is not floating
1080 : // (since their initialization code calls g_object_ref_sink) and
1081 : // their destroy code releases that reference (which means they
1082 : // have to be explicitly destroyed, since calling unref enough
1083 : // to cause destruction would lead to *another* unref).
1084 : // However, this combination means that it's actually still ok
1085 : // to use the normal pattern, which is to g_object_ref_sink
1086 : // after construction, and then destroy *and* unref when we're
1087 : // done. (Though we could skip the g_object_ref_sink and the
1088 : // corresponding g_object_unref, but that's particular to
1089 : // GtkInvisibles and GtkWindows.)
1090 : GtkWidget *widget = gtk_invisible_new();
1091 : g_object_ref_sink(widget); // effectively g_object_ref (see above)
1092 :
1093 : gtk_widget_ensure_style(widget);
1094 : mStyle = gtk_style_copy(gtk_widget_get_style(widget));
1095 :
1096 : gtk_widget_destroy(widget);
1097 : g_object_unref(widget);
1098 :
1099 : // tooltip foreground and background
1100 : GtkStyle *style = gtk_rc_get_style_by_paths(gtk_settings_get_default(),
1101 : "gtk-tooltips", "GtkWindow",
1102 : GTK_TYPE_WINDOW);
1103 : if (style) {
1104 : sInfoBackground = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_NORMAL]);
1105 : sInfoText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]);
1106 : }
1107 :
1108 : // menu foreground & menu background
1109 : GtkWidget *accel_label = gtk_accel_label_new("M");
1110 : GtkWidget *menuitem = gtk_menu_item_new();
1111 : GtkWidget *menu = gtk_menu_new();
1112 :
1113 : g_object_ref_sink(menu);
1114 :
1115 : gtk_container_add(GTK_CONTAINER(menuitem), accel_label);
1116 : gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1117 :
1118 : gtk_widget_set_style(accel_label, nullptr);
1119 : gtk_widget_set_style(menu, nullptr);
1120 : gtk_widget_realize(menu);
1121 : gtk_widget_realize(accel_label);
1122 :
1123 : style = gtk_widget_get_style(accel_label);
1124 : if (style) {
1125 : sMenuText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]);
1126 : }
1127 :
1128 : style = gtk_widget_get_style(menu);
1129 : if (style) {
1130 : sMenuBackground = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_NORMAL]);
1131 : }
1132 :
1133 : style = gtk_widget_get_style(menuitem);
1134 : if (style) {
1135 : sMenuHover = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_PRELIGHT]);
1136 : sMenuHoverText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_PRELIGHT]);
1137 : }
1138 :
1139 : g_object_unref(menu);
1140 : #else
1141 : GdkRGBA color;
1142 : GtkStyleContext *style;
1143 :
1144 : // Gtk manages a screen's CSS in the settings object so we
1145 : // ask Gtk to create it explicitly. Otherwise we may end up
1146 : // with wrong color theme, see Bug 972382
1147 2 : GtkSettings *settings = gtk_settings_get_for_screen(gdk_screen_get_default());
1148 :
1149 : // Dark themes interacts poorly with widget styling (see bug 1216658).
1150 : // We disable dark themes by default for all processes (chrome, web content)
1151 : // but allow user to overide it by prefs.
1152 2 : const gchar* dark_setting = "gtk-application-prefer-dark-theme";
1153 : gboolean darkThemeDefault;
1154 2 : g_object_get(settings, dark_setting, &darkThemeDefault, nullptr);
1155 :
1156 : // To avoid triggering reload of theme settings unnecessarily, only set the
1157 : // setting when necessary.
1158 2 : if (darkThemeDefault) {
1159 : bool allowDarkTheme;
1160 0 : if (XRE_IsContentProcess()) {
1161 : allowDarkTheme =
1162 : mozilla::Preferences::GetBool("widget.content.allow-gtk-dark-theme",
1163 0 : false);
1164 : } else {
1165 0 : allowDarkTheme = (PR_GetEnv("MOZ_ALLOW_GTK_DARK_THEME") != nullptr) ||
1166 0 : mozilla::Preferences::GetBool("widget.chrome.allow-gtk-dark-theme",
1167 : false);
1168 : }
1169 0 : if (!allowDarkTheme) {
1170 0 : g_object_set(settings, dark_setting, FALSE, nullptr);
1171 : }
1172 : }
1173 :
1174 : // Allow content Gtk theme override by pref, it's useful when styled Gtk+
1175 : // widgets break web content.
1176 2 : if (XRE_IsContentProcess()) {
1177 : auto contentThemeName =
1178 2 : mozilla::Preferences::GetCString("widget.content.gtk-theme-override");
1179 1 : if (!contentThemeName.IsEmpty()) {
1180 0 : g_object_set(settings, "gtk-theme-name", contentThemeName.get(), nullptr);
1181 : }
1182 : }
1183 :
1184 : // Scrollbar colors
1185 2 : style = ClaimStyleContext(MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL);
1186 2 : gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
1187 2 : sMozScrollbar = GDK_RGBA_TO_NS_RGBA(color);
1188 2 : ReleaseStyleContext(style);
1189 :
1190 : // Window colors
1191 2 : style = ClaimStyleContext(MOZ_GTK_WINDOW);
1192 2 : gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
1193 2 : sMozWindowBackground = GDK_RGBA_TO_NS_RGBA(color);
1194 2 : gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
1195 2 : sMozWindowText = GDK_RGBA_TO_NS_RGBA(color);
1196 2 : ReleaseStyleContext(style);
1197 :
1198 : // tooltip foreground and background
1199 2 : style = ClaimStyleContext(MOZ_GTK_TOOLTIP);
1200 2 : gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
1201 2 : sInfoBackground = GDK_RGBA_TO_NS_RGBA(color);
1202 2 : ReleaseStyleContext(style);
1203 :
1204 2 : style = ClaimStyleContext(MOZ_GTK_TOOLTIP_BOX_LABEL);
1205 2 : gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
1206 2 : sInfoText = GDK_RGBA_TO_NS_RGBA(color);
1207 2 : ReleaseStyleContext(style);
1208 :
1209 2 : style = ClaimStyleContext(MOZ_GTK_MENUITEM);
1210 : {
1211 : GtkStyleContext* accelStyle =
1212 2 : CreateStyleForWidget(gtk_accel_label_new("M"), style);
1213 2 : gtk_style_context_get_color(accelStyle, GTK_STATE_FLAG_NORMAL, &color);
1214 2 : sMenuText = GDK_RGBA_TO_NS_RGBA(color);
1215 2 : gtk_style_context_get_color(accelStyle, GTK_STATE_FLAG_INSENSITIVE, &color);
1216 2 : sMenuTextInactive = GDK_RGBA_TO_NS_RGBA(color);
1217 2 : g_object_unref(accelStyle);
1218 : }
1219 2 : ReleaseStyleContext(style);
1220 :
1221 2 : style = ClaimStyleContext(MOZ_GTK_MENUPOPUP);
1222 2 : gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
1223 2 : sMenuBackground = GDK_RGBA_TO_NS_RGBA(color);
1224 2 : ReleaseStyleContext(style);
1225 :
1226 2 : style = ClaimStyleContext(MOZ_GTK_MENUITEM);
1227 2 : gtk_style_context_get_background_color(style, GTK_STATE_FLAG_PRELIGHT, &color);
1228 2 : sMenuHover = GDK_RGBA_TO_NS_RGBA(color);
1229 2 : gtk_style_context_get_color(style, GTK_STATE_FLAG_PRELIGHT, &color);
1230 2 : sMenuHoverText = GDK_RGBA_TO_NS_RGBA(color);
1231 2 : ReleaseStyleContext(style);
1232 : #endif
1233 :
1234 : // button styles
1235 2 : GtkWidget *parent = gtk_fixed_new();
1236 2 : GtkWidget *button = gtk_button_new();
1237 2 : GtkWidget *label = gtk_label_new("M");
1238 : #if (MOZ_WIDGET_GTK == 2)
1239 : GtkWidget *combobox = gtk_combo_box_new();
1240 : GtkWidget *comboboxLabel = gtk_label_new("M");
1241 : gtk_container_add(GTK_CONTAINER(combobox), comboboxLabel);
1242 : #endif
1243 2 : GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP);
1244 2 : GtkWidget *treeView = gtk_tree_view_new();
1245 2 : GtkWidget *linkButton = gtk_link_button_new("http://example.com/");
1246 2 : GtkWidget *menuBar = gtk_menu_bar_new();
1247 2 : GtkWidget *menuBarItem = gtk_menu_item_new();
1248 2 : GtkWidget *entry = gtk_entry_new();
1249 2 : GtkWidget *textView = gtk_text_view_new();
1250 :
1251 2 : gtk_container_add(GTK_CONTAINER(button), label);
1252 2 : gtk_container_add(GTK_CONTAINER(parent), button);
1253 2 : gtk_container_add(GTK_CONTAINER(parent), treeView);
1254 2 : gtk_container_add(GTK_CONTAINER(parent), linkButton);
1255 : #if (MOZ_WIDGET_GTK == 2)
1256 : gtk_container_add(GTK_CONTAINER(parent), combobox);
1257 : #endif
1258 2 : gtk_container_add(GTK_CONTAINER(parent), menuBar);
1259 2 : gtk_menu_shell_append(GTK_MENU_SHELL(menuBar), menuBarItem);
1260 2 : gtk_container_add(GTK_CONTAINER(window), parent);
1261 2 : gtk_container_add(GTK_CONTAINER(parent), entry);
1262 2 : gtk_container_add(GTK_CONTAINER(parent), textView);
1263 :
1264 : #if (MOZ_WIDGET_GTK == 2)
1265 : gtk_widget_set_style(button, nullptr);
1266 : gtk_widget_set_style(label, nullptr);
1267 : gtk_widget_set_style(treeView, nullptr);
1268 : gtk_widget_set_style(linkButton, nullptr);
1269 : gtk_widget_set_style(combobox, nullptr);
1270 : gtk_widget_set_style(comboboxLabel, nullptr);
1271 : gtk_widget_set_style(menuBar, nullptr);
1272 : gtk_widget_set_style(entry, nullptr);
1273 :
1274 : gtk_widget_realize(button);
1275 : gtk_widget_realize(label);
1276 : gtk_widget_realize(treeView);
1277 : gtk_widget_realize(linkButton);
1278 : gtk_widget_realize(combobox);
1279 : gtk_widget_realize(comboboxLabel);
1280 : gtk_widget_realize(menuBar);
1281 : gtk_widget_realize(entry);
1282 :
1283 : style = gtk_widget_get_style(label);
1284 : if (style) {
1285 : sButtonText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]);
1286 : }
1287 :
1288 : style = gtk_widget_get_style(comboboxLabel);
1289 : if (style) {
1290 : sComboBoxText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]);
1291 : }
1292 : style = gtk_widget_get_style(combobox);
1293 : if (style) {
1294 : sComboBoxBackground = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_NORMAL]);
1295 : }
1296 :
1297 : style = gtk_widget_get_style(menuBar);
1298 : if (style) {
1299 : sMenuBarText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]);
1300 : sMenuBarHoverText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_SELECTED]);
1301 : }
1302 :
1303 : // GTK's guide to fancy odd row background colors:
1304 : // 1) Check if a theme explicitly defines an odd row color
1305 : // 2) If not, check if it defines an even row color, and darken it
1306 : // slightly by a hardcoded value (gtkstyle.c)
1307 : // 3) If neither are defined, take the base background color and
1308 : // darken that by a hardcoded value
1309 : colorValuePtr = nullptr;
1310 : gtk_widget_style_get(treeView,
1311 : "odd-row-color", &colorValuePtr,
1312 : nullptr);
1313 :
1314 : if (colorValuePtr) {
1315 : colorValue = *colorValuePtr;
1316 : } else {
1317 : gtk_widget_style_get(treeView,
1318 : "even-row-color", &colorValuePtr,
1319 : nullptr);
1320 : if (colorValuePtr)
1321 : darken_gdk_color(colorValuePtr, &colorValue);
1322 : else
1323 : darken_gdk_color(&treeView->style->base[GTK_STATE_NORMAL], &colorValue);
1324 : }
1325 :
1326 : sOddCellBackground = GDK_COLOR_TO_NS_RGB(colorValue);
1327 : if (colorValuePtr)
1328 : gdk_color_free(colorValuePtr);
1329 :
1330 : style = gtk_widget_get_style(button);
1331 : if (style) {
1332 : sButtonBackground = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_NORMAL]);
1333 : sFrameOuterLightBorder =
1334 : GDK_COLOR_TO_NS_RGB(style->light[GTK_STATE_NORMAL]);
1335 : sFrameInnerDarkBorder =
1336 : GDK_COLOR_TO_NS_RGB(style->dark[GTK_STATE_NORMAL]);
1337 : }
1338 : #else
1339 : // Text colors
1340 : GdkRGBA bgColor;
1341 : // If the text window background is translucent, then the background of
1342 : // the textview root node is visible.
1343 2 : style = ClaimStyleContext(MOZ_GTK_TEXT_VIEW);
1344 : gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL,
1345 2 : &bgColor);
1346 2 : ReleaseStyleContext(style);
1347 :
1348 2 : style = ClaimStyleContext(MOZ_GTK_TEXT_VIEW_TEXT);
1349 : gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL,
1350 2 : &color);
1351 2 : ApplyColorOver(color, &bgColor);
1352 2 : sMozFieldBackground = GDK_RGBA_TO_NS_RGBA(bgColor);
1353 2 : gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
1354 2 : sMozFieldText = GDK_RGBA_TO_NS_RGBA(color);
1355 :
1356 : // Selected text and background
1357 : gtk_style_context_get_background_color(style,
1358 : static_cast<GtkStateFlags>(GTK_STATE_FLAG_FOCUSED|GTK_STATE_FLAG_SELECTED),
1359 2 : &color);
1360 2 : sTextSelectedBackground = GDK_RGBA_TO_NS_RGBA(color);
1361 : gtk_style_context_get_color(style,
1362 : static_cast<GtkStateFlags>(GTK_STATE_FLAG_FOCUSED|GTK_STATE_FLAG_SELECTED),
1363 2 : &color);
1364 2 : sTextSelectedText = GDK_RGBA_TO_NS_RGBA(color);
1365 2 : ReleaseStyleContext(style);
1366 :
1367 : // Button text color
1368 2 : style = ClaimStyleContext(MOZ_GTK_BUTTON);
1369 : {
1370 : GtkStyleContext* labelStyle =
1371 2 : CreateStyleForWidget(gtk_label_new("M"), style);
1372 2 : gtk_style_context_get_color(labelStyle, GTK_STATE_FLAG_NORMAL, &color);
1373 2 : sButtonText = GDK_RGBA_TO_NS_RGBA(color);
1374 2 : gtk_style_context_get_color(labelStyle, GTK_STATE_FLAG_PRELIGHT, &color);
1375 2 : sButtonHoverText = GDK_RGBA_TO_NS_RGBA(color);
1376 2 : g_object_unref(labelStyle);
1377 : }
1378 2 : ReleaseStyleContext(style);
1379 :
1380 : // Combobox text color
1381 2 : style = ClaimStyleContext(MOZ_GTK_COMBOBOX_ENTRY_TEXTAREA);
1382 2 : gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
1383 2 : sComboBoxText = GDK_RGBA_TO_NS_RGBA(color);
1384 2 : ReleaseStyleContext(style);
1385 :
1386 : // Menubar text and hover text colors
1387 2 : style = ClaimStyleContext(MOZ_GTK_MENUBARITEM);
1388 2 : gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
1389 2 : sMenuBarText = GDK_RGBA_TO_NS_RGBA(color);
1390 2 : gtk_style_context_get_color(style, GTK_STATE_FLAG_PRELIGHT, &color);
1391 2 : sMenuBarHoverText = GDK_RGBA_TO_NS_RGBA(color);
1392 2 : ReleaseStyleContext(style);
1393 :
1394 : // GTK's guide to fancy odd row background colors:
1395 : // 1) Check if a theme explicitly defines an odd row color
1396 : // 2) If not, check if it defines an even row color, and darken it
1397 : // slightly by a hardcoded value (gtkstyle.c)
1398 : // 3) If neither are defined, take the base background color and
1399 : // darken that by a hardcoded value
1400 2 : style = ClaimStyleContext(MOZ_GTK_TREEVIEW);
1401 :
1402 : // Get odd row background color
1403 2 : gtk_style_context_save(style);
1404 2 : gtk_style_context_add_region(style, GTK_STYLE_REGION_ROW, GTK_REGION_ODD);
1405 2 : gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
1406 2 : sOddCellBackground = GDK_RGBA_TO_NS_RGBA(color);
1407 2 : gtk_style_context_restore(style);
1408 2 : ReleaseStyleContext(style);
1409 :
1410 : // GtkFrame has a "border" subnode on which Adwaita draws the border.
1411 : // Some themes do not draw on this node but draw a border on the widget
1412 : // root node, so check the root node if no border is found on the border
1413 : // node.
1414 2 : style = ClaimStyleContext(MOZ_GTK_FRAME_BORDER);
1415 : bool themeUsesColors =
1416 2 : GetBorderColors(style, &sFrameOuterLightBorder, &sFrameInnerDarkBorder);
1417 2 : ReleaseStyleContext(style);
1418 2 : if (!themeUsesColors) {
1419 0 : style = ClaimStyleContext(MOZ_GTK_FRAME);
1420 0 : GetBorderColors(style, &sFrameOuterLightBorder, &sFrameInnerDarkBorder);
1421 0 : ReleaseStyleContext(style);
1422 : }
1423 :
1424 : // GtkInfoBar
1425 : // TODO - Use WidgetCache for it?
1426 2 : GtkWidget* infoBar = gtk_info_bar_new();
1427 2 : GtkWidget* infoBarContent = gtk_info_bar_get_content_area(GTK_INFO_BAR(infoBar));
1428 2 : GtkWidget* infoBarLabel = gtk_label_new(nullptr);
1429 2 : gtk_container_add(GTK_CONTAINER(parent), infoBar);
1430 2 : gtk_container_add(GTK_CONTAINER(infoBarContent), infoBarLabel);
1431 2 : style = gtk_widget_get_style_context(infoBarLabel);
1432 2 : gtk_style_context_add_class(style, GTK_STYLE_CLASS_INFO);
1433 2 : gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color);
1434 2 : sInfoBarText = GDK_RGBA_TO_NS_RGBA(color);
1435 : #endif
1436 : // Some themes have a unified menu bar, and support window dragging on it
1437 2 : gboolean supports_menubar_drag = FALSE;
1438 : GParamSpec *param_spec =
1439 2 : gtk_widget_class_find_style_property(GTK_WIDGET_GET_CLASS(menuBar),
1440 2 : "window-dragging");
1441 2 : if (param_spec) {
1442 2 : if (g_type_is_a(G_PARAM_SPEC_VALUE_TYPE(param_spec), G_TYPE_BOOLEAN)) {
1443 : gtk_widget_style_get(menuBar,
1444 : "window-dragging", &supports_menubar_drag,
1445 2 : nullptr);
1446 : }
1447 : }
1448 2 : sMenuSupportsDrag = supports_menubar_drag;
1449 :
1450 2 : colorValuePtr = nullptr;
1451 2 : gtk_widget_style_get(linkButton, "link-color", &colorValuePtr, nullptr);
1452 2 : if (colorValuePtr) {
1453 0 : colorValue = *colorValuePtr; // we can't pass deref pointers to GDK_COLOR_TO_NS_RGB
1454 0 : sNativeHyperLinkText = GDK_COLOR_TO_NS_RGB(colorValue);
1455 0 : gdk_color_free(colorValuePtr);
1456 : } else {
1457 2 : sNativeHyperLinkText = NS_RGB(0x00,0x00,0xEE);
1458 : }
1459 :
1460 : // invisible character styles
1461 : guint value;
1462 2 : g_object_get (entry, "invisible-char", &value, nullptr);
1463 2 : sInvisibleCharacter = char16_t(value);
1464 :
1465 : // caret styles
1466 2 : gtk_widget_style_get(entry,
1467 : "cursor-aspect-ratio", &sCaretRatio,
1468 2 : nullptr);
1469 :
1470 2 : gtk_widget_destroy(window);
1471 : }
1472 :
1473 : // virtual
1474 : char16_t
1475 0 : nsLookAndFeel::GetPasswordCharacterImpl()
1476 : {
1477 0 : EnsureInit();
1478 0 : return sInvisibleCharacter;
1479 : }
1480 :
1481 : void
1482 0 : nsLookAndFeel::RefreshImpl()
1483 : {
1484 0 : nsXPLookAndFeel::RefreshImpl();
1485 0 : moz_gtk_refresh();
1486 :
1487 0 : mDefaultFontCached = false;
1488 0 : mButtonFontCached = false;
1489 0 : mFieldFontCached = false;
1490 0 : mMenuFontCached = false;
1491 :
1492 : #if (MOZ_WIDGET_GTK == 2)
1493 : g_object_unref(mStyle);
1494 : mStyle = nullptr;
1495 : #endif
1496 :
1497 0 : mInitialized = false;
1498 0 : }
1499 :
1500 : bool
1501 0 : nsLookAndFeel::GetEchoPasswordImpl() {
1502 0 : return false;
1503 : }
|