diff options
Diffstat (limited to 'widget/gtk/nsLookAndFeel.cpp')
-rw-r--r-- | widget/gtk/nsLookAndFeel.cpp | 1465 |
1 files changed, 1465 insertions, 0 deletions
diff --git a/widget/gtk/nsLookAndFeel.cpp b/widget/gtk/nsLookAndFeel.cpp new file mode 100644 index 000000000..53430dfbb --- /dev/null +++ b/widget/gtk/nsLookAndFeel.cpp @@ -0,0 +1,1465 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim:expandtab:shiftwidth=4:tabstop=4: + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// for strtod() +#include <stdlib.h> + +#include "nsLookAndFeel.h" + +#include <gtk/gtk.h> +#include <gdk/gdk.h> + +#include <pango/pango.h> +#include <pango/pango-fontmap.h> + +#include <fontconfig/fontconfig.h> +#include "gfxPlatformGtk.h" +#include "nsScreenGtk.h" + +#include "gtkdrawing.h" +#include "nsStyleConsts.h" +#include "gfxFontConstants.h" +#include "WidgetUtils.h" + +#include <dlfcn.h> + +#include "mozilla/gfx/2D.h" + +#if MOZ_WIDGET_GTK != 2 +#include <cairo-gobject.h> +#include "WidgetStyleCache.h" +#include "prenv.h" +#endif + +using mozilla::LookAndFeel; + +#define GDK_COLOR_TO_NS_RGB(c) \ + ((nscolor) NS_RGB(c.red>>8, c.green>>8, c.blue>>8)) +#define GDK_RGBA_TO_NS_RGBA(c) \ + ((nscolor) NS_RGBA((int)((c).red*255), (int)((c).green*255), \ + (int)((c).blue*255), (int)((c).alpha*255))) + +nsLookAndFeel::nsLookAndFeel() + : nsXPLookAndFeel(), +#if (MOZ_WIDGET_GTK == 2) + mStyle(nullptr), +#else + mBackgroundStyle(nullptr), + mButtonStyle(nullptr), +#endif + mDefaultFontCached(false), mButtonFontCached(false), + mFieldFontCached(false), mMenuFontCached(false) +{ + Init(); +} + +nsLookAndFeel::~nsLookAndFeel() +{ +#if (MOZ_WIDGET_GTK == 2) + g_object_unref(mStyle); +#else + g_object_unref(mBackgroundStyle); + g_object_unref(mButtonStyle); +#endif +} + +#if MOZ_WIDGET_GTK != 2 +static void +GetLightAndDarkness(const GdkRGBA& aColor, + double* aLightness, double* aDarkness) +{ + double sum = aColor.red + aColor.green + aColor.blue; + *aLightness = sum * aColor.alpha; + *aDarkness = (3.0 - sum) * aColor.alpha; +} + +static bool +GetGradientColors(const GValue* aValue, + GdkRGBA* aLightColor, GdkRGBA* aDarkColor) +{ + if (!G_TYPE_CHECK_VALUE_TYPE(aValue, CAIRO_GOBJECT_TYPE_PATTERN)) + return false; + + auto pattern = static_cast<cairo_pattern_t*>(g_value_get_boxed(aValue)); + if (!pattern) + return false; + + // Just picking the lightest and darkest colors as simple samples rather + // than trying to blend, which could get messy if there are many stops. + if (CAIRO_STATUS_SUCCESS != + cairo_pattern_get_color_stop_rgba(pattern, 0, nullptr, &aDarkColor->red, + &aDarkColor->green, &aDarkColor->blue, + &aDarkColor->alpha)) + return false; + + double maxLightness, maxDarkness; + GetLightAndDarkness(*aDarkColor, &maxLightness, &maxDarkness); + *aLightColor = *aDarkColor; + + GdkRGBA stop; + for (int index = 1; + CAIRO_STATUS_SUCCESS == + cairo_pattern_get_color_stop_rgba(pattern, index, nullptr, + &stop.red, &stop.green, + &stop.blue, &stop.alpha); + ++index) { + double lightness, darkness; + GetLightAndDarkness(stop, &lightness, &darkness); + if (lightness > maxLightness) { + maxLightness = lightness; + *aLightColor = stop; + } + if (darkness > maxDarkness) { + maxDarkness = darkness; + *aDarkColor = stop; + } + } + + return true; +} + +static bool +GetUnicoBorderGradientColors(GtkStyleContext* aContext, + GdkRGBA* aLightColor, GdkRGBA* aDarkColor) +{ + // Ubuntu 12.04 has GTK engine Unico-1.0.2, which overrides render_frame, + // providing its own border code. Ubuntu 14.04 has + // Unico-1.0.3+14.04.20140109, which does not override render_frame, and + // so does not need special attention. The earlier Unico can be detected + // by the -unico-border-gradient style property it registers. + // gtk_style_properties_lookup_property() is checked first to avoid the + // warning from gtk_style_context_get_property() when the property does + // not exist. (gtk_render_frame() of GTK+ 3.16 no longer uses the + // engine.) + const char* propertyName = "-unico-border-gradient"; + if (!gtk_style_properties_lookup_property(propertyName, nullptr, nullptr)) + return false; + + // -unico-border-gradient is used only when the CSS node's engine is Unico. + GtkThemingEngine* engine; + GtkStateFlags state = gtk_style_context_get_state(aContext); + gtk_style_context_get(aContext, state, "engine", &engine, nullptr); + if (strcmp(g_type_name(G_TYPE_FROM_INSTANCE(engine)), "UnicoEngine") != 0) + return false; + + // draw_border() of Unico engine uses -unico-border-gradient + // in preference to border-color. + GValue value = G_VALUE_INIT; + gtk_style_context_get_property(aContext, propertyName, state, &value); + + bool result = GetGradientColors(&value, aLightColor, aDarkColor); + + g_value_unset(&value); + return result; +} + +// Sets |aLightColor| and |aDarkColor| to colors from |aContext|. Returns +// true if |aContext| uses these colors to render a visible border. +// If returning false, then the colors returned are a fallback from the +// border-color value even though |aContext| does not use these colors to +// render a border. +static bool +GetBorderColors(GtkStyleContext* aContext, + GdkRGBA* aLightColor, GdkRGBA* aDarkColor) +{ + // Determine whether the border on this style context is visible. + GtkStateFlags state = gtk_style_context_get_state(aContext); + GtkBorderStyle borderStyle; + gtk_style_context_get(aContext, state, GTK_STYLE_PROPERTY_BORDER_STYLE, + &borderStyle, nullptr); + bool visible = borderStyle != GTK_BORDER_STYLE_NONE && + borderStyle != GTK_BORDER_STYLE_HIDDEN; + if (visible) { + // GTK has an initial value of zero for border-widths, and so themes + // need to explicitly set border-widths to make borders visible. + GtkBorder border; + gtk_style_context_get_border(aContext, GTK_STATE_FLAG_NORMAL, &border); + visible = border.top != 0 || border.right != 0 || + border.bottom != 0 || border.left != 0; + } + + if (visible && + GetUnicoBorderGradientColors(aContext, aLightColor, aDarkColor)) + return true; + + // The initial value for the border-color is the foreground color, and so + // this will usually return a color distinct from the background even if + // there is no visible border detected. + gtk_style_context_get_border_color(aContext, state, aDarkColor); + // TODO GTK3 - update aLightColor + // for GTK_BORDER_STYLE_INSET/OUTSET/GROVE/RIDGE border styles. + // https://bugzilla.mozilla.org/show_bug.cgi?id=978172#c25 + *aLightColor = *aDarkColor; + return visible; +} + +static bool +GetBorderColors(GtkStyleContext* aContext, + nscolor* aLightColor, nscolor* aDarkColor) +{ + GdkRGBA lightColor, darkColor; + bool ret = GetBorderColors(aContext, &lightColor, &darkColor); + *aLightColor = GDK_RGBA_TO_NS_RGBA(lightColor); + *aDarkColor = GDK_RGBA_TO_NS_RGBA(darkColor); + return ret; +} +#endif + +nsresult +nsLookAndFeel::NativeGetColor(ColorID aID, nscolor& aColor) +{ +#if (MOZ_WIDGET_GTK == 3) + GdkRGBA gdk_color; +#endif + nsresult res = NS_OK; + + switch (aID) { + // These colors don't seem to be used for anything anymore in Mozilla + // (except here at least TextSelectBackground and TextSelectForeground) + // The CSS2 colors below are used. +#if (MOZ_WIDGET_GTK == 2) + case eColorID_WindowBackground: + aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_NORMAL]); + break; + case eColorID_WindowForeground: + aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_NORMAL]); + break; + case eColorID_WidgetBackground: + aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]); + break; + case eColorID_WidgetForeground: + aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_NORMAL]); + break; + case eColorID_WidgetSelectBackground: + aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_SELECTED]); + break; + case eColorID_WidgetSelectForeground: + aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_SELECTED]); + break; +#else + case eColorID_WindowBackground: + case eColorID_WidgetBackground: + case eColorID_TextBackground: + case eColorID_activecaption: // active window caption background + case eColorID_appworkspace: // MDI background color + case eColorID_background: // desktop background + case eColorID_window: + case eColorID_windowframe: + case eColorID__moz_dialog: + case eColorID__moz_combobox: + aColor = sMozWindowBackground; + break; + case eColorID_WindowForeground: + case eColorID_WidgetForeground: + case eColorID_TextForeground: + case eColorID_captiontext: // text in active window caption, size box, and scrollbar arrow box (!) + case eColorID_windowtext: + case eColorID__moz_dialogtext: + aColor = sMozWindowText; + break; + case eColorID_WidgetSelectBackground: + case eColorID_TextSelectBackground: + case eColorID_IMESelectedRawTextBackground: + case eColorID_IMESelectedConvertedTextBackground: + case eColorID__moz_dragtargetzone: + case eColorID__moz_cellhighlight: + case eColorID__moz_html_cellhighlight: + case eColorID_highlight: // preference selected item, + aColor = sTextSelectedBackground; + break; + case eColorID_WidgetSelectForeground: + case eColorID_TextSelectForeground: + case eColorID_IMESelectedRawTextForeground: + case eColorID_IMESelectedConvertedTextForeground: + case eColorID_highlighttext: + case eColorID__moz_cellhighlighttext: + case eColorID__moz_html_cellhighlighttext: + aColor = sTextSelectedText; + break; +#endif + case eColorID_Widget3DHighlight: + aColor = NS_RGB(0xa0,0xa0,0xa0); + break; + case eColorID_Widget3DShadow: + aColor = NS_RGB(0x40,0x40,0x40); + break; +#if (MOZ_WIDGET_GTK == 2) + case eColorID_TextBackground: + // not used? + aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_NORMAL]); + break; + case eColorID_TextForeground: + // not used? + aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_NORMAL]); + break; + case eColorID_TextSelectBackground: + case eColorID_IMESelectedRawTextBackground: + case eColorID_IMESelectedConvertedTextBackground: + // still used + aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_SELECTED]); + break; + case eColorID_TextSelectForeground: + case eColorID_IMESelectedRawTextForeground: + case eColorID_IMESelectedConvertedTextForeground: + // still used + aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_SELECTED]); + break; +#endif + case eColorID_IMERawInputBackground: + case eColorID_IMEConvertedTextBackground: + aColor = NS_TRANSPARENT; + break; + case eColorID_IMERawInputForeground: + case eColorID_IMEConvertedTextForeground: + aColor = NS_SAME_AS_FOREGROUND_COLOR; + break; + case eColorID_IMERawInputUnderline: + case eColorID_IMEConvertedTextUnderline: + aColor = NS_SAME_AS_FOREGROUND_COLOR; + break; + case eColorID_IMESelectedRawTextUnderline: + case eColorID_IMESelectedConvertedTextUnderline: + aColor = NS_TRANSPARENT; + break; + case eColorID_SpellCheckerUnderline: + aColor = NS_RGB(0xff, 0, 0); + break; + +#if (MOZ_WIDGET_GTK == 2) + // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors + case eColorID_activeborder: + // active window border + aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]); + break; + case eColorID_activecaption: + // active window caption background + aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]); + break; + case eColorID_appworkspace: + // MDI background color + aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]); + break; + case eColorID_background: + // desktop background + aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]); + break; + case eColorID_captiontext: + // text in active window caption, size box, and scrollbar arrow box (!) + aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_NORMAL]); + break; + case eColorID_graytext: + // disabled text in windows, menus, etc. + aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_INSENSITIVE]); + break; + case eColorID_highlight: + // background of selected item + aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_SELECTED]); + break; + case eColorID_highlighttext: + // text of selected item + aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_SELECTED]); + break; + case eColorID_inactiveborder: + // inactive window border + aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]); + break; + case eColorID_inactivecaption: + // inactive window caption + aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_INSENSITIVE]); + break; + case eColorID_inactivecaptiontext: + // text in inactive window caption + aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_INSENSITIVE]); + break; +#else + // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors + case eColorID_activeborder: + // active window border + gtk_style_context_get_border_color(mBackgroundStyle, + GTK_STATE_FLAG_NORMAL, &gdk_color); + aColor = GDK_RGBA_TO_NS_RGBA(gdk_color); + break; + case eColorID_inactiveborder: + // inactive window border + gtk_style_context_get_border_color(mBackgroundStyle, + GTK_STATE_FLAG_INSENSITIVE, + &gdk_color); + aColor = GDK_RGBA_TO_NS_RGBA(gdk_color); + break; + case eColorID_graytext: // disabled text in windows, menus, etc. + case eColorID_inactivecaptiontext: // text in inactive window caption + aColor = sMenuTextInactive; + break; + case eColorID_inactivecaption: + // inactive window caption + gtk_style_context_get_background_color(mBackgroundStyle, + GTK_STATE_FLAG_INSENSITIVE, + &gdk_color); + aColor = GDK_RGBA_TO_NS_RGBA(gdk_color); + break; +#endif + case eColorID_infobackground: + // tooltip background color + aColor = sInfoBackground; + break; + case eColorID_infotext: + // tooltip text color + aColor = sInfoText; + break; + case eColorID_menu: + // menu background + aColor = sMenuBackground; + break; + case eColorID_menutext: + // menu text + aColor = sMenuText; + break; + case eColorID_scrollbar: + // scrollbar gray area +#if (MOZ_WIDGET_GTK == 2) + aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_ACTIVE]); +#else + aColor = sMozScrollbar; +#endif + break; + + case eColorID_threedlightshadow: + // 3-D highlighted inner edge color + // always same as background in GTK code + case eColorID_threedface: + case eColorID_buttonface: + // 3-D face color +#if (MOZ_WIDGET_GTK == 3) + aColor = sMozWindowBackground; +#else + aColor = sButtonBackground; +#endif + break; + + case eColorID_buttontext: + // text on push buttons + aColor = sButtonText; + break; + + case eColorID_buttonhighlight: + // 3-D highlighted edge color + case eColorID_threedhighlight: + // 3-D highlighted outer edge color + aColor = sFrameOuterLightBorder; + break; + + case eColorID_buttonshadow: + // 3-D shadow edge color + case eColorID_threedshadow: + // 3-D shadow inner edge color + aColor = sFrameInnerDarkBorder; + break; + +#if (MOZ_WIDGET_GTK == 2) + case eColorID_threeddarkshadow: + // 3-D shadow outer edge color + aColor = GDK_COLOR_TO_NS_RGB(mStyle->black); + break; + + case eColorID_window: + case eColorID_windowframe: + aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]); + break; + + case eColorID_windowtext: + aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_NORMAL]); + break; + + case eColorID__moz_eventreerow: + case eColorID__moz_field: + aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_NORMAL]); + break; + case eColorID__moz_fieldtext: + aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_NORMAL]); + break; + case eColorID__moz_dialog: + aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_NORMAL]); + break; + case eColorID__moz_dialogtext: + aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_NORMAL]); + break; + case eColorID__moz_dragtargetzone: + aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_SELECTED]); + break; + case eColorID__moz_buttondefault: + // default button border color + aColor = GDK_COLOR_TO_NS_RGB(mStyle->black); + break; + case eColorID__moz_buttonhoverface: + aColor = GDK_COLOR_TO_NS_RGB(mStyle->bg[GTK_STATE_PRELIGHT]); + break; + case eColorID__moz_buttonhovertext: + aColor = GDK_COLOR_TO_NS_RGB(mStyle->fg[GTK_STATE_PRELIGHT]); + break; + case eColorID__moz_cellhighlight: + case eColorID__moz_html_cellhighlight: + aColor = GDK_COLOR_TO_NS_RGB(mStyle->base[GTK_STATE_ACTIVE]); + break; + case eColorID__moz_cellhighlighttext: + case eColorID__moz_html_cellhighlighttext: + aColor = GDK_COLOR_TO_NS_RGB(mStyle->text[GTK_STATE_ACTIVE]); + break; +#else + case eColorID_threeddarkshadow: + // Hardcode to black + aColor = NS_RGB(0x00,0x00,0x00); + break; + + case eColorID__moz_eventreerow: + case eColorID__moz_field: + aColor = sMozFieldBackground; + break; + case eColorID__moz_fieldtext: + aColor = sMozFieldText; + break; + case eColorID__moz_buttondefault: + // default button border color + gtk_style_context_get_border_color(mButtonStyle, + GTK_STATE_FLAG_NORMAL, &gdk_color); + aColor = GDK_RGBA_TO_NS_RGBA(gdk_color); + break; + case eColorID__moz_buttonhoverface: + gtk_style_context_get_background_color(mButtonStyle, + GTK_STATE_FLAG_PRELIGHT, + &gdk_color); + aColor = GDK_RGBA_TO_NS_RGBA(gdk_color); + break; + case eColorID__moz_buttonhovertext: + aColor = sButtonHoverText; + break; +#endif + case eColorID__moz_menuhover: + aColor = sMenuHover; + break; + case eColorID__moz_menuhovertext: + aColor = sMenuHoverText; + break; + case eColorID__moz_oddtreerow: + aColor = sOddCellBackground; + break; + case eColorID__moz_nativehyperlinktext: + aColor = sNativeHyperLinkText; + break; + case eColorID__moz_comboboxtext: + aColor = sComboBoxText; + break; +#if (MOZ_WIDGET_GTK == 2) + case eColorID__moz_combobox: + aColor = sComboBoxBackground; + break; +#endif + case eColorID__moz_menubartext: + aColor = sMenuBarText; + break; + case eColorID__moz_menubarhovertext: + aColor = sMenuBarHoverText; + break; + case eColorID__moz_gtk_info_bar_text: +#if (MOZ_WIDGET_GTK == 3) + aColor = sInfoBarText; +#else + aColor = sInfoText; +#endif + break; + default: + /* default color is BLACK */ + aColor = 0; + res = NS_ERROR_FAILURE; + break; + } + + return res; +} + +#if (MOZ_WIDGET_GTK == 2) +static void darken_gdk_color(GdkColor *src, GdkColor *dest) +{ + gdouble red; + gdouble green; + gdouble blue; + + red = (gdouble) src->red / 65535.0; + green = (gdouble) src->green / 65535.0; + blue = (gdouble) src->blue / 65535.0; + + red *= 0.93; + green *= 0.93; + blue *= 0.93; + + dest->red = red * 65535.0; + dest->green = green * 65535.0; + dest->blue = blue * 65535.0; +} +#endif + +static int32_t CheckWidgetStyle(GtkWidget* aWidget, const char* aStyle, int32_t aResult) { + gboolean value = FALSE; + gtk_widget_style_get(aWidget, aStyle, &value, nullptr); + return value ? aResult : 0; +} + +static int32_t ConvertGTKStepperStyleToMozillaScrollArrowStyle(GtkWidget* aWidget) +{ + if (!aWidget) + return mozilla::LookAndFeel::eScrollArrowStyle_Single; + + return + CheckWidgetStyle(aWidget, "has-backward-stepper", + mozilla::LookAndFeel::eScrollArrow_StartBackward) | + CheckWidgetStyle(aWidget, "has-forward-stepper", + mozilla::LookAndFeel::eScrollArrow_EndForward) | + CheckWidgetStyle(aWidget, "has-secondary-backward-stepper", + mozilla::LookAndFeel::eScrollArrow_EndBackward) | + CheckWidgetStyle(aWidget, "has-secondary-forward-stepper", + mozilla::LookAndFeel::eScrollArrow_StartForward); +} + +nsresult +nsLookAndFeel::GetIntImpl(IntID aID, int32_t &aResult) +{ + nsresult res = NS_OK; + + // Set these before they can get overrided in the nsXPLookAndFeel. + switch (aID) { + case eIntID_ScrollButtonLeftMouseButtonAction: + aResult = 0; + return NS_OK; + case eIntID_ScrollButtonMiddleMouseButtonAction: + aResult = 1; + return NS_OK; + case eIntID_ScrollButtonRightMouseButtonAction: + aResult = 2; + return NS_OK; + default: + break; + } + + res = nsXPLookAndFeel::GetIntImpl(aID, aResult); + if (NS_SUCCEEDED(res)) + return res; + res = NS_OK; + + switch (aID) { + case eIntID_CaretBlinkTime: + { + GtkSettings *settings; + gint blink_time; + gboolean blink; + + settings = gtk_settings_get_default (); + g_object_get (settings, + "gtk-cursor-blink-time", &blink_time, + "gtk-cursor-blink", &blink, + nullptr); + + if (blink) + aResult = (int32_t) blink_time; + else + aResult = 0; + break; + } + case eIntID_CaretWidth: + aResult = 1; + break; + case eIntID_ShowCaretDuringSelection: + aResult = 0; + break; + case eIntID_SelectTextfieldsOnKeyFocus: + { + GtkWidget *entry; + GtkSettings *settings; + gboolean select_on_focus; + + entry = gtk_entry_new(); + g_object_ref_sink(entry); + settings = gtk_widget_get_settings(entry); + g_object_get(settings, + "gtk-entry-select-on-focus", + &select_on_focus, + nullptr); + + if(select_on_focus) + aResult = 1; + else + aResult = 0; + + gtk_widget_destroy(entry); + g_object_unref(entry); + } + break; + case eIntID_ScrollToClick: + { + GtkSettings *settings; + gboolean warps_slider = FALSE; + + settings = gtk_settings_get_default (); + if (g_object_class_find_property (G_OBJECT_GET_CLASS(settings), + "gtk-primary-button-warps-slider")) { + g_object_get (settings, + "gtk-primary-button-warps-slider", + &warps_slider, + nullptr); + } + + if (warps_slider) + aResult = 1; + else + aResult = 0; + } + break; + case eIntID_SubmenuDelay: + { + GtkSettings *settings; + gint delay; + + settings = gtk_settings_get_default (); + g_object_get (settings, "gtk-menu-popup-delay", &delay, nullptr); + aResult = (int32_t) delay; + break; + } + case eIntID_TooltipDelay: + { + aResult = 500; + break; + } + case eIntID_MenusCanOverlapOSBar: + // we want XUL popups to be able to overlap the task bar. + aResult = 1; + break; + case eIntID_SkipNavigatingDisabledMenuItem: + aResult = 1; + break; + case eIntID_DragThresholdX: + case eIntID_DragThresholdY: + { + GtkWidget* box = gtk_hbox_new(FALSE, 5); + gint threshold = 0; + g_object_get(gtk_widget_get_settings(box), + "gtk-dnd-drag-threshold", &threshold, + nullptr); + g_object_ref_sink(box); + + aResult = threshold; + } + break; + case eIntID_ScrollArrowStyle: + moz_gtk_init(); + aResult = + ConvertGTKStepperStyleToMozillaScrollArrowStyle(moz_gtk_get_scrollbar_widget()); + break; + case eIntID_ScrollSliderStyle: + aResult = eScrollThumbStyle_Proportional; + break; + case eIntID_TreeOpenDelay: + aResult = 1000; + break; + case eIntID_TreeCloseDelay: + aResult = 1000; + break; + case eIntID_TreeLazyScrollDelay: + aResult = 150; + break; + case eIntID_TreeScrollDelay: + aResult = 100; + break; + case eIntID_TreeScrollLinesMax: + aResult = 3; + break; + case eIntID_DWMCompositor: + case eIntID_WindowsClassic: + case eIntID_WindowsDefaultTheme: + case eIntID_WindowsThemeIdentifier: + case eIntID_OperatingSystemVersionIdentifier: + aResult = 0; + res = NS_ERROR_NOT_IMPLEMENTED; + break; + case eIntID_TouchEnabled: +#if MOZ_WIDGET_GTK == 3 + aResult = mozilla::widget::WidgetUtils::IsTouchDeviceSupportPresent(); + break; +#else + aResult = 0; + res = NS_ERROR_NOT_IMPLEMENTED; +#endif + break; + case eIntID_MacGraphiteTheme: + aResult = 0; + res = NS_ERROR_NOT_IMPLEMENTED; + break; + case eIntID_AlertNotificationOrigin: + aResult = NS_ALERT_TOP; + break; + case eIntID_IMERawInputUnderlineStyle: + case eIntID_IMEConvertedTextUnderlineStyle: + aResult = NS_STYLE_TEXT_DECORATION_STYLE_SOLID; + break; + case eIntID_IMESelectedRawTextUnderlineStyle: + case eIntID_IMESelectedConvertedTextUnderline: + aResult = NS_STYLE_TEXT_DECORATION_STYLE_NONE; + break; + case eIntID_SpellCheckerUnderlineStyle: + aResult = NS_STYLE_TEXT_DECORATION_STYLE_WAVY; + break; + case eIntID_MenuBarDrag: + aResult = sMenuSupportsDrag; + break; + case eIntID_ScrollbarButtonAutoRepeatBehavior: + aResult = 1; + break; + case eIntID_SwipeAnimationEnabled: + aResult = 0; + break; + case eIntID_ColorPickerAvailable: + aResult = 1; + break; + case eIntID_ContextMenuOffsetVertical: + case eIntID_ContextMenuOffsetHorizontal: + aResult = 2; + break; + default: + aResult = 0; + res = NS_ERROR_FAILURE; + } + + return res; +} + +nsresult +nsLookAndFeel::GetFloatImpl(FloatID aID, float &aResult) +{ + nsresult res = NS_OK; + res = nsXPLookAndFeel::GetFloatImpl(aID, aResult); + if (NS_SUCCEEDED(res)) + return res; + res = NS_OK; + + switch (aID) { + case eFloatID_IMEUnderlineRelativeSize: + aResult = 1.0f; + break; + case eFloatID_SpellCheckerUnderlineRelativeSize: + aResult = 1.0f; + break; + case eFloatID_CaretAspectRatio: + aResult = sCaretRatio; + break; + default: + aResult = -1.0; + res = NS_ERROR_FAILURE; + } + return res; +} + +static void +GetSystemFontInfo(GtkWidget *aWidget, + nsString *aFontName, + gfxFontStyle *aFontStyle) +{ + GtkSettings *settings = gtk_widget_get_settings(aWidget); + + aFontStyle->style = NS_FONT_STYLE_NORMAL; + + gchar *fontname; + g_object_get(settings, "gtk-font-name", &fontname, nullptr); + + PangoFontDescription *desc; + desc = pango_font_description_from_string(fontname); + + aFontStyle->systemFont = true; + + g_free(fontname); + + NS_NAMED_LITERAL_STRING(quote, "\""); + NS_ConvertUTF8toUTF16 family(pango_font_description_get_family(desc)); + *aFontName = quote + family + quote; + + aFontStyle->weight = pango_font_description_get_weight(desc); + + // FIXME: Set aFontStyle->stretch correctly! + aFontStyle->stretch = NS_FONT_STRETCH_NORMAL; + + float size = float(pango_font_description_get_size(desc)) / PANGO_SCALE; + + // |size| is now either pixels or pango-points (not Mozilla-points!) + + if (!pango_font_description_get_size_is_absolute(desc)) { + // |size| is in pango-points, so convert to pixels. + size *= float(gfxPlatformGtk::GetDPI()) / POINTS_PER_INCH_FLOAT; + } + + // Scale fonts up on HiDPI displays. + // This would be done automatically with cairo, but we manually manage + // the display scale for platform consistency. + size *= nsScreenGtk::GetGtkMonitorScaleFactor(); + + // |size| is now pixels + + aFontStyle->size = size; + + pango_font_description_free(desc); +} + +static void +GetSystemFontInfo(LookAndFeel::FontID aID, + nsString *aFontName, + gfxFontStyle *aFontStyle) +{ + if (aID == LookAndFeel::eFont_Widget) { + GtkWidget *label = gtk_label_new("M"); + GtkWidget *parent = gtk_fixed_new(); + GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP); + + gtk_container_add(GTK_CONTAINER(parent), label); + gtk_container_add(GTK_CONTAINER(window), parent); + + gtk_widget_ensure_style(label); + GetSystemFontInfo(label, aFontName, aFontStyle); + gtk_widget_destroy(window); // no unref, windows are different + + } else if (aID == LookAndFeel::eFont_Button) { + GtkWidget *label = gtk_label_new("M"); + GtkWidget *parent = gtk_fixed_new(); + GtkWidget *button = gtk_button_new(); + GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP); + + gtk_container_add(GTK_CONTAINER(button), label); + gtk_container_add(GTK_CONTAINER(parent), button); + gtk_container_add(GTK_CONTAINER(window), parent); + + gtk_widget_ensure_style(label); + GetSystemFontInfo(label, aFontName, aFontStyle); + gtk_widget_destroy(window); // no unref, windows are different + + } else if (aID == LookAndFeel::eFont_Field) { + GtkWidget *entry = gtk_entry_new(); + GtkWidget *parent = gtk_fixed_new(); + GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP); + + gtk_container_add(GTK_CONTAINER(parent), entry); + gtk_container_add(GTK_CONTAINER(window), parent); + + gtk_widget_ensure_style(entry); + GetSystemFontInfo(entry, aFontName, aFontStyle); + gtk_widget_destroy(window); // no unref, windows are different + + } else { + MOZ_ASSERT(aID == LookAndFeel::eFont_Menu, "unexpected font ID"); + GtkWidget *accel_label = gtk_accel_label_new("M"); + GtkWidget *menuitem = gtk_menu_item_new(); + GtkWidget *menu = gtk_menu_new(); + g_object_ref_sink(menu); + + gtk_container_add(GTK_CONTAINER(menuitem), accel_label); + gtk_menu_shell_append((GtkMenuShell *)GTK_MENU(menu), menuitem); + + gtk_widget_ensure_style(accel_label); + GetSystemFontInfo(accel_label, aFontName, aFontStyle); + g_object_unref(menu); + } +} + +bool +nsLookAndFeel::GetFontImpl(FontID aID, nsString& aFontName, + gfxFontStyle& aFontStyle, + float aDevPixPerCSSPixel) +{ + nsString *cachedFontName = nullptr; + gfxFontStyle *cachedFontStyle = nullptr; + bool *isCached = nullptr; + + switch (aID) { + case eFont_Menu: // css2 + case eFont_PullDownMenu: // css3 + cachedFontName = &mMenuFontName; + cachedFontStyle = &mMenuFontStyle; + isCached = &mMenuFontCached; + aID = eFont_Menu; + break; + + case eFont_Field: // css3 + case eFont_List: // css3 + cachedFontName = &mFieldFontName; + cachedFontStyle = &mFieldFontStyle; + isCached = &mFieldFontCached; + aID = eFont_Field; + break; + + case eFont_Button: // css3 + cachedFontName = &mButtonFontName; + cachedFontStyle = &mButtonFontStyle; + isCached = &mButtonFontCached; + break; + + case eFont_Caption: // css2 + case eFont_Icon: // css2 + case eFont_MessageBox: // css2 + case eFont_SmallCaption: // css2 + case eFont_StatusBar: // css2 + case eFont_Window: // css3 + case eFont_Document: // css3 + case eFont_Workspace: // css3 + case eFont_Desktop: // css3 + case eFont_Info: // css3 + case eFont_Dialog: // css3 + case eFont_Tooltips: // moz + case eFont_Widget: // moz + cachedFontName = &mDefaultFontName; + cachedFontStyle = &mDefaultFontStyle; + isCached = &mDefaultFontCached; + aID = eFont_Widget; + break; + } + + if (!*isCached) { + GetSystemFontInfo(aID, cachedFontName, cachedFontStyle); + *isCached = true; + } + + aFontName = *cachedFontName; + aFontStyle = *cachedFontStyle; + return true; +} + +#if (MOZ_WIDGET_GTK == 3) +static GtkStyleContext* +create_context(GtkWidgetPath *path) +{ + GtkStyleContext *style = gtk_style_context_new(); + gtk_style_context_set_path(style, path); + return(style); +} +#endif + +void +nsLookAndFeel::Init() +{ + GdkColor colorValue; + GdkColor *colorValuePtr; + +#if (MOZ_WIDGET_GTK == 2) + NS_ASSERTION(!mStyle, "already initialized"); + // GtkInvisibles come with a refcount that is not floating + // (since their initialization code calls g_object_ref_sink) and + // their destroy code releases that reference (which means they + // have to be explicitly destroyed, since calling unref enough + // to cause destruction would lead to *another* unref). + // However, this combination means that it's actually still ok + // to use the normal pattern, which is to g_object_ref_sink + // after construction, and then destroy *and* unref when we're + // done. (Though we could skip the g_object_ref_sink and the + // corresponding g_object_unref, but that's particular to + // GtkInvisibles and GtkWindows.) + GtkWidget *widget = gtk_invisible_new(); + g_object_ref_sink(widget); // effectively g_object_ref (see above) + + gtk_widget_ensure_style(widget); + mStyle = gtk_style_copy(gtk_widget_get_style(widget)); + + gtk_widget_destroy(widget); + g_object_unref(widget); + + // tooltip foreground and background + GtkStyle *style = gtk_rc_get_style_by_paths(gtk_settings_get_default(), + "gtk-tooltips", "GtkWindow", + GTK_TYPE_WINDOW); + if (style) { + sInfoBackground = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_NORMAL]); + sInfoText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]); + } + + // menu foreground & menu background + GtkWidget *accel_label = gtk_accel_label_new("M"); + GtkWidget *menuitem = gtk_menu_item_new(); + GtkWidget *menu = gtk_menu_new(); + + g_object_ref_sink(menu); + + gtk_container_add(GTK_CONTAINER(menuitem), accel_label); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + + gtk_widget_set_style(accel_label, nullptr); + gtk_widget_set_style(menu, nullptr); + gtk_widget_realize(menu); + gtk_widget_realize(accel_label); + + style = gtk_widget_get_style(accel_label); + if (style) { + sMenuText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]); + } + + style = gtk_widget_get_style(menu); + if (style) { + sMenuBackground = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_NORMAL]); + } + + style = gtk_widget_get_style(menuitem); + if (style) { + sMenuHover = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_PRELIGHT]); + sMenuHoverText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_PRELIGHT]); + } + + g_object_unref(menu); +#else + GdkRGBA color; + GtkStyleContext *style; + + // Gtk manages a screen's CSS in the settings object so we + // ask Gtk to create it explicitly. Otherwise we may end up + // with wrong color theme, see Bug 972382 + GtkSettings *settings = gtk_settings_get_for_screen(gdk_screen_get_default()); + + // Disable dark theme because it interacts poorly with widget styling in + // web content (see bug 1216658). + // To avoid triggering reload of theme settings unnecessarily, only set the + // setting when necessary. + const gchar* dark_setting = "gtk-application-prefer-dark-theme"; + gboolean dark; + g_object_get(settings, dark_setting, &dark, nullptr); + + if (dark && !PR_GetEnv("MOZ_ALLOW_GTK_DARK_THEME")) { + g_object_set(settings, dark_setting, FALSE, nullptr); + } + + GtkWidgetPath *path = gtk_widget_path_new(); + gtk_widget_path_append_type(path, GTK_TYPE_WINDOW); + + mBackgroundStyle = create_context(path); + gtk_style_context_add_class(mBackgroundStyle, GTK_STYLE_CLASS_BACKGROUND); + + mButtonStyle = create_context(path); + gtk_style_context_add_class(mButtonStyle, GTK_STYLE_CLASS_BUTTON); + + // Scrollbar colors + style = create_context(path); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_SCROLLBAR); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_TROUGH); + gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color); + sMozScrollbar = GDK_RGBA_TO_NS_RGBA(color); + g_object_unref(style); + + // Window colors + style = create_context(path); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND); + gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color); + sMozWindowBackground = GDK_RGBA_TO_NS_RGBA(color); + gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color); + sMozWindowText = GDK_RGBA_TO_NS_RGBA(color); + gtk_style_context_restore(style); + g_object_unref(style); + + // tooltip foreground and background + style = ClaimStyleContext(MOZ_GTK_TOOLTIP); + gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color); + sInfoBackground = GDK_RGBA_TO_NS_RGBA(color); + { + GtkStyleContext* boxStyle = + CreateStyleForWidget(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0), + style); + GtkStyleContext* labelStyle = + CreateStyleForWidget(gtk_label_new(nullptr), boxStyle); + gtk_style_context_get_color(labelStyle, GTK_STATE_FLAG_NORMAL, &color); + g_object_unref(labelStyle); + g_object_unref(boxStyle); + } + sInfoText = GDK_RGBA_TO_NS_RGBA(color); + ReleaseStyleContext(style); + + // menu foreground & menu background + GtkWidget *accel_label = gtk_accel_label_new("M"); + GtkWidget *menuitem = gtk_menu_item_new(); + GtkWidget *menu = gtk_menu_new(); + + g_object_ref_sink(menu); + + gtk_container_add(GTK_CONTAINER(menuitem), accel_label); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); + + style = gtk_widget_get_style_context(accel_label); + gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color); + sMenuText = GDK_RGBA_TO_NS_RGBA(color); + gtk_style_context_get_color(style, GTK_STATE_FLAG_INSENSITIVE, &color); + sMenuTextInactive = GDK_RGBA_TO_NS_RGBA(color); + + style = gtk_widget_get_style_context(menu); + gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color); + sMenuBackground = GDK_RGBA_TO_NS_RGBA(color); + + style = gtk_widget_get_style_context(menuitem); + gtk_style_context_get_background_color(style, GTK_STATE_FLAG_PRELIGHT, &color); + sMenuHover = GDK_RGBA_TO_NS_RGBA(color); + gtk_style_context_get_color(style, GTK_STATE_FLAG_PRELIGHT, &color); + sMenuHoverText = GDK_RGBA_TO_NS_RGBA(color); + + g_object_unref(menu); +#endif + + // button styles + GtkWidget *parent = gtk_fixed_new(); + GtkWidget *button = gtk_button_new(); + GtkWidget *label = gtk_label_new("M"); +#if (MOZ_WIDGET_GTK == 2) + GtkWidget *combobox = gtk_combo_box_new(); + GtkWidget *comboboxLabel = gtk_label_new("M"); + gtk_container_add(GTK_CONTAINER(combobox), comboboxLabel); +#else + GtkWidget *combobox = gtk_combo_box_new_with_entry(); + GtkWidget *comboboxLabel = gtk_bin_get_child(GTK_BIN(combobox)); +#endif + GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP); + GtkWidget *treeView = gtk_tree_view_new(); + GtkWidget *linkButton = gtk_link_button_new("http://example.com/"); + GtkWidget *menuBar = gtk_menu_bar_new(); + GtkWidget *menuBarItem = gtk_menu_item_new(); + GtkWidget *entry = gtk_entry_new(); + GtkWidget *textView = gtk_text_view_new(); + + gtk_container_add(GTK_CONTAINER(button), label); + gtk_container_add(GTK_CONTAINER(parent), button); + gtk_container_add(GTK_CONTAINER(parent), treeView); + gtk_container_add(GTK_CONTAINER(parent), linkButton); + gtk_container_add(GTK_CONTAINER(parent), combobox); + gtk_container_add(GTK_CONTAINER(parent), menuBar); + gtk_menu_shell_append(GTK_MENU_SHELL(menuBar), menuBarItem); + gtk_container_add(GTK_CONTAINER(window), parent); + gtk_container_add(GTK_CONTAINER(parent), entry); + gtk_container_add(GTK_CONTAINER(parent), textView); + +#if (MOZ_WIDGET_GTK == 2) + gtk_widget_set_style(button, nullptr); + gtk_widget_set_style(label, nullptr); + gtk_widget_set_style(treeView, nullptr); + gtk_widget_set_style(linkButton, nullptr); + gtk_widget_set_style(combobox, nullptr); + gtk_widget_set_style(comboboxLabel, nullptr); + gtk_widget_set_style(menuBar, nullptr); + gtk_widget_set_style(entry, nullptr); + + gtk_widget_realize(button); + gtk_widget_realize(label); + gtk_widget_realize(treeView); + gtk_widget_realize(linkButton); + gtk_widget_realize(combobox); + gtk_widget_realize(comboboxLabel); + gtk_widget_realize(menuBar); + gtk_widget_realize(entry); + + style = gtk_widget_get_style(label); + if (style) { + sButtonText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]); + } + + style = gtk_widget_get_style(comboboxLabel); + if (style) { + sComboBoxText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]); + } + style = gtk_widget_get_style(combobox); + if (style) { + sComboBoxBackground = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_NORMAL]); + } + + style = gtk_widget_get_style(menuBar); + if (style) { + sMenuBarText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_NORMAL]); + sMenuBarHoverText = GDK_COLOR_TO_NS_RGB(style->fg[GTK_STATE_SELECTED]); + } + + // GTK's guide to fancy odd row background colors: + // 1) Check if a theme explicitly defines an odd row color + // 2) If not, check if it defines an even row color, and darken it + // slightly by a hardcoded value (gtkstyle.c) + // 3) If neither are defined, take the base background color and + // darken that by a hardcoded value + colorValuePtr = nullptr; + gtk_widget_style_get(treeView, + "odd-row-color", &colorValuePtr, + nullptr); + + if (colorValuePtr) { + colorValue = *colorValuePtr; + } else { + gtk_widget_style_get(treeView, + "even-row-color", &colorValuePtr, + nullptr); + if (colorValuePtr) + darken_gdk_color(colorValuePtr, &colorValue); + else + darken_gdk_color(&treeView->style->base[GTK_STATE_NORMAL], &colorValue); + } + + sOddCellBackground = GDK_COLOR_TO_NS_RGB(colorValue); + if (colorValuePtr) + gdk_color_free(colorValuePtr); + + style = gtk_widget_get_style(button); + if (style) { + sButtonBackground = GDK_COLOR_TO_NS_RGB(style->bg[GTK_STATE_NORMAL]); + sFrameOuterLightBorder = + GDK_COLOR_TO_NS_RGB(style->light[GTK_STATE_NORMAL]); + sFrameInnerDarkBorder = + GDK_COLOR_TO_NS_RGB(style->dark[GTK_STATE_NORMAL]); + } +#else + // Text colors + style = gtk_widget_get_style_context(textView); + gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_VIEW); + gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color); + sMozFieldBackground = GDK_RGBA_TO_NS_RGBA(color); + gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color); + sMozFieldText = GDK_RGBA_TO_NS_RGBA(color); + + // Selected text and background + gtk_style_context_get_background_color(style, + static_cast<GtkStateFlags>(GTK_STATE_FLAG_FOCUSED|GTK_STATE_FLAG_SELECTED), + &color); + sTextSelectedBackground = GDK_RGBA_TO_NS_RGBA(color); + gtk_style_context_get_color(style, + static_cast<GtkStateFlags>(GTK_STATE_FLAG_FOCUSED|GTK_STATE_FLAG_SELECTED), + &color); + sTextSelectedText = GDK_RGBA_TO_NS_RGBA(color); + gtk_style_context_restore(style); + + // Button text, background, border + style = gtk_widget_get_style_context(label); + gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color); + sButtonText = GDK_RGBA_TO_NS_RGBA(color); + gtk_style_context_get_color(style, GTK_STATE_FLAG_PRELIGHT, &color); + sButtonHoverText = GDK_RGBA_TO_NS_RGBA(color); + + // Combobox text color + style = gtk_widget_get_style_context(comboboxLabel); + gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color); + sComboBoxText = GDK_RGBA_TO_NS_RGBA(color); + + // Menubar text and hover text colors + style = gtk_widget_get_style_context(menuBarItem); + gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color); + sMenuBarText = GDK_RGBA_TO_NS_RGBA(color); + gtk_style_context_get_color(style, GTK_STATE_FLAG_PRELIGHT, &color); + sMenuBarHoverText = GDK_RGBA_TO_NS_RGBA(color); + + // GTK's guide to fancy odd row background colors: + // 1) Check if a theme explicitly defines an odd row color + // 2) If not, check if it defines an even row color, and darken it + // slightly by a hardcoded value (gtkstyle.c) + // 3) If neither are defined, take the base background color and + // darken that by a hardcoded value + style = gtk_widget_get_style_context(treeView); + + // Get odd row background color + gtk_style_context_save(style); + gtk_style_context_add_region(style, GTK_STYLE_REGION_ROW, GTK_REGION_ODD); + gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color); + sOddCellBackground = GDK_RGBA_TO_NS_RGBA(color); + gtk_style_context_restore(style); + + gtk_widget_path_free(path); + + // GtkFrame has a "border" subnode on which Adwaita draws the border. + // Some themes do not draw on this node but draw a border on the widget + // root node, so check the root node if no border is found on the border + // node. + style = ClaimStyleContext(MOZ_GTK_FRAME_BORDER); + bool themeUsesColors = + GetBorderColors(style, &sFrameOuterLightBorder, &sFrameInnerDarkBorder); + ReleaseStyleContext(style); + if (!themeUsesColors) { + style = ClaimStyleContext(MOZ_GTK_FRAME); + GetBorderColors(style, &sFrameOuterLightBorder, &sFrameInnerDarkBorder); + ReleaseStyleContext(style); + } + + // GtkInfoBar + // TODO - Use WidgetCache for it? + GtkWidget* infoBar = gtk_info_bar_new(); + GtkWidget* infoBarContent = gtk_info_bar_get_content_area(GTK_INFO_BAR(infoBar)); + GtkWidget* infoBarLabel = gtk_label_new(nullptr); + gtk_container_add(GTK_CONTAINER(parent), infoBar); + gtk_container_add(GTK_CONTAINER(infoBarContent), infoBarLabel); + style = gtk_widget_get_style_context(infoBarLabel); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_INFO); + gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color); + sInfoBarText = GDK_RGBA_TO_NS_RGBA(color); +#endif + // Some themes have a unified menu bar, and support window dragging on it + gboolean supports_menubar_drag = FALSE; + GParamSpec *param_spec = + gtk_widget_class_find_style_property(GTK_WIDGET_GET_CLASS(menuBar), + "window-dragging"); + if (param_spec) { + if (g_type_is_a(G_PARAM_SPEC_VALUE_TYPE(param_spec), G_TYPE_BOOLEAN)) { + gtk_widget_style_get(menuBar, + "window-dragging", &supports_menubar_drag, + nullptr); + } + } + sMenuSupportsDrag = supports_menubar_drag; + + colorValuePtr = nullptr; + gtk_widget_style_get(linkButton, "link-color", &colorValuePtr, nullptr); + if (colorValuePtr) { + colorValue = *colorValuePtr; // we can't pass deref pointers to GDK_COLOR_TO_NS_RGB + sNativeHyperLinkText = GDK_COLOR_TO_NS_RGB(colorValue); + gdk_color_free(colorValuePtr); + } else { + sNativeHyperLinkText = NS_RGB(0x00,0x00,0xEE); + } + + // invisible character styles + guint value; + g_object_get (entry, "invisible-char", &value, nullptr); + sInvisibleCharacter = char16_t(value); + + // caret styles + gtk_widget_style_get(entry, + "cursor-aspect-ratio", &sCaretRatio, + nullptr); + + gtk_widget_destroy(window); +} + +// virtual +char16_t +nsLookAndFeel::GetPasswordCharacterImpl() +{ + return sInvisibleCharacter; +} + +void +nsLookAndFeel::RefreshImpl() +{ + nsXPLookAndFeel::RefreshImpl(); + + mDefaultFontCached = false; + mButtonFontCached = false; + mFieldFontCached = false; + mMenuFontCached = false; + +#if (MOZ_WIDGET_GTK == 2) + g_object_unref(mStyle); + mStyle = nullptr; +#else + g_object_unref(mBackgroundStyle); + g_object_unref(mButtonStyle); + + mBackgroundStyle = nullptr; + mButtonStyle = nullptr; +#endif + + Init(); +} + +bool +nsLookAndFeel::GetEchoPasswordImpl() { + return false; +} |