1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim:expandtab:shiftwidth=4:tabstop=4:
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/. */
11 #include "nsLookAndFeel.h"
16 #include <pango/pango.h>
17 #include <pango/pango-fontmap.h>
19 #include <fontconfig/fontconfig.h>
20 #include "gfxPlatformGtk.h"
22 #include "gtkdrawing.h"
23 #include "nsStyleConsts.h"
24 #include "gfxFontConstants.h"
28 #include "mozilla/gfx/2D.h"
30 using mozilla::LookAndFeel
;
32 #define GDK_COLOR_TO_NS_RGB(c) \
33 ((nscolor) NS_RGB(c.red>>8, c.green>>8, c.blue>>8))
34 #define GDK_RGBA_TO_NS_RGBA(c) \
35 ((nscolor) NS_RGBA((int)((c).red*255), (int)((c).green*255), \
36 (int)((c).blue*255), (int)((c).alpha*255)))
38 nsLookAndFeel::nsLookAndFeel()
40 #if (MOZ_WIDGET_GTK == 2)
43 mBackgroundStyle(nullptr),
44 mButtonStyle(nullptr),
46 mDefaultFontCached(false), mButtonFontCached(false),
47 mFieldFontCached(false), mMenuFontCached(false)
52 nsLookAndFeel::~nsLookAndFeel()
54 #if (MOZ_WIDGET_GTK == 2)
55 g_object_unref(mStyle
);
57 g_object_unref(mBackgroundStyle
);
58 g_object_unref(mButtonStyle
);
63 nsLookAndFeel::NativeGetColor(ColorID aID
, nscolor
& aColor
)
65 #if (MOZ_WIDGET_GTK == 3)
71 // These colors don't seem to be used for anything anymore in Mozilla
72 // (except here at least TextSelectBackground and TextSelectForeground)
73 // The CSS2 colors below are used.
74 #if (MOZ_WIDGET_GTK == 2)
75 case eColorID_WindowBackground
:
76 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->base
[GTK_STATE_NORMAL
]);
78 case eColorID_WindowForeground
:
79 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->text
[GTK_STATE_NORMAL
]);
81 case eColorID_WidgetBackground
:
82 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->bg
[GTK_STATE_NORMAL
]);
84 case eColorID_WidgetForeground
:
85 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->fg
[GTK_STATE_NORMAL
]);
87 case eColorID_WidgetSelectBackground
:
88 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->bg
[GTK_STATE_SELECTED
]);
90 case eColorID_WidgetSelectForeground
:
91 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->fg
[GTK_STATE_SELECTED
]);
94 case eColorID_WindowBackground
:
95 case eColorID_WidgetBackground
:
96 case eColorID_TextBackground
:
97 case eColorID_activecaption
: // active window caption background
98 case eColorID_appworkspace
: // MDI background color
99 case eColorID_background
: // desktop background
100 case eColorID_window
:
101 case eColorID_windowframe
:
102 case eColorID__moz_dialog
:
103 aColor
= sMozWindowBackground
;
105 case eColorID_WindowForeground
:
106 case eColorID_WidgetForeground
:
107 case eColorID_TextForeground
:
108 case eColorID_captiontext
: // text in active window caption, size box, and scrollbar arrow box (!)
109 case eColorID_windowtext
:
110 case eColorID__moz_dialogtext
:
111 aColor
= sMozWindowText
;
113 case eColorID_WidgetSelectBackground
:
114 case eColorID_TextSelectBackground
:
115 case eColorID_IMESelectedRawTextBackground
:
116 case eColorID_IMESelectedConvertedTextBackground
:
117 case eColorID__moz_dragtargetzone
:
118 case eColorID__moz_cellhighlight
:
119 case eColorID__moz_html_cellhighlight
:
120 case eColorID_highlight
: // preference selected item,
121 aColor
= sTextSelectedBackground
;
123 case eColorID_WidgetSelectForeground
:
124 case eColorID_TextSelectForeground
:
125 case eColorID_IMESelectedRawTextForeground
:
126 case eColorID_IMESelectedConvertedTextForeground
:
127 case eColorID_highlighttext
:
128 case eColorID__moz_cellhighlighttext
:
129 case eColorID__moz_html_cellhighlighttext
:
130 aColor
= sTextSelectedText
;
133 case eColorID_Widget3DHighlight
:
134 aColor
= NS_RGB(0xa0,0xa0,0xa0);
136 case eColorID_Widget3DShadow
:
137 aColor
= NS_RGB(0x40,0x40,0x40);
139 #if (MOZ_WIDGET_GTK == 2)
140 case eColorID_TextBackground
:
142 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->base
[GTK_STATE_NORMAL
]);
144 case eColorID_TextForeground
:
146 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->text
[GTK_STATE_NORMAL
]);
148 case eColorID_TextSelectBackground
:
149 case eColorID_IMESelectedRawTextBackground
:
150 case eColorID_IMESelectedConvertedTextBackground
:
152 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->base
[GTK_STATE_SELECTED
]);
154 case eColorID_TextSelectForeground
:
155 case eColorID_IMESelectedRawTextForeground
:
156 case eColorID_IMESelectedConvertedTextForeground
:
158 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->text
[GTK_STATE_SELECTED
]);
161 case eColorID_IMERawInputBackground
:
162 case eColorID_IMEConvertedTextBackground
:
163 aColor
= NS_TRANSPARENT
;
165 case eColorID_IMERawInputForeground
:
166 case eColorID_IMEConvertedTextForeground
:
167 aColor
= NS_SAME_AS_FOREGROUND_COLOR
;
169 case eColorID_IMERawInputUnderline
:
170 case eColorID_IMEConvertedTextUnderline
:
171 aColor
= NS_SAME_AS_FOREGROUND_COLOR
;
173 case eColorID_IMESelectedRawTextUnderline
:
174 case eColorID_IMESelectedConvertedTextUnderline
:
175 aColor
= NS_TRANSPARENT
;
177 case eColorID_SpellCheckerUnderline
:
178 aColor
= NS_RGB(0xff, 0, 0);
181 #if (MOZ_WIDGET_GTK == 2)
182 // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
183 case eColorID_activeborder
:
184 // active window border
185 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->bg
[GTK_STATE_NORMAL
]);
187 case eColorID_activecaption
:
188 // active window caption background
189 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->bg
[GTK_STATE_NORMAL
]);
191 case eColorID_appworkspace
:
192 // MDI background color
193 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->bg
[GTK_STATE_NORMAL
]);
195 case eColorID_background
:
196 // desktop background
197 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->bg
[GTK_STATE_NORMAL
]);
199 case eColorID_captiontext
:
200 // text in active window caption, size box, and scrollbar arrow box (!)
201 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->fg
[GTK_STATE_NORMAL
]);
203 case eColorID_graytext
:
204 // disabled text in windows, menus, etc.
205 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->fg
[GTK_STATE_INSENSITIVE
]);
207 case eColorID_highlight
:
208 // background of selected item
209 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->base
[GTK_STATE_SELECTED
]);
211 case eColorID_highlighttext
:
212 // text of selected item
213 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->text
[GTK_STATE_SELECTED
]);
215 case eColorID_inactiveborder
:
216 // inactive window border
217 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->bg
[GTK_STATE_NORMAL
]);
219 case eColorID_inactivecaption
:
220 // inactive window caption
221 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->bg
[GTK_STATE_INSENSITIVE
]);
223 case eColorID_inactivecaptiontext
:
224 // text in inactive window caption
225 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->fg
[GTK_STATE_INSENSITIVE
]);
228 // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
229 case eColorID_activeborder
:
230 // active window border
231 gtk_style_context_get_border_color(mBackgroundStyle
,
232 GTK_STATE_FLAG_NORMAL
, &gdk_color
);
233 aColor
= GDK_RGBA_TO_NS_RGBA(gdk_color
);
235 case eColorID_inactiveborder
:
236 // inactive window border
237 gtk_style_context_get_border_color(mBackgroundStyle
,
238 GTK_STATE_FLAG_INSENSITIVE
,
240 aColor
= GDK_RGBA_TO_NS_RGBA(gdk_color
);
242 case eColorID_graytext
: // disabled text in windows, menus, etc.
243 case eColorID_inactivecaptiontext
: // text in inactive window caption
244 gtk_style_context_get_color(mBackgroundStyle
,
245 GTK_STATE_FLAG_INSENSITIVE
, &gdk_color
);
246 aColor
= GDK_RGBA_TO_NS_RGBA(gdk_color
);
248 case eColorID_inactivecaption
:
249 // inactive window caption
250 gtk_style_context_get_background_color(mBackgroundStyle
,
251 GTK_STATE_FLAG_INSENSITIVE
,
253 aColor
= GDK_RGBA_TO_NS_RGBA(gdk_color
);
256 case eColorID_infobackground
:
257 // tooltip background color
258 aColor
= sInfoBackground
;
260 case eColorID_infotext
:
261 // tooltip text color
266 aColor
= sMenuBackground
;
268 case eColorID_menutext
:
272 case eColorID_scrollbar
:
273 // scrollbar gray area
274 #if (MOZ_WIDGET_GTK == 2)
275 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->bg
[GTK_STATE_ACTIVE
]);
277 aColor
= sMozScrollbar
;
281 case eColorID_threedlightshadow
:
282 // 3-D highlighted inner edge color
283 // always same as background in GTK code
284 case eColorID_threedface
:
285 case eColorID_buttonface
:
287 #if (MOZ_WIDGET_GTK == 3)
288 aColor
= sMozWindowBackground
;
290 aColor
= sButtonBackground
;
294 case eColorID_buttontext
:
295 // text on push buttons
296 aColor
= sButtonText
;
299 case eColorID_buttonhighlight
:
300 // 3-D highlighted edge color
301 case eColorID_threedhighlight
:
302 // 3-D highlighted outer edge color
303 aColor
= sFrameOuterLightBorder
;
306 case eColorID_buttonshadow
:
307 // 3-D shadow edge color
308 case eColorID_threedshadow
:
309 // 3-D shadow inner edge color
310 aColor
= sFrameInnerDarkBorder
;
313 #if (MOZ_WIDGET_GTK == 2)
314 case eColorID_threeddarkshadow
:
315 // 3-D shadow outer edge color
316 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->black
);
319 case eColorID_window
:
320 case eColorID_windowframe
:
321 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->bg
[GTK_STATE_NORMAL
]);
324 case eColorID_windowtext
:
325 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->fg
[GTK_STATE_NORMAL
]);
328 case eColorID__moz_eventreerow
:
329 case eColorID__moz_field
:
330 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->base
[GTK_STATE_NORMAL
]);
332 case eColorID__moz_fieldtext
:
333 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->text
[GTK_STATE_NORMAL
]);
335 case eColorID__moz_dialog
:
336 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->bg
[GTK_STATE_NORMAL
]);
338 case eColorID__moz_dialogtext
:
339 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->fg
[GTK_STATE_NORMAL
]);
341 case eColorID__moz_dragtargetzone
:
342 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->bg
[GTK_STATE_SELECTED
]);
344 case eColorID__moz_buttondefault
:
345 // default button border color
346 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->black
);
348 case eColorID__moz_buttonhoverface
:
349 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->bg
[GTK_STATE_PRELIGHT
]);
351 case eColorID__moz_buttonhovertext
:
352 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->fg
[GTK_STATE_PRELIGHT
]);
354 case eColorID__moz_cellhighlight
:
355 case eColorID__moz_html_cellhighlight
:
356 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->base
[GTK_STATE_ACTIVE
]);
358 case eColorID__moz_cellhighlighttext
:
359 case eColorID__moz_html_cellhighlighttext
:
360 aColor
= GDK_COLOR_TO_NS_RGB(mStyle
->text
[GTK_STATE_ACTIVE
]);
363 case eColorID_threeddarkshadow
:
365 aColor
= NS_RGB(0x00,0x00,0x00);;
368 case eColorID__moz_eventreerow
:
369 case eColorID__moz_field
:
370 aColor
= sMozFieldBackground
;
372 case eColorID__moz_fieldtext
:
373 aColor
= sMozFieldText
;
375 case eColorID__moz_buttondefault
:
376 // default button border color
377 gtk_style_context_get_border_color(mButtonStyle
,
378 GTK_STATE_FLAG_NORMAL
, &gdk_color
);
379 aColor
= GDK_RGBA_TO_NS_RGBA(gdk_color
);
381 case eColorID__moz_buttonhoverface
:
382 gtk_style_context_get_background_color(mButtonStyle
,
383 GTK_STATE_FLAG_PRELIGHT
,
385 aColor
= GDK_RGBA_TO_NS_RGBA(gdk_color
);
387 case eColorID__moz_buttonhovertext
:
388 aColor
= sButtonHoverText
;
391 case eColorID__moz_menuhover
:
394 case eColorID__moz_menuhovertext
:
395 aColor
= sMenuHoverText
;
397 case eColorID__moz_oddtreerow
:
398 aColor
= sOddCellBackground
;
400 case eColorID__moz_nativehyperlinktext
:
401 aColor
= sNativeHyperLinkText
;
403 case eColorID__moz_comboboxtext
:
404 aColor
= sComboBoxText
;
406 case eColorID__moz_combobox
:
407 aColor
= sComboBoxBackground
;
409 case eColorID__moz_menubartext
:
410 aColor
= sMenuBarText
;
412 case eColorID__moz_menubarhovertext
:
413 aColor
= sMenuBarHoverText
;
416 /* default color is BLACK */
418 res
= NS_ERROR_FAILURE
;
425 #if (MOZ_WIDGET_GTK == 2)
426 static void darken_gdk_color(GdkColor
*src
, GdkColor
*dest
)
432 red
= (gdouble
) src
->red
/ 65535.0;
433 green
= (gdouble
) src
->green
/ 65535.0;
434 blue
= (gdouble
) src
->blue
/ 65535.0;
440 dest
->red
= red
* 65535.0;
441 dest
->green
= green
* 65535.0;
442 dest
->blue
= blue
* 65535.0;
446 static int32_t CheckWidgetStyle(GtkWidget
* aWidget
, const char* aStyle
, int32_t aResult
) {
447 gboolean value
= FALSE
;
448 gtk_widget_style_get(aWidget
, aStyle
, &value
, nullptr);
449 return value
? aResult
: 0;
452 static int32_t ConvertGTKStepperStyleToMozillaScrollArrowStyle(GtkWidget
* aWidget
)
455 return mozilla::LookAndFeel::eScrollArrowStyle_Single
;
458 CheckWidgetStyle(aWidget
, "has-backward-stepper",
459 mozilla::LookAndFeel::eScrollArrow_StartBackward
) |
460 CheckWidgetStyle(aWidget
, "has-forward-stepper",
461 mozilla::LookAndFeel::eScrollArrow_EndForward
) |
462 CheckWidgetStyle(aWidget
, "has-secondary-backward-stepper",
463 mozilla::LookAndFeel::eScrollArrow_EndBackward
) |
464 CheckWidgetStyle(aWidget
, "has-secondary-forward-stepper",
465 mozilla::LookAndFeel::eScrollArrow_StartForward
);
469 nsLookAndFeel::GetIntImpl(IntID aID
, int32_t &aResult
)
471 nsresult res
= NS_OK
;
473 // Set these before they can get overrided in the nsXPLookAndFeel.
475 case eIntID_ScrollButtonLeftMouseButtonAction
:
478 case eIntID_ScrollButtonMiddleMouseButtonAction
:
481 case eIntID_ScrollButtonRightMouseButtonAction
:
488 res
= nsXPLookAndFeel::GetIntImpl(aID
, aResult
);
489 if (NS_SUCCEEDED(res
))
494 case eIntID_CaretBlinkTime
:
496 GtkSettings
*settings
;
500 settings
= gtk_settings_get_default ();
501 g_object_get (settings
,
502 "gtk-cursor-blink-time", &blink_time
,
503 "gtk-cursor-blink", &blink
,
507 aResult
= (int32_t) blink_time
;
512 case eIntID_CaretWidth
:
515 case eIntID_ShowCaretDuringSelection
:
518 case eIntID_SelectTextfieldsOnKeyFocus
:
521 GtkSettings
*settings
;
522 gboolean select_on_focus
;
524 entry
= gtk_entry_new();
525 g_object_ref_sink(entry
);
526 settings
= gtk_widget_get_settings(entry
);
527 g_object_get(settings
,
528 "gtk-entry-select-on-focus",
537 gtk_widget_destroy(entry
);
538 g_object_unref(entry
);
541 case eIntID_ScrollToClick
:
543 GtkSettings
*settings
;
544 gboolean warps_slider
= FALSE
;
546 settings
= gtk_settings_get_default ();
547 if (g_object_class_find_property (G_OBJECT_GET_CLASS(settings
),
548 "gtk-primary-button-warps-slider")) {
549 g_object_get (settings
,
550 "gtk-primary-button-warps-slider",
561 case eIntID_SubmenuDelay
:
563 GtkSettings
*settings
;
566 settings
= gtk_settings_get_default ();
567 g_object_get (settings
, "gtk-menu-popup-delay", &delay
, nullptr);
568 aResult
= (int32_t) delay
;
571 case eIntID_TooltipDelay
:
576 case eIntID_MenusCanOverlapOSBar
:
577 // we want XUL popups to be able to overlap the task bar.
580 case eIntID_SkipNavigatingDisabledMenuItem
:
583 case eIntID_DragThresholdX
:
584 case eIntID_DragThresholdY
:
586 GtkWidget
* box
= gtk_hbox_new(FALSE
, 5);
588 g_object_get(gtk_widget_get_settings(box
),
589 "gtk-dnd-drag-threshold", &threshold
,
591 g_object_ref_sink(box
);
596 case eIntID_ScrollArrowStyle
:
599 ConvertGTKStepperStyleToMozillaScrollArrowStyle(moz_gtk_get_scrollbar_widget());
601 case eIntID_ScrollSliderStyle
:
602 aResult
= eScrollThumbStyle_Proportional
;
604 case eIntID_TreeOpenDelay
:
607 case eIntID_TreeCloseDelay
:
610 case eIntID_TreeLazyScrollDelay
:
613 case eIntID_TreeScrollDelay
:
616 case eIntID_TreeScrollLinesMax
:
619 case eIntID_DWMCompositor
:
620 case eIntID_WindowsClassic
:
621 case eIntID_WindowsDefaultTheme
:
622 case eIntID_WindowsThemeIdentifier
:
623 case eIntID_OperatingSystemVersionIdentifier
:
625 res
= NS_ERROR_NOT_IMPLEMENTED
;
627 case eIntID_TouchEnabled
:
629 res
= NS_ERROR_NOT_IMPLEMENTED
;
631 case eIntID_MacGraphiteTheme
:
632 case eIntID_MacLionTheme
:
634 res
= NS_ERROR_NOT_IMPLEMENTED
;
636 case eIntID_AlertNotificationOrigin
:
637 aResult
= NS_ALERT_TOP
;
639 case eIntID_IMERawInputUnderlineStyle
:
640 case eIntID_IMEConvertedTextUnderlineStyle
:
641 aResult
= NS_STYLE_TEXT_DECORATION_STYLE_SOLID
;
643 case eIntID_IMESelectedRawTextUnderlineStyle
:
644 case eIntID_IMESelectedConvertedTextUnderline
:
645 aResult
= NS_STYLE_TEXT_DECORATION_STYLE_NONE
;
647 case eIntID_SpellCheckerUnderlineStyle
:
648 aResult
= NS_STYLE_TEXT_DECORATION_STYLE_WAVY
;
650 case eIntID_ImagesInMenus
:
651 aResult
= moz_gtk_images_in_menus();
653 case eIntID_ImagesInButtons
:
654 aResult
= moz_gtk_images_in_buttons();
656 case eIntID_MenuBarDrag
:
657 aResult
= sMenuSupportsDrag
;
659 case eIntID_ScrollbarButtonAutoRepeatBehavior
:
662 case eIntID_SwipeAnimationEnabled
:
665 case eIntID_ColorPickerAvailable
:
670 res
= NS_ERROR_FAILURE
;
677 nsLookAndFeel::GetFloatImpl(FloatID aID
, float &aResult
)
679 nsresult res
= NS_OK
;
680 res
= nsXPLookAndFeel::GetFloatImpl(aID
, aResult
);
681 if (NS_SUCCEEDED(res
))
686 case eFloatID_IMEUnderlineRelativeSize
:
689 case eFloatID_SpellCheckerUnderlineRelativeSize
:
692 case eFloatID_CaretAspectRatio
:
693 aResult
= sCaretRatio
;
697 res
= NS_ERROR_FAILURE
;
703 GetSystemFontInfo(GtkWidget
*aWidget
,
705 gfxFontStyle
*aFontStyle
)
707 GtkSettings
*settings
= gtk_widget_get_settings(aWidget
);
709 aFontStyle
->style
= NS_FONT_STYLE_NORMAL
;
712 g_object_get(settings
, "gtk-font-name", &fontname
, nullptr);
714 PangoFontDescription
*desc
;
715 desc
= pango_font_description_from_string(fontname
);
717 aFontStyle
->systemFont
= true;
721 NS_NAMED_LITERAL_STRING(quote
, "\"");
722 NS_ConvertUTF8toUTF16
family(pango_font_description_get_family(desc
));
723 *aFontName
= quote
+ family
+ quote
;
725 aFontStyle
->weight
= pango_font_description_get_weight(desc
);
727 // FIXME: Set aFontStyle->stretch correctly!
728 aFontStyle
->stretch
= NS_FONT_STRETCH_NORMAL
;
730 float size
= float(pango_font_description_get_size(desc
)) / PANGO_SCALE
;
732 // |size| is now either pixels or pango-points (not Mozilla-points!)
734 if (!pango_font_description_get_size_is_absolute(desc
)) {
735 // |size| is in pango-points, so convert to pixels.
736 size
*= float(gfxPlatformGtk::GetDPI()) / POINTS_PER_INCH_FLOAT
;
739 // Scale fonts up on HiDPI displays.
740 // This would be done automatically with cairo, but we manually manage
741 // the display scale for platform consistency.
742 static auto sGdkScreenGetMonitorScaleFactorPtr
= (gint (*)(GdkScreen
*,gint
))
743 dlsym(RTLD_DEFAULT
, "gdk_screen_get_monitor_scale_factor");
744 if (sGdkScreenGetMonitorScaleFactorPtr
) {
745 GdkScreen
*screen
= gdk_screen_get_default();
746 size
*= (*sGdkScreenGetMonitorScaleFactorPtr
)(screen
, 0);
749 // |size| is now pixels
751 aFontStyle
->size
= size
;
753 pango_font_description_free(desc
);
757 GetSystemFontInfo(LookAndFeel::FontID aID
,
759 gfxFontStyle
*aFontStyle
)
761 if (aID
== LookAndFeel::eFont_Widget
) {
762 GtkWidget
*label
= gtk_label_new("M");
763 GtkWidget
*parent
= gtk_fixed_new();
764 GtkWidget
*window
= gtk_window_new(GTK_WINDOW_POPUP
);
766 gtk_container_add(GTK_CONTAINER(parent
), label
);
767 gtk_container_add(GTK_CONTAINER(window
), parent
);
769 gtk_widget_ensure_style(label
);
770 GetSystemFontInfo(label
, aFontName
, aFontStyle
);
771 gtk_widget_destroy(window
); // no unref, windows are different
773 } else if (aID
== LookAndFeel::eFont_Button
) {
774 GtkWidget
*label
= gtk_label_new("M");
775 GtkWidget
*parent
= gtk_fixed_new();
776 GtkWidget
*button
= gtk_button_new();
777 GtkWidget
*window
= gtk_window_new(GTK_WINDOW_POPUP
);
779 gtk_container_add(GTK_CONTAINER(button
), label
);
780 gtk_container_add(GTK_CONTAINER(parent
), button
);
781 gtk_container_add(GTK_CONTAINER(window
), parent
);
783 gtk_widget_ensure_style(label
);
784 GetSystemFontInfo(label
, aFontName
, aFontStyle
);
785 gtk_widget_destroy(window
); // no unref, windows are different
787 } else if (aID
== LookAndFeel::eFont_Field
) {
788 GtkWidget
*entry
= gtk_entry_new();
789 GtkWidget
*parent
= gtk_fixed_new();
790 GtkWidget
*window
= gtk_window_new(GTK_WINDOW_POPUP
);
792 gtk_container_add(GTK_CONTAINER(parent
), entry
);
793 gtk_container_add(GTK_CONTAINER(window
), parent
);
795 gtk_widget_ensure_style(entry
);
796 GetSystemFontInfo(entry
, aFontName
, aFontStyle
);
797 gtk_widget_destroy(window
); // no unref, windows are different
800 MOZ_ASSERT(aID
== LookAndFeel::eFont_Menu
, "unexpected font ID");
801 GtkWidget
*accel_label
= gtk_accel_label_new("M");
802 GtkWidget
*menuitem
= gtk_menu_item_new();
803 GtkWidget
*menu
= gtk_menu_new();
804 g_object_ref_sink(menu
);
806 gtk_container_add(GTK_CONTAINER(menuitem
), accel_label
);
807 gtk_menu_shell_append((GtkMenuShell
*)GTK_MENU(menu
), menuitem
);
809 gtk_widget_ensure_style(accel_label
);
810 GetSystemFontInfo(accel_label
, aFontName
, aFontStyle
);
811 g_object_unref(menu
);
816 nsLookAndFeel::GetFontImpl(FontID aID
, nsString
& aFontName
,
817 gfxFontStyle
& aFontStyle
,
818 float aDevPixPerCSSPixel
)
820 nsString
*cachedFontName
= nullptr;
821 gfxFontStyle
*cachedFontStyle
= nullptr;
822 bool *isCached
= nullptr;
825 case eFont_Menu
: // css2
826 case eFont_PullDownMenu
: // css3
827 cachedFontName
= &mMenuFontName
;
828 cachedFontStyle
= &mMenuFontStyle
;
829 isCached
= &mMenuFontCached
;
833 case eFont_Field
: // css3
834 case eFont_List
: // css3
835 cachedFontName
= &mFieldFontName
;
836 cachedFontStyle
= &mFieldFontStyle
;
837 isCached
= &mFieldFontCached
;
841 case eFont_Button
: // css3
842 cachedFontName
= &mButtonFontName
;
843 cachedFontStyle
= &mButtonFontStyle
;
844 isCached
= &mButtonFontCached
;
847 case eFont_Caption
: // css2
848 case eFont_Icon
: // css2
849 case eFont_MessageBox
: // css2
850 case eFont_SmallCaption
: // css2
851 case eFont_StatusBar
: // css2
852 case eFont_Window
: // css3
853 case eFont_Document
: // css3
854 case eFont_Workspace
: // css3
855 case eFont_Desktop
: // css3
856 case eFont_Info
: // css3
857 case eFont_Dialog
: // css3
858 case eFont_Tooltips
: // moz
859 case eFont_Widget
: // moz
860 cachedFontName
= &mDefaultFontName
;
861 cachedFontStyle
= &mDefaultFontStyle
;
862 isCached
= &mDefaultFontCached
;
868 GetSystemFontInfo(aID
, cachedFontName
, cachedFontStyle
);
872 aFontName
= *cachedFontName
;
873 aFontStyle
= *cachedFontStyle
;
877 #if (MOZ_WIDGET_GTK == 3)
878 static GtkStyleContext
*
879 create_context(GtkWidgetPath
*path
)
881 GtkStyleContext
*style
= gtk_style_context_new();
882 gtk_style_context_set_path(style
, path
);
888 nsLookAndFeel::Init()
891 GdkColor
*colorValuePtr
;
893 #if (MOZ_WIDGET_GTK == 2)
894 NS_ASSERTION(!mStyle
, "already initialized");
895 // GtkInvisibles come with a refcount that is not floating
896 // (since their initialization code calls g_object_ref_sink) and
897 // their destroy code releases that reference (which means they
898 // have to be explicitly destroyed, since calling unref enough
899 // to cause destruction would lead to *another* unref).
900 // However, this combination means that it's actually still ok
901 // to use the normal pattern, which is to g_object_ref_sink
902 // after construction, and then destroy *and* unref when we're
903 // done. (Though we could skip the g_object_ref_sink and the
904 // corresponding g_object_unref, but that's particular to
905 // GtkInvisibles and GtkWindows.)
906 GtkWidget
*widget
= gtk_invisible_new();
907 g_object_ref_sink(widget
); // effectively g_object_ref (see above)
909 gtk_widget_ensure_style(widget
);
910 mStyle
= gtk_style_copy(gtk_widget_get_style(widget
));
912 gtk_widget_destroy(widget
);
913 g_object_unref(widget
);
915 // tooltip foreground and background
916 GtkStyle
*style
= gtk_rc_get_style_by_paths(gtk_settings_get_default(),
917 "gtk-tooltips", "GtkWindow",
920 sInfoBackground
= GDK_COLOR_TO_NS_RGB(style
->bg
[GTK_STATE_NORMAL
]);
921 sInfoText
= GDK_COLOR_TO_NS_RGB(style
->fg
[GTK_STATE_NORMAL
]);
924 // menu foreground & menu background
925 GtkWidget
*accel_label
= gtk_accel_label_new("M");
926 GtkWidget
*menuitem
= gtk_menu_item_new();
927 GtkWidget
*menu
= gtk_menu_new();
929 g_object_ref_sink(menu
);
931 gtk_container_add(GTK_CONTAINER(menuitem
), accel_label
);
932 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), menuitem
);
934 gtk_widget_set_style(accel_label
, nullptr);
935 gtk_widget_set_style(menu
, nullptr);
936 gtk_widget_realize(menu
);
937 gtk_widget_realize(accel_label
);
939 style
= gtk_widget_get_style(accel_label
);
941 sMenuText
= GDK_COLOR_TO_NS_RGB(style
->fg
[GTK_STATE_NORMAL
]);
944 style
= gtk_widget_get_style(menu
);
946 sMenuBackground
= GDK_COLOR_TO_NS_RGB(style
->bg
[GTK_STATE_NORMAL
]);
949 style
= gtk_widget_get_style(menuitem
);
951 sMenuHover
= GDK_COLOR_TO_NS_RGB(style
->bg
[GTK_STATE_PRELIGHT
]);
952 sMenuHoverText
= GDK_COLOR_TO_NS_RGB(style
->fg
[GTK_STATE_PRELIGHT
]);
955 g_object_unref(menu
);
958 GtkStyleContext
*style
;
960 // Gtk manages a screen's CSS in the settings object so we
961 // ask Gtk to create it explicitly. Otherwise we may end up
962 // with wrong color theme, see Bug 972382
963 (void)gtk_settings_get_for_screen(gdk_screen_get_default());
965 GtkWidgetPath
*path
= gtk_widget_path_new();
966 gtk_widget_path_append_type(path
, GTK_TYPE_WINDOW
);
968 mBackgroundStyle
= create_context(path
);
969 gtk_style_context_add_class(mBackgroundStyle
, GTK_STYLE_CLASS_BACKGROUND
);
971 mButtonStyle
= create_context(path
);
972 gtk_style_context_add_class(mButtonStyle
, GTK_STYLE_CLASS_BUTTON
);
975 style
= create_context(path
);
976 gtk_style_context_add_class(style
, GTK_STYLE_CLASS_SCROLLBAR
);
977 gtk_style_context_add_class(style
, GTK_STYLE_CLASS_TROUGH
);
978 gtk_style_context_get_background_color(style
, GTK_STATE_FLAG_NORMAL
, &color
);
979 sMozScrollbar
= GDK_RGBA_TO_NS_RGBA(color
);
980 g_object_unref(style
);
983 style
= create_context(path
);
984 gtk_style_context_add_class(style
, GTK_STYLE_CLASS_VIEW
);
985 gtk_style_context_get_background_color(style
, GTK_STATE_FLAG_NORMAL
, &color
);
986 sMozFieldBackground
= GDK_RGBA_TO_NS_RGBA(color
);
987 gtk_style_context_get_color(style
, GTK_STATE_FLAG_NORMAL
, &color
);
988 sMozFieldText
= GDK_RGBA_TO_NS_RGBA(color
);
990 // Selected text and background
991 gtk_style_context_get_background_color(style
,
992 static_cast<GtkStateFlags
>(GTK_STATE_FLAG_FOCUSED
|GTK_STATE_FLAG_SELECTED
),
994 sTextSelectedBackground
= GDK_RGBA_TO_NS_RGBA(color
);
995 gtk_style_context_get_color(style
,
996 static_cast<GtkStateFlags
>(GTK_STATE_FLAG_FOCUSED
|GTK_STATE_FLAG_SELECTED
),
998 sTextSelectedText
= GDK_RGBA_TO_NS_RGBA(color
);
999 g_object_unref(style
);
1002 style
= create_context(path
);
1003 gtk_style_context_save(style
);
1004 gtk_style_context_add_class(style
, GTK_STYLE_CLASS_BACKGROUND
);
1005 gtk_style_context_get_background_color(style
, GTK_STATE_FLAG_NORMAL
, &color
);
1006 sMozWindowBackground
= GDK_RGBA_TO_NS_RGBA(color
);
1007 gtk_style_context_get_color(style
, GTK_STATE_FLAG_NORMAL
, &color
);
1008 sMozWindowText
= GDK_RGBA_TO_NS_RGBA(color
);
1009 gtk_style_context_restore(style
);
1011 // tooltip foreground and background
1012 gtk_style_context_add_class(style
, GTK_STYLE_CLASS_TOOLTIP
);
1013 gtk_style_context_get_background_color(style
, GTK_STATE_FLAG_NORMAL
, &color
);
1014 sInfoBackground
= GDK_RGBA_TO_NS_RGBA(color
);
1015 gtk_style_context_get_color(style
, GTK_STATE_FLAG_NORMAL
, &color
);
1016 sInfoText
= GDK_RGBA_TO_NS_RGBA(color
);
1017 g_object_unref(style
);
1019 // menu foreground & menu background
1020 GtkWidget
*accel_label
= gtk_accel_label_new("M");
1021 GtkWidget
*menuitem
= gtk_menu_item_new();
1022 GtkWidget
*menu
= gtk_menu_new();
1024 g_object_ref_sink(menu
);
1026 gtk_container_add(GTK_CONTAINER(menuitem
), accel_label
);
1027 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), menuitem
);
1029 style
= gtk_widget_get_style_context(accel_label
);
1030 gtk_style_context_get_color(style
, GTK_STATE_FLAG_NORMAL
, &color
);
1031 sMenuText
= GDK_RGBA_TO_NS_RGBA(color
);
1033 style
= gtk_widget_get_style_context(menu
);
1034 gtk_style_context_get_background_color(style
, GTK_STATE_FLAG_NORMAL
, &color
);
1035 sMenuBackground
= GDK_RGBA_TO_NS_RGBA(color
);
1037 style
= gtk_widget_get_style_context(menuitem
);
1038 gtk_style_context_get_background_color(style
, GTK_STATE_FLAG_PRELIGHT
, &color
);
1039 sMenuHover
= GDK_RGBA_TO_NS_RGBA(color
);
1040 gtk_style_context_get_color(style
, GTK_STATE_FLAG_PRELIGHT
, &color
);
1041 sMenuHoverText
= GDK_RGBA_TO_NS_RGBA(color
);
1043 g_object_unref(menu
);
1047 GtkWidget
*parent
= gtk_fixed_new();
1048 GtkWidget
*button
= gtk_button_new();
1049 GtkWidget
*label
= gtk_label_new("M");
1050 #if (MOZ_WIDGET_GTK == 2)
1051 GtkWidget
*combobox
= gtk_combo_box_new();
1052 GtkWidget
*comboboxLabel
= gtk_label_new("M");
1053 gtk_container_add(GTK_CONTAINER(combobox
), comboboxLabel
);
1055 GtkWidget
*combobox
= gtk_combo_box_new_with_entry();
1056 GtkWidget
*comboboxLabel
= gtk_bin_get_child(GTK_BIN(combobox
));
1058 GtkWidget
*window
= gtk_window_new(GTK_WINDOW_POPUP
);
1059 GtkWidget
*treeView
= gtk_tree_view_new();
1060 GtkWidget
*linkButton
= gtk_link_button_new("http://example.com/");
1061 GtkWidget
*menuBar
= gtk_menu_bar_new();
1062 GtkWidget
*entry
= gtk_entry_new();
1064 gtk_container_add(GTK_CONTAINER(button
), label
);
1065 gtk_container_add(GTK_CONTAINER(parent
), button
);
1066 gtk_container_add(GTK_CONTAINER(parent
), treeView
);
1067 gtk_container_add(GTK_CONTAINER(parent
), linkButton
);
1068 gtk_container_add(GTK_CONTAINER(parent
), combobox
);
1069 gtk_container_add(GTK_CONTAINER(parent
), menuBar
);
1070 gtk_container_add(GTK_CONTAINER(window
), parent
);
1071 gtk_container_add(GTK_CONTAINER(parent
), entry
);
1073 #if (MOZ_WIDGET_GTK == 2)
1074 gtk_widget_set_style(button
, nullptr);
1075 gtk_widget_set_style(label
, nullptr);
1076 gtk_widget_set_style(treeView
, nullptr);
1077 gtk_widget_set_style(linkButton
, nullptr);
1078 gtk_widget_set_style(combobox
, nullptr);
1079 gtk_widget_set_style(comboboxLabel
, nullptr);
1080 gtk_widget_set_style(menuBar
, nullptr);
1081 gtk_widget_set_style(entry
, nullptr);
1083 gtk_widget_realize(button
);
1084 gtk_widget_realize(label
);
1085 gtk_widget_realize(treeView
);
1086 gtk_widget_realize(linkButton
);
1087 gtk_widget_realize(combobox
);
1088 gtk_widget_realize(comboboxLabel
);
1089 gtk_widget_realize(menuBar
);
1090 gtk_widget_realize(entry
);
1092 style
= gtk_widget_get_style(label
);
1094 sButtonText
= GDK_COLOR_TO_NS_RGB(style
->fg
[GTK_STATE_NORMAL
]);
1097 style
= gtk_widget_get_style(comboboxLabel
);
1099 sComboBoxText
= GDK_COLOR_TO_NS_RGB(style
->fg
[GTK_STATE_NORMAL
]);
1101 style
= gtk_widget_get_style(combobox
);
1103 sComboBoxBackground
= GDK_COLOR_TO_NS_RGB(style
->bg
[GTK_STATE_NORMAL
]);
1106 style
= gtk_widget_get_style(menuBar
);
1108 sMenuBarText
= GDK_COLOR_TO_NS_RGB(style
->fg
[GTK_STATE_NORMAL
]);
1109 sMenuBarHoverText
= GDK_COLOR_TO_NS_RGB(style
->fg
[GTK_STATE_SELECTED
]);
1112 // GTK's guide to fancy odd row background colors:
1113 // 1) Check if a theme explicitly defines an odd row color
1114 // 2) If not, check if it defines an even row color, and darken it
1115 // slightly by a hardcoded value (gtkstyle.c)
1116 // 3) If neither are defined, take the base background color and
1117 // darken that by a hardcoded value
1118 colorValuePtr
= nullptr;
1119 gtk_widget_style_get(treeView
,
1120 "odd-row-color", &colorValuePtr
,
1123 if (colorValuePtr
) {
1124 colorValue
= *colorValuePtr
;
1126 gtk_widget_style_get(treeView
,
1127 "even-row-color", &colorValuePtr
,
1130 darken_gdk_color(colorValuePtr
, &colorValue
);
1132 darken_gdk_color(&treeView
->style
->base
[GTK_STATE_NORMAL
], &colorValue
);
1135 sOddCellBackground
= GDK_COLOR_TO_NS_RGB(colorValue
);
1137 gdk_color_free(colorValuePtr
);
1139 style
= gtk_widget_get_style(button
);
1141 sButtonBackground
= GDK_COLOR_TO_NS_RGB(style
->bg
[GTK_STATE_NORMAL
]);
1142 sFrameOuterLightBorder
=
1143 GDK_COLOR_TO_NS_RGB(style
->light
[GTK_STATE_NORMAL
]);
1144 sFrameInnerDarkBorder
=
1145 GDK_COLOR_TO_NS_RGB(style
->dark
[GTK_STATE_NORMAL
]);
1148 // Button text, background, border
1149 style
= gtk_widget_get_style_context(label
);
1150 gtk_style_context_get_color(style
, GTK_STATE_FLAG_NORMAL
, &color
);
1151 sButtonText
= GDK_RGBA_TO_NS_RGBA(color
);
1152 gtk_style_context_get_color(style
, GTK_STATE_FLAG_PRELIGHT
, &color
);
1153 sButtonHoverText
= GDK_RGBA_TO_NS_RGBA(color
);
1155 // Combobox label and background colors
1156 style
= gtk_widget_get_style_context(comboboxLabel
);
1157 gtk_style_context_get_color(style
, GTK_STATE_FLAG_NORMAL
, &color
);
1158 sComboBoxText
= GDK_RGBA_TO_NS_RGBA(color
);
1160 style
= gtk_widget_get_style_context(combobox
);
1161 gtk_style_context_get_background_color(style
, GTK_STATE_FLAG_NORMAL
, &color
);
1162 sComboBoxBackground
= GDK_RGBA_TO_NS_RGBA(color
);
1164 // Menubar text and hover text colors
1165 style
= gtk_widget_get_style_context(menuBar
);
1166 gtk_style_context_get_color(style
, GTK_STATE_FLAG_NORMAL
, &color
);
1167 sMenuBarText
= GDK_RGBA_TO_NS_RGBA(color
);
1168 gtk_style_context_get_color(style
, GTK_STATE_FLAG_PRELIGHT
, &color
);
1169 sMenuBarHoverText
= GDK_RGBA_TO_NS_RGBA(color
);
1171 // GTK's guide to fancy odd row background colors:
1172 // 1) Check if a theme explicitly defines an odd row color
1173 // 2) If not, check if it defines an even row color, and darken it
1174 // slightly by a hardcoded value (gtkstyle.c)
1175 // 3) If neither are defined, take the base background color and
1176 // darken that by a hardcoded value
1177 style
= gtk_widget_get_style_context(treeView
);
1179 // Get odd row background color
1180 gtk_style_context_save(style
);
1181 gtk_style_context_add_region(style
, GTK_STYLE_REGION_ROW
, GTK_REGION_ODD
);
1182 gtk_style_context_get_background_color(style
, GTK_STATE_FLAG_NORMAL
, &color
);
1183 sOddCellBackground
= GDK_RGBA_TO_NS_RGBA(color
);
1184 gtk_style_context_restore(style
);
1186 GtkWidget
*frame
= gtk_frame_new(nullptr);
1187 gtk_container_add(GTK_CONTAINER(parent
), frame
);
1189 // TODO GTK3 - update sFrameOuterLightBorder
1190 // for GTK_BORDER_STYLE_INSET/OUTSET/GROVE/RIDGE border styles (Bug 978172).
1191 style
= gtk_widget_get_style_context(frame
);
1192 gtk_style_context_get_border_color(style
, GTK_STATE_FLAG_NORMAL
, &color
);
1193 sFrameInnerDarkBorder
= sFrameOuterLightBorder
= GDK_RGBA_TO_NS_RGBA(color
);
1195 // Some themes have a unified menu bar, and support window dragging on it
1196 gboolean supports_menubar_drag
= FALSE
;
1197 GParamSpec
*param_spec
=
1198 gtk_widget_class_find_style_property(GTK_WIDGET_GET_CLASS(menuBar
),
1201 if (g_type_is_a(G_PARAM_SPEC_VALUE_TYPE(param_spec
), G_TYPE_BOOLEAN
)) {
1202 gtk_widget_style_get(menuBar
,
1203 "window-dragging", &supports_menubar_drag
,
1207 sMenuSupportsDrag
= supports_menubar_drag
;
1209 colorValuePtr
= nullptr;
1210 gtk_widget_style_get(linkButton
, "link-color", &colorValuePtr
, nullptr);
1211 if (colorValuePtr
) {
1212 colorValue
= *colorValuePtr
; // we can't pass deref pointers to GDK_COLOR_TO_NS_RGB
1213 sNativeHyperLinkText
= GDK_COLOR_TO_NS_RGB(colorValue
);
1214 gdk_color_free(colorValuePtr
);
1216 sNativeHyperLinkText
= NS_RGB(0x00,0x00,0xEE);
1219 // invisible character styles
1221 g_object_get (entry
, "invisible-char", &value
, nullptr);
1222 sInvisibleCharacter
= char16_t(value
);
1225 gtk_widget_style_get(entry
,
1226 "cursor-aspect-ratio", &sCaretRatio
,
1229 gtk_widget_destroy(window
);
1234 nsLookAndFeel::GetPasswordCharacterImpl()
1236 return sInvisibleCharacter
;
1240 nsLookAndFeel::RefreshImpl()
1242 nsXPLookAndFeel::RefreshImpl();
1244 mDefaultFontCached
= false;
1245 mButtonFontCached
= false;
1246 mFieldFontCached
= false;
1247 mMenuFontCached
= false;
1249 #if (MOZ_WIDGET_GTK == 2)
1250 g_object_unref(mStyle
);
1253 g_object_unref(mBackgroundStyle
);
1254 g_object_unref(mButtonStyle
);
1256 mBackgroundStyle
= nullptr;
1257 mButtonStyle
= nullptr;
1264 nsLookAndFeel::GetEchoPasswordImpl() {