/src/mozilla-central/widget/gtk/nsLookAndFeel.cpp
Line | Count | Source (jump to first uncovered line) |
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 "mozilla/FontPropertyTypes.h" |
22 | | #include "ScreenHelperGTK.h" |
23 | | |
24 | | #include "gtkdrawing.h" |
25 | | #include "nsStyleConsts.h" |
26 | | #include "gfxFontConstants.h" |
27 | | #include "WidgetUtils.h" |
28 | | #include "nsWindow.h" |
29 | | |
30 | | #include "mozilla/gfx/2D.h" |
31 | | |
32 | | #include <cairo-gobject.h> |
33 | | #include "WidgetStyleCache.h" |
34 | | #include "prenv.h" |
35 | | #include "nsCSSColorUtils.h" |
36 | | |
37 | | using namespace mozilla; |
38 | | using mozilla::LookAndFeel; |
39 | | |
40 | | #define GDK_COLOR_TO_NS_RGB(c) \ |
41 | 0 | ((nscolor) NS_RGB(c.red>>8, c.green>>8, c.blue>>8)) |
42 | | #define GDK_RGBA_TO_NS_RGBA(c) \ |
43 | 0 | ((nscolor) NS_RGBA((int)((c).red*255), (int)((c).green*255), \ |
44 | 0 | (int)((c).blue*255), (int)((c).alpha*255))) |
45 | | |
46 | | #if !GTK_CHECK_VERSION(3,12,0) |
47 | | #define GTK_STATE_FLAG_LINK (static_cast<GtkStateFlags>(1 << 9)) |
48 | | #endif |
49 | | |
50 | | nsLookAndFeel::nsLookAndFeel() |
51 | | : nsXPLookAndFeel(), |
52 | | mDefaultFontCached(false), mButtonFontCached(false), |
53 | | mFieldFontCached(false), mMenuFontCached(false), |
54 | | mInitialized(false) |
55 | 0 | { |
56 | 0 | } |
57 | | |
58 | | nsLookAndFeel::~nsLookAndFeel() |
59 | 0 | { |
60 | 0 | } |
61 | | |
62 | | // Modifies color |*aDest| as if a pattern of color |aSource| was painted with |
63 | | // CAIRO_OPERATOR_OVER to a surface with color |*aDest|. |
64 | | static void |
65 | 0 | ApplyColorOver(const GdkRGBA& aSource, GdkRGBA* aDest) { |
66 | 0 | gdouble sourceCoef = aSource.alpha; |
67 | 0 | gdouble destCoef = aDest->alpha * (1.0 - sourceCoef); |
68 | 0 | gdouble resultAlpha = sourceCoef + destCoef; |
69 | 0 | if (resultAlpha != 0.0) { // don't divide by zero |
70 | 0 | destCoef /= resultAlpha; |
71 | 0 | sourceCoef /= resultAlpha; |
72 | 0 | aDest->red = sourceCoef * aSource.red + destCoef * aDest->red; |
73 | 0 | aDest->green = sourceCoef * aSource.green + destCoef * aDest->green; |
74 | 0 | aDest->blue = sourceCoef * aSource.blue + destCoef * aDest->blue; |
75 | 0 | aDest->alpha = resultAlpha; |
76 | 0 | } |
77 | 0 | } |
78 | | |
79 | | static void |
80 | | GetLightAndDarkness(const GdkRGBA& aColor, |
81 | | double* aLightness, double* aDarkness) |
82 | 0 | { |
83 | 0 | double sum = aColor.red + aColor.green + aColor.blue; |
84 | 0 | *aLightness = sum * aColor.alpha; |
85 | 0 | *aDarkness = (3.0 - sum) * aColor.alpha; |
86 | 0 | } |
87 | | |
88 | | static bool |
89 | | GetGradientColors(const GValue* aValue, |
90 | | GdkRGBA* aLightColor, GdkRGBA* aDarkColor) |
91 | 0 | { |
92 | 0 | if (!G_TYPE_CHECK_VALUE_TYPE(aValue, CAIRO_GOBJECT_TYPE_PATTERN)) |
93 | 0 | return false; |
94 | 0 | |
95 | 0 | auto pattern = static_cast<cairo_pattern_t*>(g_value_get_boxed(aValue)); |
96 | 0 | if (!pattern) |
97 | 0 | return false; |
98 | 0 | |
99 | 0 | // Just picking the lightest and darkest colors as simple samples rather |
100 | 0 | // than trying to blend, which could get messy if there are many stops. |
101 | 0 | if (CAIRO_STATUS_SUCCESS != |
102 | 0 | cairo_pattern_get_color_stop_rgba(pattern, 0, nullptr, &aDarkColor->red, |
103 | 0 | &aDarkColor->green, &aDarkColor->blue, |
104 | 0 | &aDarkColor->alpha)) |
105 | 0 | return false; |
106 | 0 | |
107 | 0 | double maxLightness, maxDarkness; |
108 | 0 | GetLightAndDarkness(*aDarkColor, &maxLightness, &maxDarkness); |
109 | 0 | *aLightColor = *aDarkColor; |
110 | 0 |
|
111 | 0 | GdkRGBA stop; |
112 | 0 | for (int index = 1; |
113 | 0 | CAIRO_STATUS_SUCCESS == |
114 | 0 | cairo_pattern_get_color_stop_rgba(pattern, index, nullptr, |
115 | 0 | &stop.red, &stop.green, |
116 | 0 | &stop.blue, &stop.alpha); |
117 | 0 | ++index) { |
118 | 0 | double lightness, darkness; |
119 | 0 | GetLightAndDarkness(stop, &lightness, &darkness); |
120 | 0 | if (lightness > maxLightness) { |
121 | 0 | maxLightness = lightness; |
122 | 0 | *aLightColor = stop; |
123 | 0 | } |
124 | 0 | if (darkness > maxDarkness) { |
125 | 0 | maxDarkness = darkness; |
126 | 0 | *aDarkColor = stop; |
127 | 0 | } |
128 | 0 | } |
129 | 0 |
|
130 | 0 | return true; |
131 | 0 | } |
132 | | |
133 | | static bool |
134 | | GetUnicoBorderGradientColors(GtkStyleContext* aContext, |
135 | | GdkRGBA* aLightColor, GdkRGBA* aDarkColor) |
136 | 0 | { |
137 | 0 | // Ubuntu 12.04 has GTK engine Unico-1.0.2, which overrides render_frame, |
138 | 0 | // providing its own border code. Ubuntu 14.04 has |
139 | 0 | // Unico-1.0.3+14.04.20140109, which does not override render_frame, and |
140 | 0 | // so does not need special attention. The earlier Unico can be detected |
141 | 0 | // by the -unico-border-gradient style property it registers. |
142 | 0 | // gtk_style_properties_lookup_property() is checked first to avoid the |
143 | 0 | // warning from gtk_style_context_get_property() when the property does |
144 | 0 | // not exist. (gtk_render_frame() of GTK+ 3.16 no longer uses the |
145 | 0 | // engine.) |
146 | 0 | const char* propertyName = "-unico-border-gradient"; |
147 | 0 | if (!gtk_style_properties_lookup_property(propertyName, nullptr, nullptr)) |
148 | 0 | return false; |
149 | 0 | |
150 | 0 | // -unico-border-gradient is used only when the CSS node's engine is Unico. |
151 | 0 | GtkThemingEngine* engine; |
152 | 0 | GtkStateFlags state = gtk_style_context_get_state(aContext); |
153 | 0 | gtk_style_context_get(aContext, state, "engine", &engine, nullptr); |
154 | 0 | if (strcmp(g_type_name(G_TYPE_FROM_INSTANCE(engine)), "UnicoEngine") != 0) |
155 | 0 | return false; |
156 | 0 | |
157 | 0 | // draw_border() of Unico engine uses -unico-border-gradient |
158 | 0 | // in preference to border-color. |
159 | 0 | GValue value = G_VALUE_INIT; |
160 | 0 | gtk_style_context_get_property(aContext, propertyName, state, &value); |
161 | 0 |
|
162 | 0 | bool result = GetGradientColors(&value, aLightColor, aDarkColor); |
163 | 0 |
|
164 | 0 | g_value_unset(&value); |
165 | 0 | return result; |
166 | 0 | } |
167 | | |
168 | | // Sets |aLightColor| and |aDarkColor| to colors from |aContext|. Returns |
169 | | // true if |aContext| uses these colors to render a visible border. |
170 | | // If returning false, then the colors returned are a fallback from the |
171 | | // border-color value even though |aContext| does not use these colors to |
172 | | // render a border. |
173 | | static bool |
174 | | GetBorderColors(GtkStyleContext* aContext, |
175 | | GdkRGBA* aLightColor, GdkRGBA* aDarkColor) |
176 | 0 | { |
177 | 0 | // Determine whether the border on this style context is visible. |
178 | 0 | GtkStateFlags state = gtk_style_context_get_state(aContext); |
179 | 0 | GtkBorderStyle borderStyle; |
180 | 0 | gtk_style_context_get(aContext, state, GTK_STYLE_PROPERTY_BORDER_STYLE, |
181 | 0 | &borderStyle, nullptr); |
182 | 0 | bool visible = borderStyle != GTK_BORDER_STYLE_NONE && |
183 | 0 | borderStyle != GTK_BORDER_STYLE_HIDDEN; |
184 | 0 | if (visible) { |
185 | 0 | // GTK has an initial value of zero for border-widths, and so themes |
186 | 0 | // need to explicitly set border-widths to make borders visible. |
187 | 0 | GtkBorder border; |
188 | 0 | gtk_style_context_get_border(aContext, state, &border); |
189 | 0 | visible = border.top != 0 || border.right != 0 || |
190 | 0 | border.bottom != 0 || border.left != 0; |
191 | 0 | } |
192 | 0 |
|
193 | 0 | if (visible && |
194 | 0 | GetUnicoBorderGradientColors(aContext, aLightColor, aDarkColor)) |
195 | 0 | return true; |
196 | 0 | |
197 | 0 | // The initial value for the border-color is the foreground color, and so |
198 | 0 | // this will usually return a color distinct from the background even if |
199 | 0 | // there is no visible border detected. |
200 | 0 | gtk_style_context_get_border_color(aContext, state, aDarkColor); |
201 | 0 | // TODO GTK3 - update aLightColor |
202 | 0 | // for GTK_BORDER_STYLE_INSET/OUTSET/GROVE/RIDGE border styles. |
203 | 0 | // https://bugzilla.mozilla.org/show_bug.cgi?id=978172#c25 |
204 | 0 | *aLightColor = *aDarkColor; |
205 | 0 | return visible; |
206 | 0 | } |
207 | | |
208 | | static bool |
209 | | GetBorderColors(GtkStyleContext* aContext, |
210 | | nscolor* aLightColor, nscolor* aDarkColor) |
211 | 0 | { |
212 | 0 | GdkRGBA lightColor, darkColor; |
213 | 0 | bool ret = GetBorderColors(aContext, &lightColor, &darkColor); |
214 | 0 | *aLightColor = GDK_RGBA_TO_NS_RGBA(lightColor); |
215 | 0 | *aDarkColor = GDK_RGBA_TO_NS_RGBA(darkColor); |
216 | 0 | return ret; |
217 | 0 | } |
218 | | |
219 | | // Finds ideal cell highlight colors used for unfocused+selected cells distinct |
220 | | // from both Highlight, used as focused+selected background, and the listbox |
221 | | // background which is assumed to be similar to -moz-field |
222 | | nsresult |
223 | 0 | nsLookAndFeel::InitCellHighlightColors() { |
224 | 0 | // NS_SUFFICIENT_LUMINOSITY_DIFFERENCE is the a11y standard for text |
225 | 0 | // on a background. Use 20% of that standard since we have a background |
226 | 0 | // on top of another background |
227 | 0 | int32_t minLuminosityDifference = NS_SUFFICIENT_LUMINOSITY_DIFFERENCE / 5; |
228 | 0 | int32_t backLuminosityDifference = NS_LUMINOSITY_DIFFERENCE( |
229 | 0 | mMozWindowBackground, mMozFieldBackground); |
230 | 0 | if (backLuminosityDifference >= minLuminosityDifference) { |
231 | 0 | mMozCellHighlightBackground = mMozWindowBackground; |
232 | 0 | mMozCellHighlightText = mMozWindowText; |
233 | 0 | return NS_OK; |
234 | 0 | } |
235 | 0 | |
236 | 0 | uint16_t hue, sat, luminance; |
237 | 0 | uint8_t alpha; |
238 | 0 | mMozCellHighlightBackground = mMozFieldBackground; |
239 | 0 | mMozCellHighlightText = mMozFieldText; |
240 | 0 |
|
241 | 0 | NS_RGB2HSV(mMozCellHighlightBackground, hue, sat, luminance, alpha); |
242 | 0 |
|
243 | 0 | uint16_t step = 30; |
244 | 0 | // Lighten the color if the color is very dark |
245 | 0 | if (luminance <= step) { |
246 | 0 | luminance += step; |
247 | 0 | } |
248 | 0 | // Darken it if it is very light |
249 | 0 | else if (luminance >= 255 - step) { |
250 | 0 | luminance -= step; |
251 | 0 | } |
252 | 0 | // Otherwise, compute what works best depending on the text luminance. |
253 | 0 | else { |
254 | 0 | uint16_t textHue, textSat, textLuminance; |
255 | 0 | uint8_t textAlpha; |
256 | 0 | NS_RGB2HSV(mMozCellHighlightText, textHue, textSat, textLuminance, |
257 | 0 | textAlpha); |
258 | 0 | // Text is darker than background, use a lighter shade |
259 | 0 | if (textLuminance < luminance) { |
260 | 0 | luminance += step; |
261 | 0 | } |
262 | 0 | // Otherwise, use a darker shade |
263 | 0 | else { |
264 | 0 | luminance -= step; |
265 | 0 | } |
266 | 0 | } |
267 | 0 | NS_HSV2RGB(mMozCellHighlightBackground, hue, sat, luminance, alpha); |
268 | 0 | return NS_OK; |
269 | 0 | } |
270 | | |
271 | | void |
272 | | nsLookAndFeel::NativeInit() |
273 | 0 | { |
274 | 0 | EnsureInit(); |
275 | 0 | } |
276 | | |
277 | | void |
278 | | nsLookAndFeel::RefreshImpl() |
279 | 0 | { |
280 | 0 | nsXPLookAndFeel::RefreshImpl(); |
281 | 0 | moz_gtk_refresh(); |
282 | 0 |
|
283 | 0 | mDefaultFontCached = false; |
284 | 0 | mButtonFontCached = false; |
285 | 0 | mFieldFontCached = false; |
286 | 0 | mMenuFontCached = false; |
287 | 0 |
|
288 | 0 | mInitialized = false; |
289 | 0 | } |
290 | | |
291 | | nsresult |
292 | | nsLookAndFeel::NativeGetColor(ColorID aID, nscolor& aColor) |
293 | 0 | { |
294 | 0 | EnsureInit(); |
295 | 0 |
|
296 | 0 | nsresult res = NS_OK; |
297 | 0 |
|
298 | 0 | switch (aID) { |
299 | 0 | // These colors don't seem to be used for anything anymore in Mozilla |
300 | 0 | // (except here at least TextSelectBackground and TextSelectForeground) |
301 | 0 | // The CSS2 colors below are used. |
302 | 0 | case eColorID_WindowBackground: |
303 | 0 | case eColorID_WidgetBackground: |
304 | 0 | case eColorID_TextBackground: |
305 | 0 | case eColorID_activecaption: // active window caption background |
306 | 0 | case eColorID_appworkspace: // MDI background color |
307 | 0 | case eColorID_background: // desktop background |
308 | 0 | case eColorID_window: |
309 | 0 | case eColorID_windowframe: |
310 | 0 | case eColorID__moz_dialog: |
311 | 0 | case eColorID__moz_combobox: |
312 | 0 | aColor = mMozWindowBackground; |
313 | 0 | break; |
314 | 0 | case eColorID_WindowForeground: |
315 | 0 | case eColorID_WidgetForeground: |
316 | 0 | case eColorID_TextForeground: |
317 | 0 | case eColorID_captiontext: // text in active window caption, size box, and scrollbar arrow box (!) |
318 | 0 | case eColorID_windowtext: |
319 | 0 | case eColorID__moz_dialogtext: |
320 | 0 | aColor = mMozWindowText; |
321 | 0 | break; |
322 | 0 | case eColorID_WidgetSelectBackground: |
323 | 0 | case eColorID_TextSelectBackground: |
324 | 0 | case eColorID_IMESelectedRawTextBackground: |
325 | 0 | case eColorID_IMESelectedConvertedTextBackground: |
326 | 0 | case eColorID__moz_dragtargetzone: |
327 | 0 | case eColorID__moz_html_cellhighlight: |
328 | 0 | case eColorID_highlight: // preference selected item, |
329 | 0 | aColor = mTextSelectedBackground; |
330 | 0 | break; |
331 | 0 | case eColorID_WidgetSelectForeground: |
332 | 0 | case eColorID_TextSelectForeground: |
333 | 0 | case eColorID_IMESelectedRawTextForeground: |
334 | 0 | case eColorID_IMESelectedConvertedTextForeground: |
335 | 0 | case eColorID_highlighttext: |
336 | 0 | case eColorID__moz_html_cellhighlighttext: |
337 | 0 | aColor = mTextSelectedText; |
338 | 0 | break; |
339 | 0 | case eColorID__moz_cellhighlight: |
340 | 0 | aColor = mMozCellHighlightBackground; |
341 | 0 | break; |
342 | 0 | case eColorID__moz_cellhighlighttext: |
343 | 0 | aColor = mMozCellHighlightText; |
344 | 0 | break; |
345 | 0 | case eColorID_Widget3DHighlight: |
346 | 0 | aColor = NS_RGB(0xa0,0xa0,0xa0); |
347 | 0 | break; |
348 | 0 | case eColorID_Widget3DShadow: |
349 | 0 | aColor = NS_RGB(0x40,0x40,0x40); |
350 | 0 | break; |
351 | 0 | case eColorID_IMERawInputBackground: |
352 | 0 | case eColorID_IMEConvertedTextBackground: |
353 | 0 | aColor = NS_TRANSPARENT; |
354 | 0 | break; |
355 | 0 | case eColorID_IMERawInputForeground: |
356 | 0 | case eColorID_IMEConvertedTextForeground: |
357 | 0 | aColor = NS_SAME_AS_FOREGROUND_COLOR; |
358 | 0 | break; |
359 | 0 | case eColorID_IMERawInputUnderline: |
360 | 0 | case eColorID_IMEConvertedTextUnderline: |
361 | 0 | aColor = NS_SAME_AS_FOREGROUND_COLOR; |
362 | 0 | break; |
363 | 0 | case eColorID_IMESelectedRawTextUnderline: |
364 | 0 | case eColorID_IMESelectedConvertedTextUnderline: |
365 | 0 | aColor = NS_TRANSPARENT; |
366 | 0 | break; |
367 | 0 | case eColorID_SpellCheckerUnderline: |
368 | 0 | aColor = NS_RGB(0xff, 0, 0); |
369 | 0 | break; |
370 | 0 |
|
371 | 0 | // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors |
372 | 0 | case eColorID_activeborder: |
373 | 0 | // active window border |
374 | 0 | aColor = mMozWindowActiveBorder; |
375 | 0 | break; |
376 | 0 | case eColorID_inactiveborder: |
377 | 0 | // inactive window border |
378 | 0 | aColor = mMozWindowInactiveBorder; |
379 | 0 | break; |
380 | 0 | case eColorID_graytext: // disabled text in windows, menus, etc. |
381 | 0 | case eColorID_inactivecaptiontext: // text in inactive window caption |
382 | 0 | aColor = mMenuTextInactive; |
383 | 0 | break; |
384 | 0 | case eColorID_inactivecaption: |
385 | 0 | // inactive window caption |
386 | 0 | aColor = mMozWindowInactiveCaption; |
387 | 0 | break; |
388 | 0 | case eColorID_infobackground: |
389 | 0 | // tooltip background color |
390 | 0 | aColor = mInfoBackground; |
391 | 0 | break; |
392 | 0 | case eColorID_infotext: |
393 | 0 | // tooltip text color |
394 | 0 | aColor = mInfoText; |
395 | 0 | break; |
396 | 0 | case eColorID_menu: |
397 | 0 | // menu background |
398 | 0 | aColor = mMenuBackground; |
399 | 0 | break; |
400 | 0 | case eColorID_menutext: |
401 | 0 | // menu text |
402 | 0 | aColor = mMenuText; |
403 | 0 | break; |
404 | 0 | case eColorID_scrollbar: |
405 | 0 | // scrollbar gray area |
406 | 0 | aColor = mMozScrollbar; |
407 | 0 | break; |
408 | 0 |
|
409 | 0 | case eColorID_threedlightshadow: |
410 | 0 | // 3-D highlighted inner edge color |
411 | 0 | // always same as background in GTK code |
412 | 0 | case eColorID_threedface: |
413 | 0 | case eColorID_buttonface: |
414 | 0 | // 3-D face color |
415 | 0 | aColor = mMozWindowBackground; |
416 | 0 | break; |
417 | 0 |
|
418 | 0 | case eColorID_buttontext: |
419 | 0 | // text on push buttons |
420 | 0 | aColor = mButtonText; |
421 | 0 | break; |
422 | 0 |
|
423 | 0 | case eColorID_buttonhighlight: |
424 | 0 | // 3-D highlighted edge color |
425 | 0 | case eColorID_threedhighlight: |
426 | 0 | // 3-D highlighted outer edge color |
427 | 0 | aColor = mFrameOuterLightBorder; |
428 | 0 | break; |
429 | 0 |
|
430 | 0 | case eColorID_buttonshadow: |
431 | 0 | // 3-D shadow edge color |
432 | 0 | case eColorID_threedshadow: |
433 | 0 | // 3-D shadow inner edge color |
434 | 0 | aColor = mFrameInnerDarkBorder; |
435 | 0 | break; |
436 | 0 |
|
437 | 0 | case eColorID_threeddarkshadow: |
438 | 0 | // Hardcode to black |
439 | 0 | aColor = NS_RGB(0x00,0x00,0x00); |
440 | 0 | break; |
441 | 0 |
|
442 | 0 | case eColorID__moz_eventreerow: |
443 | 0 | case eColorID__moz_field: |
444 | 0 | aColor = mMozFieldBackground; |
445 | 0 | break; |
446 | 0 | case eColorID__moz_fieldtext: |
447 | 0 | aColor = mMozFieldText; |
448 | 0 | break; |
449 | 0 | case eColorID__moz_buttondefault: |
450 | 0 | // default button border color |
451 | 0 | aColor = mButtonDefault; |
452 | 0 | break; |
453 | 0 | case eColorID__moz_buttonhoverface: |
454 | 0 | aColor = mButtonHoverFace; |
455 | 0 | break; |
456 | 0 | case eColorID__moz_buttonhovertext: |
457 | 0 | aColor = mButtonHoverText; |
458 | 0 | break; |
459 | 0 | case eColorID__moz_menuhover: |
460 | 0 | aColor = mMenuHover; |
461 | 0 | break; |
462 | 0 | case eColorID__moz_menuhovertext: |
463 | 0 | aColor = mMenuHoverText; |
464 | 0 | break; |
465 | 0 | case eColorID__moz_oddtreerow: |
466 | 0 | aColor = mOddCellBackground; |
467 | 0 | break; |
468 | 0 | case eColorID__moz_nativehyperlinktext: |
469 | 0 | aColor = mNativeHyperLinkText; |
470 | 0 | break; |
471 | 0 | case eColorID__moz_comboboxtext: |
472 | 0 | aColor = mComboBoxText; |
473 | 0 | break; |
474 | 0 | case eColorID__moz_menubartext: |
475 | 0 | aColor = mMenuBarText; |
476 | 0 | break; |
477 | 0 | case eColorID__moz_menubarhovertext: |
478 | 0 | aColor = mMenuBarHoverText; |
479 | 0 | break; |
480 | 0 | case eColorID__moz_gtk_info_bar_text: |
481 | 0 | aColor = mInfoBarText; |
482 | 0 | break; |
483 | 0 | default: |
484 | 0 | /* default color is BLACK */ |
485 | 0 | aColor = 0; |
486 | 0 | res = NS_ERROR_FAILURE; |
487 | 0 | break; |
488 | 0 | } |
489 | 0 | |
490 | 0 | return res; |
491 | 0 | } |
492 | | |
493 | 0 | static int32_t CheckWidgetStyle(GtkWidget* aWidget, const char* aStyle, int32_t aResult) { |
494 | 0 | gboolean value = FALSE; |
495 | 0 | gtk_widget_style_get(aWidget, aStyle, &value, nullptr); |
496 | 0 | return value ? aResult : 0; |
497 | 0 | } |
498 | | |
499 | | static int32_t ConvertGTKStepperStyleToMozillaScrollArrowStyle(GtkWidget* aWidget) |
500 | 0 | { |
501 | 0 | if (!aWidget) |
502 | 0 | return mozilla::LookAndFeel::eScrollArrowStyle_Single; |
503 | 0 | |
504 | 0 | return |
505 | 0 | CheckWidgetStyle(aWidget, "has-backward-stepper", |
506 | 0 | mozilla::LookAndFeel::eScrollArrow_StartBackward) | |
507 | 0 | CheckWidgetStyle(aWidget, "has-forward-stepper", |
508 | 0 | mozilla::LookAndFeel::eScrollArrow_EndForward) | |
509 | 0 | CheckWidgetStyle(aWidget, "has-secondary-backward-stepper", |
510 | 0 | mozilla::LookAndFeel::eScrollArrow_EndBackward) | |
511 | 0 | CheckWidgetStyle(aWidget, "has-secondary-forward-stepper", |
512 | 0 | mozilla::LookAndFeel::eScrollArrow_StartForward); |
513 | 0 | } |
514 | | |
515 | | nsresult |
516 | | nsLookAndFeel::GetIntImpl(IntID aID, int32_t &aResult) |
517 | 0 | { |
518 | 0 | nsresult res = NS_OK; |
519 | 0 |
|
520 | 0 | // Set these before they can get overrided in the nsXPLookAndFeel. |
521 | 0 | switch (aID) { |
522 | 0 | case eIntID_ScrollButtonLeftMouseButtonAction: |
523 | 0 | aResult = 0; |
524 | 0 | return NS_OK; |
525 | 0 | case eIntID_ScrollButtonMiddleMouseButtonAction: |
526 | 0 | aResult = 1; |
527 | 0 | return NS_OK; |
528 | 0 | case eIntID_ScrollButtonRightMouseButtonAction: |
529 | 0 | aResult = 2; |
530 | 0 | return NS_OK; |
531 | 0 | default: |
532 | 0 | break; |
533 | 0 | } |
534 | 0 | |
535 | 0 | res = nsXPLookAndFeel::GetIntImpl(aID, aResult); |
536 | 0 | if (NS_SUCCEEDED(res)) |
537 | 0 | return res; |
538 | 0 | res = NS_OK; |
539 | 0 |
|
540 | 0 | // We use delayed initialization by EnsureInit() here |
541 | 0 | // to make sure mozilla::Preferences is available (Bug 115807). |
542 | 0 | // eIntID_UseAccessibilityTheme is requested before user preferences |
543 | 0 | // are read, and so EnsureInit(), which depends on preference values, |
544 | 0 | // is deliberately delayed until required. |
545 | 0 | switch (aID) { |
546 | 0 | case eIntID_CaretBlinkTime: |
547 | 0 | { |
548 | 0 | GtkSettings *settings; |
549 | 0 | gint blink_time; |
550 | 0 | gboolean blink; |
551 | 0 |
|
552 | 0 | settings = gtk_settings_get_default (); |
553 | 0 | g_object_get (settings, |
554 | 0 | "gtk-cursor-blink-time", &blink_time, |
555 | 0 | "gtk-cursor-blink", &blink, |
556 | 0 | nullptr); |
557 | 0 |
|
558 | 0 | if (blink) |
559 | 0 | aResult = (int32_t) blink_time; |
560 | 0 | else |
561 | 0 | aResult = 0; |
562 | 0 | break; |
563 | 0 | } |
564 | 0 | case eIntID_CaretWidth: |
565 | 0 | aResult = 1; |
566 | 0 | break; |
567 | 0 | case eIntID_ShowCaretDuringSelection: |
568 | 0 | aResult = 0; |
569 | 0 | break; |
570 | 0 | case eIntID_SelectTextfieldsOnKeyFocus: |
571 | 0 | { |
572 | 0 | GtkWidget *entry; |
573 | 0 | GtkSettings *settings; |
574 | 0 | gboolean select_on_focus; |
575 | 0 |
|
576 | 0 | entry = gtk_entry_new(); |
577 | 0 | g_object_ref_sink(entry); |
578 | 0 | settings = gtk_widget_get_settings(entry); |
579 | 0 | g_object_get(settings, |
580 | 0 | "gtk-entry-select-on-focus", |
581 | 0 | &select_on_focus, |
582 | 0 | nullptr); |
583 | 0 |
|
584 | 0 | if(select_on_focus) |
585 | 0 | aResult = 1; |
586 | 0 | else |
587 | 0 | aResult = 0; |
588 | 0 |
|
589 | 0 | gtk_widget_destroy(entry); |
590 | 0 | g_object_unref(entry); |
591 | 0 | } |
592 | 0 | break; |
593 | 0 | case eIntID_ScrollToClick: |
594 | 0 | { |
595 | 0 | GtkSettings *settings; |
596 | 0 | gboolean warps_slider = FALSE; |
597 | 0 |
|
598 | 0 | settings = gtk_settings_get_default (); |
599 | 0 | if (g_object_class_find_property (G_OBJECT_GET_CLASS(settings), |
600 | 0 | "gtk-primary-button-warps-slider")) { |
601 | 0 | g_object_get (settings, |
602 | 0 | "gtk-primary-button-warps-slider", |
603 | 0 | &warps_slider, |
604 | 0 | nullptr); |
605 | 0 | } |
606 | 0 |
|
607 | 0 | if (warps_slider) |
608 | 0 | aResult = 1; |
609 | 0 | else |
610 | 0 | aResult = 0; |
611 | 0 | } |
612 | 0 | break; |
613 | 0 | case eIntID_SubmenuDelay: |
614 | 0 | { |
615 | 0 | GtkSettings *settings; |
616 | 0 | gint delay; |
617 | 0 |
|
618 | 0 | settings = gtk_settings_get_default (); |
619 | 0 | g_object_get (settings, "gtk-menu-popup-delay", &delay, nullptr); |
620 | 0 | aResult = (int32_t) delay; |
621 | 0 | break; |
622 | 0 | } |
623 | 0 | case eIntID_TooltipDelay: |
624 | 0 | { |
625 | 0 | aResult = 500; |
626 | 0 | break; |
627 | 0 | } |
628 | 0 | case eIntID_MenusCanOverlapOSBar: |
629 | 0 | // we want XUL popups to be able to overlap the task bar. |
630 | 0 | aResult = 1; |
631 | 0 | break; |
632 | 0 | case eIntID_SkipNavigatingDisabledMenuItem: |
633 | 0 | aResult = 1; |
634 | 0 | break; |
635 | 0 | case eIntID_DragThresholdX: |
636 | 0 | case eIntID_DragThresholdY: |
637 | 0 | { |
638 | 0 | GtkWidget* box = gtk_hbox_new(FALSE, 5); |
639 | 0 | gint threshold = 0; |
640 | 0 | g_object_get(gtk_widget_get_settings(box), |
641 | 0 | "gtk-dnd-drag-threshold", &threshold, |
642 | 0 | nullptr); |
643 | 0 | g_object_ref_sink(box); |
644 | 0 |
|
645 | 0 | aResult = threshold; |
646 | 0 | } |
647 | 0 | break; |
648 | 0 | case eIntID_ScrollArrowStyle: { |
649 | 0 | GtkWidget* scrollbar = GetWidget(MOZ_GTK_SCROLLBAR_HORIZONTAL); |
650 | 0 | aResult = ConvertGTKStepperStyleToMozillaScrollArrowStyle(scrollbar); |
651 | 0 | break; |
652 | 0 | } |
653 | 0 | case eIntID_ScrollSliderStyle: |
654 | 0 | aResult = eScrollThumbStyle_Proportional; |
655 | 0 | break; |
656 | 0 | case eIntID_TreeOpenDelay: |
657 | 0 | aResult = 1000; |
658 | 0 | break; |
659 | 0 | case eIntID_TreeCloseDelay: |
660 | 0 | aResult = 1000; |
661 | 0 | break; |
662 | 0 | case eIntID_TreeLazyScrollDelay: |
663 | 0 | aResult = 150; |
664 | 0 | break; |
665 | 0 | case eIntID_TreeScrollDelay: |
666 | 0 | aResult = 100; |
667 | 0 | break; |
668 | 0 | case eIntID_TreeScrollLinesMax: |
669 | 0 | aResult = 3; |
670 | 0 | break; |
671 | 0 | case eIntID_DWMCompositor: |
672 | 0 | case eIntID_WindowsClassic: |
673 | 0 | case eIntID_WindowsDefaultTheme: |
674 | 0 | case eIntID_WindowsThemeIdentifier: |
675 | 0 | case eIntID_OperatingSystemVersionIdentifier: |
676 | 0 | aResult = 0; |
677 | 0 | res = NS_ERROR_NOT_IMPLEMENTED; |
678 | 0 | break; |
679 | 0 | case eIntID_TouchEnabled: |
680 | 0 | aResult = mozilla::widget::WidgetUtils::IsTouchDeviceSupportPresent(); |
681 | 0 | break; |
682 | 0 | case eIntID_MacGraphiteTheme: |
683 | 0 | aResult = 0; |
684 | 0 | res = NS_ERROR_NOT_IMPLEMENTED; |
685 | 0 | break; |
686 | 0 | case eIntID_AlertNotificationOrigin: |
687 | 0 | aResult = NS_ALERT_TOP; |
688 | 0 | break; |
689 | 0 | case eIntID_IMERawInputUnderlineStyle: |
690 | 0 | case eIntID_IMEConvertedTextUnderlineStyle: |
691 | 0 | aResult = NS_STYLE_TEXT_DECORATION_STYLE_SOLID; |
692 | 0 | break; |
693 | 0 | case eIntID_IMESelectedRawTextUnderlineStyle: |
694 | 0 | case eIntID_IMESelectedConvertedTextUnderline: |
695 | 0 | aResult = NS_STYLE_TEXT_DECORATION_STYLE_NONE; |
696 | 0 | break; |
697 | 0 | case eIntID_SpellCheckerUnderlineStyle: |
698 | 0 | aResult = NS_STYLE_TEXT_DECORATION_STYLE_WAVY; |
699 | 0 | break; |
700 | 0 | case eIntID_MenuBarDrag: |
701 | 0 | EnsureInit(); |
702 | 0 | aResult = mMenuSupportsDrag; |
703 | 0 | break; |
704 | 0 | case eIntID_ScrollbarButtonAutoRepeatBehavior: |
705 | 0 | aResult = 1; |
706 | 0 | break; |
707 | 0 | case eIntID_SwipeAnimationEnabled: |
708 | 0 | aResult = 0; |
709 | 0 | break; |
710 | 0 | case eIntID_ContextMenuOffsetVertical: |
711 | 0 | case eIntID_ContextMenuOffsetHorizontal: |
712 | 0 | aResult = 2; |
713 | 0 | break; |
714 | 0 | case eIntID_GTKCSDAvailable: |
715 | 0 | EnsureInit(); |
716 | 0 | aResult = mCSDAvailable; |
717 | 0 | break; |
718 | 0 | case eIntID_GTKCSDMaximizeButton: |
719 | 0 | EnsureInit(); |
720 | 0 | aResult = mCSDMaximizeButton; |
721 | 0 | break; |
722 | 0 | case eIntID_GTKCSDMinimizeButton: |
723 | 0 | EnsureInit(); |
724 | 0 | aResult = mCSDMinimizeButton; |
725 | 0 | break; |
726 | 0 | case eIntID_GTKCSDCloseButton: |
727 | 0 | EnsureInit(); |
728 | 0 | aResult = mCSDCloseButton; |
729 | 0 | break; |
730 | 0 | case eIntID_PrefersReducedMotion: { |
731 | 0 | GtkSettings *settings; |
732 | 0 | gboolean enableAnimations; |
733 | 0 |
|
734 | 0 | settings = gtk_settings_get_default(); |
735 | 0 | g_object_get(settings, |
736 | 0 | "gtk-enable-animations", |
737 | 0 | &enableAnimations, nullptr); |
738 | 0 | aResult = enableAnimations ? 0 : 1; |
739 | 0 | break; |
740 | 0 | } |
741 | 0 | default: |
742 | 0 | aResult = 0; |
743 | 0 | res = NS_ERROR_FAILURE; |
744 | 0 | } |
745 | 0 |
|
746 | 0 | return res; |
747 | 0 | } |
748 | | |
749 | | nsresult |
750 | | nsLookAndFeel::GetFloatImpl(FloatID aID, float &aResult) |
751 | 0 | { |
752 | 0 | nsresult res = NS_OK; |
753 | 0 | res = nsXPLookAndFeel::GetFloatImpl(aID, aResult); |
754 | 0 | if (NS_SUCCEEDED(res)) |
755 | 0 | return res; |
756 | 0 | res = NS_OK; |
757 | 0 |
|
758 | 0 | switch (aID) { |
759 | 0 | case eFloatID_IMEUnderlineRelativeSize: |
760 | 0 | aResult = 1.0f; |
761 | 0 | break; |
762 | 0 | case eFloatID_SpellCheckerUnderlineRelativeSize: |
763 | 0 | aResult = 1.0f; |
764 | 0 | break; |
765 | 0 | case eFloatID_CaretAspectRatio: |
766 | 0 | EnsureInit(); |
767 | 0 | aResult = mCaretRatio; |
768 | 0 | break; |
769 | 0 | default: |
770 | 0 | aResult = -1.0; |
771 | 0 | res = NS_ERROR_FAILURE; |
772 | 0 | } |
773 | 0 | return res; |
774 | 0 | } |
775 | | |
776 | | static void |
777 | | GetSystemFontInfo(GtkStyleContext *aStyle, |
778 | | nsString *aFontName, |
779 | | gfxFontStyle *aFontStyle) |
780 | 0 | { |
781 | 0 | aFontStyle->style = FontSlantStyle::Normal(); |
782 | 0 |
|
783 | 0 | // As in |
784 | 0 | // https://git.gnome.org/browse/gtk+/tree/gtk/gtkwidget.c?h=3.22.19#n10333 |
785 | 0 | PangoFontDescription *desc; |
786 | 0 | gtk_style_context_get(aStyle, gtk_style_context_get_state(aStyle), |
787 | 0 | "font", &desc, nullptr); |
788 | 0 |
|
789 | 0 | aFontStyle->systemFont = true; |
790 | 0 |
|
791 | 0 | NS_NAMED_LITERAL_STRING(quote, "\""); |
792 | 0 | NS_ConvertUTF8toUTF16 family(pango_font_description_get_family(desc)); |
793 | 0 | *aFontName = quote + family + quote; |
794 | 0 |
|
795 | 0 | aFontStyle->weight = FontWeight(pango_font_description_get_weight(desc)); |
796 | 0 |
|
797 | 0 | // FIXME: Set aFontStyle->stretch correctly! |
798 | 0 | aFontStyle->stretch = FontStretch::Normal(); |
799 | 0 |
|
800 | 0 | float size = float(pango_font_description_get_size(desc)) / PANGO_SCALE; |
801 | 0 |
|
802 | 0 | // |size| is now either pixels or pango-points (not Mozilla-points!) |
803 | 0 |
|
804 | 0 | if (!pango_font_description_get_size_is_absolute(desc)) { |
805 | 0 | // |size| is in pango-points, so convert to pixels. |
806 | 0 | size *= float(gfxPlatformGtk::GetFontScaleDPI()) / POINTS_PER_INCH_FLOAT; |
807 | 0 | } |
808 | 0 | // |size| is now pixels but not scaled for the hidpi displays, |
809 | 0 | // this needs to be done in GetFontImpl where the aDevPixPerCSSPixel |
810 | 0 | // parameter is provided. |
811 | 0 |
|
812 | 0 | aFontStyle->size = size; |
813 | 0 |
|
814 | 0 | pango_font_description_free(desc); |
815 | 0 | } |
816 | | |
817 | | bool |
818 | | nsLookAndFeel::GetFontImpl(FontID aID, nsString& aFontName, |
819 | | gfxFontStyle& aFontStyle, |
820 | | float aDevPixPerCSSPixel) |
821 | 0 | { |
822 | 0 | switch (aID) { |
823 | 0 | case eFont_Menu: // css2 |
824 | 0 | case eFont_PullDownMenu: // css3 |
825 | 0 | aFontName = mMenuFontName; |
826 | 0 | aFontStyle = mMenuFontStyle; |
827 | 0 | break; |
828 | 0 |
|
829 | 0 | case eFont_Field: // css3 |
830 | 0 | case eFont_List: // css3 |
831 | 0 | aFontName = mFieldFontName; |
832 | 0 | aFontStyle = mFieldFontStyle; |
833 | 0 | break; |
834 | 0 |
|
835 | 0 | case eFont_Button: // css3 |
836 | 0 | aFontName = mButtonFontName; |
837 | 0 | aFontStyle = mButtonFontStyle; |
838 | 0 | break; |
839 | 0 |
|
840 | 0 | case eFont_Caption: // css2 |
841 | 0 | case eFont_Icon: // css2 |
842 | 0 | case eFont_MessageBox: // css2 |
843 | 0 | case eFont_SmallCaption: // css2 |
844 | 0 | case eFont_StatusBar: // css2 |
845 | 0 | case eFont_Window: // css3 |
846 | 0 | case eFont_Document: // css3 |
847 | 0 | case eFont_Workspace: // css3 |
848 | 0 | case eFont_Desktop: // css3 |
849 | 0 | case eFont_Info: // css3 |
850 | 0 | case eFont_Dialog: // css3 |
851 | 0 | case eFont_Tooltips: // moz |
852 | 0 | case eFont_Widget: // moz |
853 | 0 | default: |
854 | 0 | aFontName = mDefaultFontName; |
855 | 0 | aFontStyle = mDefaultFontStyle; |
856 | 0 | break; |
857 | 0 | } |
858 | 0 | // Scale the font for the current monitor |
859 | 0 | double scaleFactor = nsIWidget::DefaultScaleOverride(); |
860 | 0 | if (scaleFactor > 0) { |
861 | 0 | aFontStyle.size *= mozilla::widget::ScreenHelperGTK::GetGTKMonitorScaleFactor(); |
862 | 0 | } else { |
863 | 0 | // Remove effect of font scale because it has been already applied in |
864 | 0 | // GetSystemFontInfo |
865 | 0 | aFontStyle.size *= aDevPixPerCSSPixel / gfxPlatformGtk::GetFontScaleFactor(); |
866 | 0 | } |
867 | 0 | return true; |
868 | 0 | } |
869 | | |
870 | | void |
871 | | nsLookAndFeel::EnsureInit() |
872 | 0 | { |
873 | 0 | GdkColor colorValue; |
874 | 0 | GdkColor *colorValuePtr; |
875 | 0 |
|
876 | 0 | if (mInitialized) |
877 | 0 | return; |
878 | 0 | mInitialized = true; |
879 | 0 |
|
880 | 0 | // gtk does non threadsafe refcounting |
881 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
882 | 0 |
|
883 | 0 | GdkRGBA color; |
884 | 0 | GtkStyleContext *style; |
885 | 0 |
|
886 | 0 | // Gtk manages a screen's CSS in the settings object so we |
887 | 0 | // ask Gtk to create it explicitly. Otherwise we may end up |
888 | 0 | // with wrong color theme, see Bug 972382 |
889 | 0 | GtkSettings *settings = gtk_settings_get_for_screen(gdk_screen_get_default()); |
890 | 0 |
|
891 | 0 | // Dark themes interacts poorly with widget styling (see bug 1216658). |
892 | 0 | // We disable dark themes by default for all processes (chrome, web content) |
893 | 0 | // but allow user to overide it by prefs. |
894 | 0 | const gchar* dark_setting = "gtk-application-prefer-dark-theme"; |
895 | 0 | gboolean darkThemeDefault; |
896 | 0 | g_object_get(settings, dark_setting, &darkThemeDefault, nullptr); |
897 | 0 |
|
898 | 0 | // To avoid triggering reload of theme settings unnecessarily, only set the |
899 | 0 | // setting when necessary. |
900 | 0 | if (darkThemeDefault) { |
901 | 0 | bool allowDarkTheme; |
902 | 0 | if (XRE_IsContentProcess()) { |
903 | 0 | allowDarkTheme = |
904 | 0 | mozilla::Preferences::GetBool("widget.content.allow-gtk-dark-theme", |
905 | 0 | false); |
906 | 0 | } else { |
907 | 0 | allowDarkTheme = (PR_GetEnv("MOZ_ALLOW_GTK_DARK_THEME") != nullptr) || |
908 | 0 | mozilla::Preferences::GetBool("widget.chrome.allow-gtk-dark-theme", |
909 | 0 | false); |
910 | 0 | } |
911 | 0 | if (!allowDarkTheme) { |
912 | 0 | g_object_set(settings, dark_setting, FALSE, nullptr); |
913 | 0 | } |
914 | 0 | } |
915 | 0 |
|
916 | 0 | // Allow content Gtk theme override by pref, it's useful when styled Gtk+ |
917 | 0 | // widgets break web content. |
918 | 0 | if (XRE_IsContentProcess()) { |
919 | 0 | nsAutoCString contentThemeName; |
920 | 0 | mozilla::Preferences::GetCString("widget.content.gtk-theme-override", |
921 | 0 | contentThemeName); |
922 | 0 | if (!contentThemeName.IsEmpty()) { |
923 | 0 | g_object_set(settings, "gtk-theme-name", contentThemeName.get(), nullptr); |
924 | 0 | } |
925 | 0 | } |
926 | 0 |
|
927 | 0 | // The label is not added to a parent widget, but shared for constructing |
928 | 0 | // different style contexts. The node hierarchy is constructed only on |
929 | 0 | // the label style context. |
930 | 0 | GtkWidget *labelWidget = gtk_label_new("M"); |
931 | 0 | g_object_ref_sink(labelWidget); |
932 | 0 |
|
933 | 0 | // Scrollbar colors |
934 | 0 | style = GetStyleContext(MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL); |
935 | 0 | gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color); |
936 | 0 | mMozScrollbar = GDK_RGBA_TO_NS_RGBA(color); |
937 | 0 |
|
938 | 0 | // Window colors |
939 | 0 | style = GetStyleContext(MOZ_GTK_WINDOW); |
940 | 0 | gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color); |
941 | 0 | mMozWindowBackground = GDK_RGBA_TO_NS_RGBA(color); |
942 | 0 | gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color); |
943 | 0 | mMozWindowText = GDK_RGBA_TO_NS_RGBA(color); |
944 | 0 | gtk_style_context_get_border_color(style, GTK_STATE_FLAG_NORMAL, &color); |
945 | 0 | mMozWindowActiveBorder = GDK_RGBA_TO_NS_RGBA(color); |
946 | 0 | gtk_style_context_get_border_color(style, GTK_STATE_FLAG_INSENSITIVE, |
947 | 0 | &color); |
948 | 0 | mMozWindowInactiveBorder = GDK_RGBA_TO_NS_RGBA(color); |
949 | 0 | gtk_style_context_get_background_color(style, GTK_STATE_FLAG_INSENSITIVE, |
950 | 0 | &color); |
951 | 0 | mMozWindowInactiveCaption = GDK_RGBA_TO_NS_RGBA(color); |
952 | 0 |
|
953 | 0 | style = GetStyleContext(MOZ_GTK_WINDOW_CONTAINER); |
954 | 0 | { |
955 | 0 | GtkStyleContext* labelStyle = CreateStyleForWidget(labelWidget, style); |
956 | 0 | GetSystemFontInfo(labelStyle, &mDefaultFontName, &mDefaultFontStyle); |
957 | 0 | g_object_unref(labelStyle); |
958 | 0 | } |
959 | 0 |
|
960 | 0 | // tooltip foreground and background |
961 | 0 | style = GetStyleContext(MOZ_GTK_TOOLTIP); |
962 | 0 | gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color); |
963 | 0 | mInfoBackground = GDK_RGBA_TO_NS_RGBA(color); |
964 | 0 |
|
965 | 0 | style = GetStyleContext(MOZ_GTK_TOOLTIP_BOX_LABEL); |
966 | 0 | gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color); |
967 | 0 | mInfoText = GDK_RGBA_TO_NS_RGBA(color); |
968 | 0 |
|
969 | 0 | style = GetStyleContext(MOZ_GTK_MENUITEM); |
970 | 0 | { |
971 | 0 | GtkStyleContext* accelStyle = |
972 | 0 | CreateStyleForWidget(gtk_accel_label_new("M"), style); |
973 | 0 |
|
974 | 0 | GetSystemFontInfo(accelStyle, &mMenuFontName, &mMenuFontStyle); |
975 | 0 |
|
976 | 0 | gtk_style_context_get_color(accelStyle, GTK_STATE_FLAG_NORMAL, &color); |
977 | 0 | mMenuText = GDK_RGBA_TO_NS_RGBA(color); |
978 | 0 | gtk_style_context_get_color(accelStyle, GTK_STATE_FLAG_INSENSITIVE, &color); |
979 | 0 | mMenuTextInactive = GDK_RGBA_TO_NS_RGBA(color); |
980 | 0 | g_object_unref(accelStyle); |
981 | 0 | } |
982 | 0 |
|
983 | 0 | style = GetStyleContext(MOZ_GTK_MENUPOPUP); |
984 | 0 | gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color); |
985 | 0 | mMenuBackground = GDK_RGBA_TO_NS_RGBA(color); |
986 | 0 |
|
987 | 0 | style = GetStyleContext(MOZ_GTK_MENUITEM); |
988 | 0 | gtk_style_context_get_background_color(style, GTK_STATE_FLAG_PRELIGHT, &color); |
989 | 0 | mMenuHover = GDK_RGBA_TO_NS_RGBA(color); |
990 | 0 | gtk_style_context_get_color(style, GTK_STATE_FLAG_PRELIGHT, &color); |
991 | 0 | mMenuHoverText = GDK_RGBA_TO_NS_RGBA(color); |
992 | 0 |
|
993 | 0 | GtkWidget *parent = gtk_fixed_new(); |
994 | 0 | GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP); |
995 | 0 | GtkWidget *treeView = gtk_tree_view_new(); |
996 | 0 | GtkWidget *linkButton = gtk_link_button_new("http://example.com/"); |
997 | 0 | GtkWidget *menuBar = gtk_menu_bar_new(); |
998 | 0 | GtkWidget *menuBarItem = gtk_menu_item_new(); |
999 | 0 | GtkWidget *entry = gtk_entry_new(); |
1000 | 0 | GtkWidget *textView = gtk_text_view_new(); |
1001 | 0 |
|
1002 | 0 | gtk_container_add(GTK_CONTAINER(parent), treeView); |
1003 | 0 | gtk_container_add(GTK_CONTAINER(parent), linkButton); |
1004 | 0 | gtk_container_add(GTK_CONTAINER(parent), menuBar); |
1005 | 0 | gtk_menu_shell_append(GTK_MENU_SHELL(menuBar), menuBarItem); |
1006 | 0 | gtk_container_add(GTK_CONTAINER(window), parent); |
1007 | 0 | gtk_container_add(GTK_CONTAINER(parent), entry); |
1008 | 0 | gtk_container_add(GTK_CONTAINER(parent), textView); |
1009 | 0 |
|
1010 | 0 | // Text colors |
1011 | 0 | GdkRGBA bgColor; |
1012 | 0 | // If the text window background is translucent, then the background of |
1013 | 0 | // the textview root node is visible. |
1014 | 0 | style = GetStyleContext(MOZ_GTK_TEXT_VIEW); |
1015 | 0 | gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, |
1016 | 0 | &bgColor); |
1017 | 0 |
|
1018 | 0 | style = GetStyleContext(MOZ_GTK_TEXT_VIEW_TEXT); |
1019 | 0 | gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, |
1020 | 0 | &color); |
1021 | 0 | ApplyColorOver(color, &bgColor); |
1022 | 0 | mMozFieldBackground = GDK_RGBA_TO_NS_RGBA(bgColor); |
1023 | 0 | gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color); |
1024 | 0 | mMozFieldText = GDK_RGBA_TO_NS_RGBA(color); |
1025 | 0 |
|
1026 | 0 | // Selected text and background |
1027 | 0 | gtk_style_context_get_background_color(style, |
1028 | 0 | static_cast<GtkStateFlags>(GTK_STATE_FLAG_FOCUSED|GTK_STATE_FLAG_SELECTED), |
1029 | 0 | &color); |
1030 | 0 | mTextSelectedBackground = GDK_RGBA_TO_NS_RGBA(color); |
1031 | 0 | gtk_style_context_get_color(style, |
1032 | 0 | static_cast<GtkStateFlags>(GTK_STATE_FLAG_FOCUSED|GTK_STATE_FLAG_SELECTED), |
1033 | 0 | &color); |
1034 | 0 | mTextSelectedText = GDK_RGBA_TO_NS_RGBA(color); |
1035 | 0 |
|
1036 | 0 | // Button text color |
1037 | 0 | style = GetStyleContext(MOZ_GTK_BUTTON); |
1038 | 0 | { |
1039 | 0 | GtkStyleContext* labelStyle = CreateStyleForWidget(labelWidget, style); |
1040 | 0 |
|
1041 | 0 | GetSystemFontInfo(labelStyle, &mButtonFontName, &mButtonFontStyle); |
1042 | 0 |
|
1043 | 0 | gtk_style_context_get_border_color(style, GTK_STATE_FLAG_NORMAL, &color); |
1044 | 0 | mButtonDefault = GDK_RGBA_TO_NS_RGBA(color); |
1045 | 0 | gtk_style_context_get_color(labelStyle, GTK_STATE_FLAG_NORMAL, &color); |
1046 | 0 | mButtonText = GDK_RGBA_TO_NS_RGBA(color); |
1047 | 0 | gtk_style_context_get_color(labelStyle, GTK_STATE_FLAG_PRELIGHT, &color); |
1048 | 0 | mButtonHoverText = GDK_RGBA_TO_NS_RGBA(color); |
1049 | 0 | gtk_style_context_get_background_color(style, GTK_STATE_FLAG_PRELIGHT, |
1050 | 0 | &color); |
1051 | 0 | mButtonHoverFace = GDK_RGBA_TO_NS_RGBA(color); |
1052 | 0 | g_object_unref(labelStyle); |
1053 | 0 | } |
1054 | 0 |
|
1055 | 0 | // Combobox text color |
1056 | 0 | style = GetStyleContext(MOZ_GTK_COMBOBOX_ENTRY_TEXTAREA); |
1057 | 0 | gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color); |
1058 | 0 | mComboBoxText = GDK_RGBA_TO_NS_RGBA(color); |
1059 | 0 |
|
1060 | 0 | // Menubar text and hover text colors |
1061 | 0 | style = GetStyleContext(MOZ_GTK_MENUBARITEM); |
1062 | 0 | gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color); |
1063 | 0 | mMenuBarText = GDK_RGBA_TO_NS_RGBA(color); |
1064 | 0 | gtk_style_context_get_color(style, GTK_STATE_FLAG_PRELIGHT, &color); |
1065 | 0 | mMenuBarHoverText = GDK_RGBA_TO_NS_RGBA(color); |
1066 | 0 |
|
1067 | 0 | // GTK's guide to fancy odd row background colors: |
1068 | 0 | // 1) Check if a theme explicitly defines an odd row color |
1069 | 0 | // 2) If not, check if it defines an even row color, and darken it |
1070 | 0 | // slightly by a hardcoded value (gtkstyle.c) |
1071 | 0 | // 3) If neither are defined, take the base background color and |
1072 | 0 | // darken that by a hardcoded value |
1073 | 0 | style = GetStyleContext(MOZ_GTK_TREEVIEW); |
1074 | 0 |
|
1075 | 0 | // Get odd row background color |
1076 | 0 | gtk_style_context_save(style); |
1077 | 0 | gtk_style_context_add_region(style, GTK_STYLE_REGION_ROW, GTK_REGION_ODD); |
1078 | 0 | gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color); |
1079 | 0 | mOddCellBackground = GDK_RGBA_TO_NS_RGBA(color); |
1080 | 0 | gtk_style_context_restore(style); |
1081 | 0 |
|
1082 | 0 | // Compute cell highlight colors |
1083 | 0 | InitCellHighlightColors(); |
1084 | 0 |
|
1085 | 0 | // GtkFrame has a "border" subnode on which Adwaita draws the border. |
1086 | 0 | // Some themes do not draw on this node but draw a border on the widget |
1087 | 0 | // root node, so check the root node if no border is found on the border |
1088 | 0 | // node. |
1089 | 0 | style = GetStyleContext(MOZ_GTK_FRAME_BORDER); |
1090 | 0 | bool themeUsesColors = |
1091 | 0 | GetBorderColors(style, &mFrameOuterLightBorder, &mFrameInnerDarkBorder); |
1092 | 0 | if (!themeUsesColors) { |
1093 | 0 | style = GetStyleContext(MOZ_GTK_FRAME); |
1094 | 0 | GetBorderColors(style, &mFrameOuterLightBorder, &mFrameInnerDarkBorder); |
1095 | 0 | } |
1096 | 0 |
|
1097 | 0 | // GtkInfoBar |
1098 | 0 | // TODO - Use WidgetCache for it? |
1099 | 0 | GtkWidget* infoBar = gtk_info_bar_new(); |
1100 | 0 | GtkWidget* infoBarContent = gtk_info_bar_get_content_area(GTK_INFO_BAR(infoBar)); |
1101 | 0 | GtkWidget* infoBarLabel = gtk_label_new(nullptr); |
1102 | 0 | gtk_container_add(GTK_CONTAINER(parent), infoBar); |
1103 | 0 | gtk_container_add(GTK_CONTAINER(infoBarContent), infoBarLabel); |
1104 | 0 | style = gtk_widget_get_style_context(infoBarLabel); |
1105 | 0 | gtk_style_context_add_class(style, GTK_STYLE_CLASS_INFO); |
1106 | 0 | gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color); |
1107 | 0 | mInfoBarText = GDK_RGBA_TO_NS_RGBA(color); |
1108 | 0 | // Some themes have a unified menu bar, and support window dragging on it |
1109 | 0 | gboolean supports_menubar_drag = FALSE; |
1110 | 0 | GParamSpec *param_spec = |
1111 | 0 | gtk_widget_class_find_style_property(GTK_WIDGET_GET_CLASS(menuBar), |
1112 | 0 | "window-dragging"); |
1113 | 0 | if (param_spec) { |
1114 | 0 | if (g_type_is_a(G_PARAM_SPEC_VALUE_TYPE(param_spec), G_TYPE_BOOLEAN)) { |
1115 | 0 | gtk_widget_style_get(menuBar, |
1116 | 0 | "window-dragging", &supports_menubar_drag, |
1117 | 0 | nullptr); |
1118 | 0 | } |
1119 | 0 | } |
1120 | 0 | mMenuSupportsDrag = supports_menubar_drag; |
1121 | 0 |
|
1122 | 0 | if (gtk_check_version(3, 12, 0) == nullptr) { |
1123 | 0 | // TODO: It returns wrong color for themes which |
1124 | 0 | // sets link color for GtkLabel only as we query |
1125 | 0 | // GtkLinkButton style here. |
1126 | 0 | style = gtk_widget_get_style_context(linkButton); |
1127 | 0 | gtk_style_context_get_color(style, GTK_STATE_FLAG_LINK, &color); |
1128 | 0 | mNativeHyperLinkText = GDK_RGBA_TO_NS_RGBA(color); |
1129 | 0 | } else { |
1130 | 0 | colorValuePtr = nullptr; |
1131 | 0 | gtk_widget_style_get(linkButton, "link-color", &colorValuePtr, nullptr); |
1132 | 0 | if (colorValuePtr) { |
1133 | 0 | colorValue = *colorValuePtr; // we can't pass deref pointers to GDK_COLOR_TO_NS_RGB |
1134 | 0 | mNativeHyperLinkText = GDK_COLOR_TO_NS_RGB(colorValue); |
1135 | 0 | gdk_color_free(colorValuePtr); |
1136 | 0 | } else { |
1137 | 0 | mNativeHyperLinkText = NS_RGB(0x00,0x00,0xEE); |
1138 | 0 | } |
1139 | 0 | } |
1140 | 0 |
|
1141 | 0 | // invisible character styles |
1142 | 0 | guint value; |
1143 | 0 | g_object_get (entry, "invisible-char", &value, nullptr); |
1144 | 0 | mInvisibleCharacter = char16_t(value); |
1145 | 0 |
|
1146 | 0 | // caret styles |
1147 | 0 | gtk_widget_style_get(entry, |
1148 | 0 | "cursor-aspect-ratio", &mCaretRatio, |
1149 | 0 | nullptr); |
1150 | 0 |
|
1151 | 0 | GetSystemFontInfo(gtk_widget_get_style_context(entry), |
1152 | 0 | &mFieldFontName, &mFieldFontStyle); |
1153 | 0 |
|
1154 | 0 | gtk_widget_destroy(window); |
1155 | 0 | g_object_unref(labelWidget); |
1156 | 0 |
|
1157 | 0 | mCSDAvailable = |
1158 | 0 | nsWindow::GetSystemCSDSupportLevel() != nsWindow::CSD_SUPPORT_NONE; |
1159 | 0 |
|
1160 | 0 | mCSDCloseButton = false; |
1161 | 0 | mCSDMinimizeButton = false; |
1162 | 0 | mCSDMaximizeButton = false; |
1163 | 0 |
|
1164 | 0 | // We need to initialize whole CSD config explicitly because it's queried |
1165 | 0 | // as -moz-gtk* media features. |
1166 | 0 | WidgetNodeType buttonLayout[TOOLBAR_BUTTONS]; |
1167 | 0 |
|
1168 | 0 | int activeButtons = |
1169 | 0 | GetGtkHeaderBarButtonLayout(buttonLayout, TOOLBAR_BUTTONS); |
1170 | 0 | for (int i = 0; i < activeButtons; i++) { |
1171 | 0 | switch(buttonLayout[i]) { |
1172 | 0 | case MOZ_GTK_HEADER_BAR_BUTTON_MINIMIZE: |
1173 | 0 | mCSDMinimizeButton = true; |
1174 | 0 | break; |
1175 | 0 | case MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE: |
1176 | 0 | mCSDMaximizeButton = true; |
1177 | 0 | break; |
1178 | 0 | case MOZ_GTK_HEADER_BAR_BUTTON_CLOSE: |
1179 | 0 | mCSDCloseButton = true; |
1180 | 0 | break; |
1181 | 0 | default: |
1182 | 0 | break; |
1183 | 0 | } |
1184 | 0 | } |
1185 | 0 | } |
1186 | | |
1187 | | // virtual |
1188 | | char16_t |
1189 | | nsLookAndFeel::GetPasswordCharacterImpl() |
1190 | 0 | { |
1191 | 0 | EnsureInit(); |
1192 | 0 | return mInvisibleCharacter; |
1193 | 0 | } |
1194 | | |
1195 | | bool |
1196 | 0 | nsLookAndFeel::GetEchoPasswordImpl() { |
1197 | 0 | return false; |
1198 | 0 | } |