diff options
-rw-r--r-- | build/valgrind/x86_64-redhat-linux-gnu.sup | 1 | ||||
-rw-r--r-- | widget/gtk/WidgetStyleCache.cpp | 159 | ||||
-rw-r--r-- | widget/gtk/gtk3drawing.cpp | 285 | ||||
-rw-r--r-- | widget/gtk/gtkdrawing.h | 18 | ||||
-rw-r--r-- | widget/gtk/nsLookAndFeel.cpp | 201 | ||||
-rw-r--r-- | widget/gtk/nsLookAndFeel.h | 3 | ||||
-rw-r--r-- | widget/gtk/nsWindow.cpp | 16 |
7 files changed, 398 insertions, 285 deletions
diff --git a/build/valgrind/x86_64-redhat-linux-gnu.sup b/build/valgrind/x86_64-redhat-linux-gnu.sup index d253a3a4e..28656e418 100644 --- a/build/valgrind/x86_64-redhat-linux-gnu.sup +++ b/build/valgrind/x86_64-redhat-linux-gnu.sup @@ -105,7 +105,6 @@ fun:g_object_newv fun:g_object_new_valist fun:g_object_new - fun:_ZN13nsLookAndFeel4InitEv ... } # set_color() in gtkstyle.c of GTK version 3.4.4 only can leak GdkRGBA diff --git a/widget/gtk/WidgetStyleCache.cpp b/widget/gtk/WidgetStyleCache.cpp index fd099681f..f35a451aa 100644 --- a/widget/gtk/WidgetStyleCache.cpp +++ b/widget/gtk/WidgetStyleCache.cpp @@ -434,15 +434,6 @@ CreateScrolledWindowWidget() } static GtkWidget* -CreateTextViewWidget() -{ - GtkWidget* widget = gtk_text_view_new(); - gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_SCROLLED_WINDOW)), - widget); - return widget; -} - -static GtkWidget* CreateMenuSeparatorWidget() { GtkWidget* widget = gtk_separator_menu_item_new(); @@ -591,8 +582,6 @@ CreateWidget(WidgetNodeType aWidgetType) return CreateEntryWidget(); case MOZ_GTK_SCROLLED_WINDOW: return CreateScrolledWindowWidget(); - case MOZ_GTK_TEXT_VIEW: - return CreateTextViewWidget(); case MOZ_GTK_TREEVIEW: return CreateTreeViewWidget(); case MOZ_GTK_TREE_HEADER_CELL: @@ -637,6 +626,24 @@ GetWidget(WidgetNodeType aWidgetType) GtkWidget* widget = sWidgetStorage[aWidgetType]; if (!widget) { widget = CreateWidget(aWidgetType); + // Some widgets (MOZ_GTK_COMBOBOX_SEPARATOR for instance) may not be + // available or implemented. + if (!widget) + return nullptr; + // In GTK versions prior to 3.18, automatic invalidation of style contexts + // for widgets was delayed until the next resize event. Gecko however, + // typically uses the style context before the resize event runs and so an + // explicit invalidation may be required. This is necessary if a style + // property was retrieved before all changes were made to the style + // context. One such situation is where gtk_button_construct_child() + // retrieves the style property "image-spacing" during construction of the + // GtkButton, before its parent is set to provide inheritance of ancestor + // properties. More recent GTK versions do not need this, but do not + // re-resolve until required and so invalidation does not trigger + // unnecessary resolution in general. + GtkStyleContext* style = gtk_widget_get_style_context(widget); + gtk_style_context_invalidate(style); + sWidgetStorage[aWidgetType] = widget; } return widget; @@ -725,6 +732,21 @@ CreateCSSNode(const char* aName, GtkStyleContext* aParentStyle, GType aType) gtk_style_context_set_parent(context, aParentStyle); gtk_widget_path_unref(path); + // In GTK 3.4, gtk_render_* functions use |theming_engine| on the style + // context without ensuring any style resolution sets it appropriately + // in style_data_lookup(). e.g. + // https://git.gnome.org/browse/gtk+/tree/gtk/gtkstylecontext.c?h=3.4.4#n3847 + // + // That can result in incorrect drawing on first draw. To work around this, + // force a style look-up to set |theming_engine|. It is sufficient to do + // this only on context creation, instead of after every modification to the + // context, because themes typically (Ambiance and oxygen-gtk, at least) set + // the "engine" property with the '*' selector. + if (GTK_MAJOR_VERSION == 3 && gtk_get_minor_version() < 6) { + GdkRGBA unused; + gtk_style_context_get_color(context, GTK_STATE_FLAG_NORMAL, &unused); + } + return context; } @@ -747,13 +769,38 @@ GetWidgetRootStyle(WidgetNodeType aNodeType) case MOZ_GTK_IMAGEMENUITEM: style = CreateStyleForWidget(gtk_image_menu_item_new(), MOZ_GTK_MENUPOPUP); break; - case MOZ_GTK_CHECKMENUITEM_CONTAINER: + case MOZ_GTK_CHECKMENUITEM: style = CreateStyleForWidget(gtk_check_menu_item_new(), MOZ_GTK_MENUPOPUP); break; - case MOZ_GTK_RADIOMENUITEM_CONTAINER: + case MOZ_GTK_RADIOMENUITEM: style = CreateStyleForWidget(gtk_radio_menu_item_new(nullptr), MOZ_GTK_MENUPOPUP); break; + case MOZ_GTK_TEXT_VIEW: + style = CreateStyleForWidget(gtk_text_view_new(), + MOZ_GTK_SCROLLED_WINDOW); + break; + case MOZ_GTK_TOOLTIP: + if (gtk_check_version(3, 20, 0) != nullptr) { + // The tooltip style class is added first in CreateTooltipWidget() + // and transfered to style in CreateStyleForWidget(). + GtkWidget* tooltipWindow = CreateTooltipWidget(); + style = CreateStyleForWidget(tooltipWindow, nullptr); + gtk_widget_destroy(tooltipWindow); // Release GtkWindow self-reference. + } else { + // We create this from the path because GtkTooltipWindow is not public. + style = CreateCSSNode("tooltip", nullptr, GTK_TYPE_TOOLTIP); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND); + } + break; + case MOZ_GTK_TOOLTIP_BOX: + style = CreateStyleForWidget(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0), + MOZ_GTK_TOOLTIP); + break; + case MOZ_GTK_TOOLTIP_BOX_LABEL: + style = CreateStyleForWidget(gtk_label_new(nullptr), + MOZ_GTK_TOOLTIP_BOX); + break; default: GtkWidget* widget = GetWidget(aNodeType); MOZ_ASSERT(widget); @@ -827,13 +874,13 @@ GetCssNodeStyleInternal(WidgetNodeType aNodeType) style = CreateChildCSSNode(GTK_STYLE_CLASS_CHECK, MOZ_GTK_CHECKBUTTON_CONTAINER); break; - case MOZ_GTK_RADIOMENUITEM: + case MOZ_GTK_RADIOMENUITEM_INDICATOR: style = CreateChildCSSNode(GTK_STYLE_CLASS_RADIO, - MOZ_GTK_RADIOMENUITEM_CONTAINER); + MOZ_GTK_RADIOMENUITEM); break; - case MOZ_GTK_CHECKMENUITEM: + case MOZ_GTK_CHECKMENUITEM_INDICATOR: style = CreateChildCSSNode(GTK_STYLE_CLASS_CHECK, - MOZ_GTK_CHECKMENUITEM_CONTAINER); + MOZ_GTK_CHECKMENUITEM); break; case MOZ_GTK_PROGRESS_TROUGH: /* Progress bar background (trough) */ @@ -844,11 +891,6 @@ GetCssNodeStyleInternal(WidgetNodeType aNodeType) style = CreateChildCSSNode("progress", MOZ_GTK_PROGRESS_TROUGH); break; - case MOZ_GTK_TOOLTIP: - // We create this from the path because GtkTooltipWindow is not public. - style = CreateCSSNode("tooltip", nullptr, GTK_TYPE_TOOLTIP); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND); - break; case MOZ_GTK_GRIPPER: // TODO - create from CSS node return GetWidgetStyleWithClass(MOZ_GTK_GRIPPER, @@ -865,10 +907,28 @@ GetCssNodeStyleInternal(WidgetNodeType aNodeType) // TODO - create from CSS node return GetWidgetStyleWithClass(MOZ_GTK_SCROLLED_WINDOW, GTK_STYLE_CLASS_FRAME); - case MOZ_GTK_TEXT_VIEW: - // TODO - create from CSS node - return GetWidgetStyleWithClass(MOZ_GTK_TEXT_VIEW, - GTK_STYLE_CLASS_VIEW); + case MOZ_GTK_TEXT_VIEW_TEXT: + case MOZ_GTK_RESIZER: + style = CreateChildCSSNode("text", MOZ_GTK_TEXT_VIEW); + if (aNodeType == MOZ_GTK_RESIZER) { + // The "grip" class provides the correct builtin icon from + // gtk_render_handle(). The icon is drawn with shaded variants of + // the background color, and so a transparent background would lead to + // a transparent resizer. gtk_render_handle() also uses the + // background color to draw a background, and so this style otherwise + // matches what is used in GtkTextView to match the background with + // textarea elements. + GdkRGBA color; + gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, + &color); + if (color.alpha == 0.0) { + g_object_unref(style); + style = CreateStyleForWidget(gtk_text_view_new(), + MOZ_GTK_SCROLLED_WINDOW); + } + gtk_style_context_add_class(style, GTK_STYLE_CLASS_GRIP); + } + break; case MOZ_GTK_FRAME_BORDER: style = CreateChildCSSNode("border", MOZ_GTK_FRAME); break; @@ -971,27 +1031,20 @@ GetWidgetStyleInternal(WidgetNodeType aNodeType) case MOZ_GTK_CHECKBUTTON: return GetWidgetStyleWithClass(MOZ_GTK_CHECKBUTTON_CONTAINER, GTK_STYLE_CLASS_CHECK); - case MOZ_GTK_RADIOMENUITEM: - return GetWidgetStyleWithClass(MOZ_GTK_RADIOMENUITEM_CONTAINER, + case MOZ_GTK_RADIOMENUITEM_INDICATOR: + return GetWidgetStyleWithClass(MOZ_GTK_RADIOMENUITEM, GTK_STYLE_CLASS_RADIO); - case MOZ_GTK_CHECKMENUITEM: - return GetWidgetStyleWithClass(MOZ_GTK_CHECKMENUITEM_CONTAINER, + case MOZ_GTK_CHECKMENUITEM_INDICATOR: + return GetWidgetStyleWithClass(MOZ_GTK_CHECKMENUITEM, GTK_STYLE_CLASS_CHECK); case MOZ_GTK_PROGRESS_TROUGH: return GetWidgetStyleWithClass(MOZ_GTK_PROGRESSBAR, GTK_STYLE_CLASS_TROUGH); - case MOZ_GTK_TOOLTIP: { - GtkStyleContext* style = sStyleStorage[aNodeType]; - if (style) - return style; - - // The tooltip style class is added first in CreateTooltipWidget() so - // that gtk_widget_path_append_for_widget() in CreateStyleForWidget() - // will find it. - GtkWidget* tooltipWindow = CreateTooltipWidget(); - style = CreateStyleForWidget(tooltipWindow, nullptr); - gtk_widget_destroy(tooltipWindow); // Release GtkWindow self-reference. - sStyleStorage[aNodeType] = style; + case MOZ_GTK_PROGRESS_CHUNK: { + GtkStyleContext* style = + GetWidgetStyleWithClass(MOZ_GTK_PROGRESSBAR, + GTK_STYLE_CLASS_PROGRESSBAR); + gtk_style_context_remove_class(style, GTK_STYLE_CLASS_TROUGH); return style; } case MOZ_GTK_GRIPPER: @@ -1006,9 +1059,25 @@ GetWidgetStyleInternal(WidgetNodeType aNodeType) case MOZ_GTK_SCROLLED_WINDOW: return GetWidgetStyleWithClass(MOZ_GTK_SCROLLED_WINDOW, GTK_STYLE_CLASS_FRAME); - case MOZ_GTK_TEXT_VIEW: - return GetWidgetStyleWithClass(MOZ_GTK_TEXT_VIEW, - GTK_STYLE_CLASS_VIEW); + case MOZ_GTK_TEXT_VIEW_TEXT: + case MOZ_GTK_RESIZER: { + // GTK versions prior to 3.20 do not have the view class on the root + // node, but add this to determine the background for the text window. + GtkStyleContext* style = + GetWidgetStyleWithClass(MOZ_GTK_TEXT_VIEW, GTK_STYLE_CLASS_VIEW); + if (aNodeType == MOZ_GTK_RESIZER) { + // The "grip" class provides the correct builtin icon from + // gtk_render_handle(). The icon is drawn with shaded variants of + // the background color, and so a transparent background would lead to + // a transparent resizer. gtk_render_handle() also uses the + // background color to draw a background, and so this style otherwise + // matches MOZ_GTK_TEXT_VIEW_TEXT to match the background with + // textarea elements. GtkTextView creates a separate text window and + // so the background should not be transparent. + gtk_style_context_add_class(style, GTK_STYLE_CLASS_GRIP); + } + return style; + } case MOZ_GTK_FRAME_BORDER: return GetWidgetRootStyle(MOZ_GTK_FRAME); case MOZ_GTK_TREEVIEW_VIEW: diff --git a/widget/gtk/gtk3drawing.cpp b/widget/gtk/gtk3drawing.cpp index fb95b4cc4..c592fa51c 100644 --- a/widget/gtk/gtk3drawing.cpp +++ b/widget/gtk/gtk3drawing.cpp @@ -36,6 +36,10 @@ static gboolean is_initialized; static gint moz_gtk_get_tab_thickness(GtkStyleContext *style); +static gint +moz_gtk_menu_item_paint(WidgetNodeType widget, cairo_t *cr, GdkRectangle* rect, + GtkWidgetState* state, GtkTextDirection direction); + // GetStateFlagsFromGtkWidgetState() can be safely used for the specific // GtkWidgets that set both prelight and active flags. For other widgets, // either the GtkStateFlags or Gecko's GtkWidgetState need to be carefully @@ -167,7 +171,7 @@ moz_gtk_menuitem_get_horizontal_padding(gint* horizontal_padding) gint moz_gtk_checkmenuitem_get_horizontal_padding(gint* horizontal_padding) { - GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_CHECKMENUITEM_CONTAINER); + GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_CHECKMENUITEM); gtk_style_context_get_style(style, "horizontal-padding", horizontal_padding, nullptr); @@ -463,7 +467,7 @@ moz_gtk_get_widget_min_size(WidgetNodeType aGtkWidgetType, int* width, } static void -moz_gtk_rectangle_inset(GdkRectangle* rect, GtkBorder& aBorder) +Inset(GdkRectangle* rect, GtkBorder& aBorder) { MOZ_ASSERT(rect); rect->x += aBorder.left; @@ -472,17 +476,29 @@ moz_gtk_rectangle_inset(GdkRectangle* rect, GtkBorder& aBorder) rect->height -= aBorder.top + aBorder.bottom; } -/* Subtracting margin is used to inset drawing of element which can have margins, - * like scrollbar, scrollbar's trough, thumb and scrollbar's button */ +// Inset a rectangle by the margins specified in a style context. static void -moz_gtk_subtract_margin(GtkStyleContext* style, GdkRectangle* rect) +InsetByMargin(GdkRectangle* rect, GtkStyleContext* style) { MOZ_ASSERT(rect); GtkBorder margin; gtk_style_context_get_margin(style, gtk_style_context_get_state(style), &margin); - moz_gtk_rectangle_inset(rect, margin); + Inset(rect, margin); +} + +// Inset a rectangle by the border and padding specified in a style context. +static void +InsetByBorderPadding(GdkRectangle* rect, GtkStyleContext* style) +{ + GtkStateFlags state = gtk_style_context_get_state(style); + GtkBorder padding, border; + + gtk_style_context_get_padding(style, state, &padding); + Inset(rect, padding); + gtk_style_context_get_border(style, state, &border); + Inset(rect, border); } static gint @@ -528,7 +544,7 @@ moz_gtk_scrollbar_button_paint(cairo_t *cr, const GdkRectangle* aRect, if (gtk_check_version(3,20,0) == nullptr) { // The "trough-border" is not used since GTK 3.20. The stepper margin // box occupies the full width of the "contents" gadget content box. - moz_gtk_subtract_margin(style, &rect); + InsetByMargin(&rect, style); } else { // Scrollbar button has to be inset by trough_border because its DOM // element is filling width of vertical scrollbar's track (or height @@ -601,7 +617,7 @@ moz_gtk_draw_styled_frame(GtkStyleContext* style, cairo_t *cr, { GdkRectangle rect = *aRect; if (gtk_check_version(3, 6, 0) == nullptr) { - moz_gtk_subtract_margin(style, &rect); + InsetByMargin(&rect, style); } gtk_render_background(style, cr, rect.x, rect.y, rect.width, rect.height); gtk_render_frame(style, cr, rect.x, rect.y, rect.width, rect.height); @@ -656,7 +672,7 @@ moz_gtk_scrollbar_thumb_paint(WidgetNodeType widget, GdkRectangle rect = *aRect; GtkStyleContext* style = ClaimStyleContext(widget, direction, state_flags); - moz_gtk_subtract_margin(style, &rect); + InsetByMargin(&rect, style); gtk_render_slider(style, cr, rect.x, @@ -857,7 +873,7 @@ moz_gtk_entry_paint(cairo_t *cr, GdkRectangle* rect, } static gint -moz_gtk_text_view_paint(cairo_t *cr, GdkRectangle* rect, +moz_gtk_text_view_paint(cairo_t *cr, GdkRectangle* aRect, GtkWidgetState* state, GtkTextDirection direction) { @@ -874,24 +890,24 @@ moz_gtk_text_view_paint(cairo_t *cr, GdkRectangle* rect, GtkStyleContext* style_frame = ClaimStyleContext(MOZ_GTK_SCROLLED_WINDOW, direction, state_flags); - gtk_render_frame(style_frame, cr, rect->x, rect->y, rect->width, rect->height); + gtk_render_frame(style_frame, cr, + aRect->x, aRect->y, aRect->width, aRect->height); + + GdkRectangle rect = *aRect; + InsetByBorderPadding(&rect, style_frame); - GtkBorder border, padding; - gtk_style_context_get_border(style_frame, state_flags, &border); - gtk_style_context_get_padding(style_frame, state_flags, &padding); ReleaseStyleContext(style_frame); GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TEXT_VIEW, direction, state_flags); - - gint xthickness = border.left + padding.left; - gint ythickness = border.top + padding.top; - - gtk_render_background(style, cr, - rect->x + xthickness, rect->y + ythickness, - rect->width - 2 * xthickness, - rect->height - 2 * ythickness); - + gtk_render_background(style, cr, rect.x, rect.y, rect.width, rect.height); + ReleaseStyleContext(style); + // There is a separate "text" window, which usually provides the + // background behind the text. However, this is transparent in Ambiance + // for GTK 3.20, in which case the MOZ_GTK_TEXT_VIEW background is + // visible. + style = ClaimStyleContext(MOZ_GTK_TEXT_VIEW_TEXT, direction, state_flags); + gtk_render_background(style, cr, rect.x, rect.y, rect.width, rect.height); ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; @@ -1013,8 +1029,7 @@ moz_gtk_treeview_expander_paint(cairo_t *cr, GdkRectangle* rect, return MOZ_GTK_SUCCESS; } -/* See gtk_separator_draw() for reference. -*/ +/* See gtk_separator_draw() for reference. */ static gint moz_gtk_combo_box_paint(cairo_t *cr, GdkRectangle* rect, GtkWidgetState* state, @@ -1283,6 +1298,7 @@ moz_gtk_tooltip_paint(cairo_t *cr, const GdkRectangle* aRect, GdkRectangle rect = *aRect; gtk_render_background(style, cr, rect.x, rect.y, rect.width, rect.height); gtk_render_frame(style, cr, rect.x, rect.y, rect.width, rect.height); + ReleaseStyleContext(style); // Horizontal Box drawing // @@ -1292,33 +1308,26 @@ moz_gtk_tooltip_paint(cairo_t *cr, const GdkRectangle* aRect, // 6px margin. // For drawing Horizontal Box we have to inset drawing area by that 6px // plus its CSS margin. - GtkStyleContext* boxStyle = - CreateStyleForWidget(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0), style); + GtkStyleContext* boxStyle = ClaimStyleContext(MOZ_GTK_TOOLTIP_BOX, direction); rect.x += 6; rect.y += 6; rect.width -= 12; rect.height -= 12; - moz_gtk_subtract_margin(boxStyle, &rect); + InsetByMargin(&rect, boxStyle); gtk_render_background(boxStyle, cr, rect.x, rect.y, rect.width, rect.height); gtk_render_frame(boxStyle, cr, rect.x, rect.y, rect.width, rect.height); // Label drawing - GtkBorder padding, border; - gtk_style_context_get_padding(boxStyle, GTK_STATE_FLAG_NORMAL, &padding); - moz_gtk_rectangle_inset(&rect, padding); - gtk_style_context_get_border(boxStyle, GTK_STATE_FLAG_NORMAL, &border); - moz_gtk_rectangle_inset(&rect, border); + InsetByBorderPadding(&rect, boxStyle); + ReleaseStyleContext(boxStyle); GtkStyleContext* labelStyle = - CreateStyleForWidget(gtk_label_new(nullptr), boxStyle); + ClaimStyleContext(MOZ_GTK_TOOLTIP_BOX_LABEL, direction); moz_gtk_draw_styled_frame(labelStyle, cr, &rect, false); - g_object_unref(labelStyle); - - g_object_unref(boxStyle); + ReleaseStyleContext(labelStyle); - ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } @@ -1327,17 +1336,9 @@ moz_gtk_resizer_paint(cairo_t *cr, GdkRectangle* rect, GtkWidgetState* state, GtkTextDirection direction) { - GtkStyleContext* style; - - // gtk_render_handle() draws a background, so use GtkTextView and its - // GTK_STYLE_CLASS_VIEW to match the background with textarea elements. - // The resizer is drawn with shaded variants of the background color, and - // so a transparent background would lead to a transparent resizer. - style = ClaimStyleContext(MOZ_GTK_TEXT_VIEW, GTK_TEXT_DIR_LTR, - GetStateFlagsFromGtkWidgetState(state)); - // TODO - we need to save/restore style when gtk 3.20 CSS node path - // is used - gtk_style_context_add_class(style, GTK_STYLE_CLASS_GRIP); + GtkStyleContext* style = + ClaimStyleContext(MOZ_GTK_RESIZER, GTK_TEXT_DIR_LTR, + GetStateFlagsFromGtkWidgetState(state)); // Workaround unico not respecting the text direction for resizers. // See bug 1174248. @@ -1384,17 +1385,8 @@ moz_gtk_progress_chunk_paint(cairo_t *cr, GdkRectangle* rect, GtkTextDirection direction, WidgetNodeType widget) { - GtkStyleContext* style; - - if (gtk_check_version(3, 20, 0) != nullptr) { - /* Ask for MOZ_GTK_PROGRESS_TROUGH instead of MOZ_GTK_PROGRESSBAR - * because ClaimStyleContext() saves/restores that style */ - style = ClaimStyleContext(MOZ_GTK_PROGRESS_TROUGH, direction); - gtk_style_context_remove_class(style, GTK_STYLE_CLASS_TROUGH); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_PROGRESSBAR); - } else { - style = ClaimStyleContext(MOZ_GTK_PROGRESS_CHUNK, direction); - } + GtkStyleContext* style = + ClaimStyleContext(MOZ_GTK_PROGRESS_CHUNK, direction); if (widget == MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE || widget == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE) { @@ -1778,6 +1770,13 @@ static gint moz_gtk_menu_separator_paint(cairo_t *cr, GdkRectangle* rect, GtkTextDirection direction) { + GtkWidgetState defaultState = { 0 }; + moz_gtk_menu_item_paint(MOZ_GTK_MENUSEPARATOR, cr, rect, + &defaultState, direction); + + if (gtk_get_minor_version() >= 20) + return MOZ_GTK_SUCCESS; + GtkStyleContext* style; gboolean wide_separators; gint separator_height; @@ -1825,36 +1824,39 @@ moz_gtk_menu_item_paint(WidgetNodeType widget, cairo_t *cr, GdkRectangle* rect, GtkWidgetState* state, GtkTextDirection direction) { gint x, y, w, h; + guint minorVersion = gtk_get_minor_version(); + GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); - if (state->inHover && !state->disabled) { - GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); - GtkStyleContext* style = - ClaimStyleContext(widget, direction, state_flags); - - bool pre_3_6 = gtk_check_version(3, 6, 0) != nullptr; - if (pre_3_6) { - // GTK+ 3.4 saves the style context and adds the menubar class to - // menubar children, but does each of these only when drawing, not - // during layout. - gtk_style_context_save(style); - if (widget == MOZ_GTK_MENUBARITEM) { - gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR); - } + // GTK versions prior to 3.8 render the background and frame only when not + // a separator and in hover prelight. + if (minorVersion < 8 && (widget == MOZ_GTK_MENUSEPARATOR || + !(state_flags & GTK_STATE_FLAG_PRELIGHT))) + return MOZ_GTK_SUCCESS; + + GtkStyleContext* style = ClaimStyleContext(widget, direction, state_flags); + + if (minorVersion < 6) { + // GTK+ 3.4 saves the style context and adds the menubar class to + // menubar children, but does each of these only when drawing, not + // during layout. + gtk_style_context_save(style); + if (widget == MOZ_GTK_MENUBARITEM) { + gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR); } + } - x = rect->x; - y = rect->y; - w = rect->width; - h = rect->height; + x = rect->x; + y = rect->y; + w = rect->width; + h = rect->height; - gtk_render_background(style, cr, x, y, w, h); - gtk_render_frame(style, cr, x, y, w, h); + gtk_render_background(style, cr, x, y, w, h); + gtk_render_frame(style, cr, x, y, w, h); - if (pre_3_6) { - gtk_style_context_restore(style); - } - ReleaseStyleContext(style); + if (minorVersion < 6) { + gtk_style_context_restore(style); } + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } @@ -1874,16 +1876,16 @@ moz_gtk_menu_arrow_paint(cairo_t *cr, GdkRectangle* rect, return MOZ_GTK_SUCCESS; } -// See gtk_real_check_menu_item_draw_indicator() for reference. +// For reference, see gtk_check_menu_item_size_allocate() in GTK versions after +// 3.20 and gtk_real_check_menu_item_draw_indicator() in earlier versions. static gint -moz_gtk_check_menu_item_paint(cairo_t *cr, GdkRectangle* rect, +moz_gtk_check_menu_item_paint(WidgetNodeType widgetType, + cairo_t *cr, GdkRectangle* rect, GtkWidgetState* state, - gboolean checked, gboolean isradio, - GtkTextDirection direction) + gboolean checked, GtkTextDirection direction) { GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); GtkStyleContext* style; - GtkBorder padding; gint indicator_size, horizontal_padding; gint x, y; @@ -1893,35 +1895,44 @@ moz_gtk_check_menu_item_paint(cairo_t *cr, GdkRectangle* rect, state_flags = static_cast<GtkStateFlags>(state_flags|checkbox_check_state); } - style = ClaimStyleContext(isradio ? MOZ_GTK_RADIOMENUITEM_CONTAINER : - MOZ_GTK_CHECKMENUITEM_CONTAINER, - direction); + bool pre_3_20 = gtk_get_minor_version() < 20; + gint offset; + style = ClaimStyleContext(widgetType, direction); gtk_style_context_get_style(style, "indicator-size", &indicator_size, "horizontal-padding", &horizontal_padding, NULL); + if (pre_3_20) { + GtkBorder padding; + gtk_style_context_get_padding(style, state_flags, &padding); + offset = horizontal_padding + padding.left + 2; + } else { + GdkRectangle r = { 0 }; + InsetByMargin(&r, style); + InsetByBorderPadding(&r, style); + offset = r.x; + } ReleaseStyleContext(style); - style = ClaimStyleContext(isradio ? MOZ_GTK_RADIOMENUITEM : - MOZ_GTK_CHECKMENUITEM, - direction, state_flags); - gtk_style_context_get_padding(style, state_flags, &padding); - gint offset = padding.left + 2; + bool isRadio = (widgetType == MOZ_GTK_RADIOMENUITEM); + WidgetNodeType indicatorType = isRadio ? MOZ_GTK_RADIOMENUITEM_INDICATOR + : MOZ_GTK_CHECKMENUITEM_INDICATOR; + style = ClaimStyleContext(indicatorType, direction, state_flags); if (direction == GTK_TEXT_DIR_RTL) { - x = rect->width - indicator_size - offset - horizontal_padding; + x = rect->width - indicator_size - offset; } else { - x = rect->x + offset + horizontal_padding; + x = rect->x + offset; } y = rect->y + (rect->height - indicator_size) / 2; - if (gtk_check_version(3, 20, 0) == nullptr) { + if (!pre_3_20) { gtk_render_background(style, cr, x, y, indicator_size, indicator_size); gtk_render_frame(style, cr, x, y, indicator_size, indicator_size); } - if (isradio) { + if (isRadio) { gtk_render_option(style, cr, x, y, indicator_size, indicator_size); } else { gtk_render_check(style, cr, x, y, indicator_size, indicator_size); @@ -2166,12 +2177,15 @@ moz_gtk_get_widget_border(WidgetNodeType widget, gint* left, gint* top, { // Bug 1274143 for MOZ_GTK_MENUBARITEM WidgetNodeType type = - widget == MOZ_GTK_MENUBARITEM || widget == MOZ_GTK_MENUITEM ? - MOZ_GTK_MENUITEM : MOZ_GTK_CHECKMENUITEM_CONTAINER; + widget == MOZ_GTK_MENUBARITEM ? MOZ_GTK_MENUITEM : widget; style = ClaimStyleContext(type); - moz_gtk_add_style_padding(style, left, top, right, bottom); - + if (gtk_get_minor_version() < 20) { + moz_gtk_add_style_padding(style, left, top, right, bottom); + } else { + moz_gtk_add_margin_border_padding(style, + left, top, right, bottom); + } ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } @@ -2180,7 +2194,6 @@ moz_gtk_get_widget_border(WidgetNodeType widget, gint* left, gint* top, break; case MOZ_GTK_TOOLTIP: { - style = ClaimStyleContext(MOZ_GTK_TOOLTIP); // In GTK 3 there are 6 pixels of additional margin around the box. // See details there: // https://github.com/GNOME/gtk/blob/5ea69a136bd7e4970b3a800390e20314665aaed2/gtk/ui/gtktooltipwindow.ui#L11 @@ -2189,21 +2202,16 @@ moz_gtk_get_widget_border(WidgetNodeType widget, gint* left, gint* top, // We also need to add margin/padding/borders from Tooltip content. // Tooltip contains horizontal box, where icon and label is put. // We ignore icon as long as we don't have support for it. - GtkStyleContext* boxStyle = - CreateStyleForWidget(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0), - style); + GtkStyleContext* boxStyle = ClaimStyleContext(MOZ_GTK_TOOLTIP_BOX); moz_gtk_add_margin_border_padding(boxStyle, left, top, right, bottom); + ReleaseStyleContext(boxStyle); - GtkStyleContext* labelStyle = - CreateStyleForWidget(gtk_label_new(nullptr), boxStyle); + GtkStyleContext* labelStyle = ClaimStyleContext(MOZ_GTK_TOOLTIP_BOX_LABEL); moz_gtk_add_margin_border_padding(labelStyle, left, top, right, bottom); + ReleaseStyleContext(labelStyle); - g_object_unref(labelStyle); - g_object_unref(boxStyle); - - ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } case MOZ_GTK_SCROLLBAR_VERTICAL: @@ -2492,11 +2500,11 @@ void moz_gtk_get_scale_metrics(GtkOrientation orient, gint* scale_width, gint* scale_height) { - WidgetNodeType widget = (orient == GTK_ORIENTATION_HORIZONTAL) ? - MOZ_GTK_SCALE_HORIZONTAL : - MOZ_GTK_SCALE_VERTICAL; - if (gtk_check_version(3, 20, 0) != nullptr) { + WidgetNodeType widget = (orient == GTK_ORIENTATION_HORIZONTAL) ? + MOZ_GTK_SCALE_HORIZONTAL : + MOZ_GTK_SCALE_VERTICAL; + gint thumb_length, thumb_height, trough_border; moz_gtk_get_scalethumb_metrics(orient, &thumb_length, &thumb_height); @@ -2512,12 +2520,10 @@ moz_gtk_get_scale_metrics(GtkOrientation orient, gint* scale_width, } ReleaseStyleContext(style); } else { - GtkStyleContext* style = ClaimStyleContext(widget); - gtk_style_context_get(style, gtk_style_context_get_state(style), - "min-width", scale_width, - "min-height", scale_height, - nullptr); - ReleaseStyleContext(style); + WidgetNodeType widget = (orient == GTK_ORIENTATION_HORIZONTAL) ? + MOZ_GTK_SCALE_TROUGH_HORIZONTAL : + MOZ_GTK_SCALE_TROUGH_VERTICAL; + moz_gtk_get_widget_min_size(widget, scale_width, scale_height); } } @@ -2540,10 +2546,27 @@ moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* MOZ_GTK_SCALE_THUMB_HORIZONTAL: MOZ_GTK_SCALE_THUMB_VERTICAL; GtkStyleContext* style = ClaimStyleContext(widget); - gtk_style_context_get(style, gtk_style_context_get_state(style), - "min-width", thumb_length, - "min-height", thumb_height, + gint min_width, min_height; + GtkStateFlags state = gtk_style_context_get_state(style); + gtk_style_context_get(style, state, + "min-width", &min_width, + "min-height", &min_height, nullptr); + GtkBorder margin; + gtk_style_context_get_margin(style, state, &margin); + gint margin_width = margin.left + margin.right; + gint margin_height = margin.top + margin.bottom; + + // Negative margin of slider element also determines its minimal size + // so use bigger of those two values. + if (min_width < -margin_width) + min_width = -margin_width; + if (min_height < -margin_height) + min_height = -margin_height; + + *thumb_length = min_width; + *thumb_height = min_height; + ReleaseStyleContext(style); } @@ -2786,10 +2809,8 @@ moz_gtk_widget_paint(WidgetNodeType widget, cairo_t *cr, break; case MOZ_GTK_CHECKMENUITEM: case MOZ_GTK_RADIOMENUITEM: - return moz_gtk_check_menu_item_paint(cr, rect, state, - (gboolean) flags, - (widget == MOZ_GTK_RADIOMENUITEM), - direction); + return moz_gtk_check_menu_item_paint(widget, cr, rect, state, + (gboolean) flags, direction); break; case MOZ_GTK_SPLITTER_HORIZONTAL: return moz_gtk_vpaned_paint(cr, rect, state); diff --git a/widget/gtk/gtkdrawing.h b/widget/gtk/gtkdrawing.h index 9bbfdefe9..7db5db043 100644 --- a/widget/gtk/gtkdrawing.h +++ b/widget/gtk/gtkdrawing.h @@ -145,8 +145,11 @@ typedef enum { MOZ_GTK_ENTRY, /* Paints a GtkExpander. */ MOZ_GTK_EXPANDER, - /* Paints a GtkTextView. */ + /* Paints a GtkTextView or gets the style context corresponding to the + root node of a GtkTextView. */ MOZ_GTK_TEXT_VIEW, + /* The "text" window or node of a GtkTextView */ + MOZ_GTK_TEXT_VIEW_TEXT, /* Paints a GtkOptionMenu. */ MOZ_GTK_DROPDOWN, /* Paints a dropdown arrow (a GtkButton containing a down GtkArrow). */ @@ -160,11 +163,15 @@ typedef enum { MOZ_GTK_TOOLBAR_SEPARATOR, /* Paints a GtkToolTip */ MOZ_GTK_TOOLTIP, + /* Paints a GtkBox from GtkToolTip */ + MOZ_GTK_TOOLTIP_BOX, + /* Paints a GtkLabel of GtkToolTip */ + MOZ_GTK_TOOLTIP_BOX_LABEL, /* Paints a GtkFrame (e.g. a status bar panel). */ MOZ_GTK_FRAME, /* Paints the border of a GtkFrame */ MOZ_GTK_FRAME_BORDER, - /* Paints a resize grip for a GtkWindow */ + /* Paints a resize grip for a GtkTextView */ MOZ_GTK_RESIZER, /* Paints a GtkProgressBar. */ MOZ_GTK_PROGRESSBAR, @@ -211,10 +218,13 @@ typedef enum { /* Paints items of popup menus. */ MOZ_GTK_MENUITEM, MOZ_GTK_IMAGEMENUITEM, - MOZ_GTK_CHECKMENUITEM_CONTAINER, - MOZ_GTK_RADIOMENUITEM_CONTAINER, + /* Paints a menuitem with check indicator, or the gets the style context for + a menuitem that contains a checkbox. */ MOZ_GTK_CHECKMENUITEM, + /* Gets the style context for a checkbox in a check menuitem. */ + MOZ_GTK_CHECKMENUITEM_INDICATOR, MOZ_GTK_RADIOMENUITEM, + MOZ_GTK_RADIOMENUITEM_INDICATOR, MOZ_GTK_MENUSEPARATOR, /* GtkVPaned base class */ MOZ_GTK_SPLITTER_HORIZONTAL, diff --git a/widget/gtk/nsLookAndFeel.cpp b/widget/gtk/nsLookAndFeel.cpp index 53430dfbb..d2b82e495 100644 --- a/widget/gtk/nsLookAndFeel.cpp +++ b/widget/gtk/nsLookAndFeel.cpp @@ -47,9 +47,6 @@ nsLookAndFeel::nsLookAndFeel() : nsXPLookAndFeel(), #if (MOZ_WIDGET_GTK == 2) mStyle(nullptr), -#else - mBackgroundStyle(nullptr), - mButtonStyle(nullptr), #endif mDefaultFontCached(false), mButtonFontCached(false), mFieldFontCached(false), mMenuFontCached(false) @@ -61,13 +58,27 @@ 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 +// Modifies color |*aDest| as if a pattern of color |aSource| was painted with +// CAIRO_OPERATOR_OVER to a surface with color |*aDest|. +static void +ApplyColorOver(const GdkRGBA& aSource, GdkRGBA* aDest) { + gdouble sourceCoef = aSource.alpha; + gdouble destCoef = aDest->alpha * (1.0 - sourceCoef); + gdouble resultAlpha = sourceCoef + destCoef; + if (resultAlpha != 0.0) { // don't divide by zero + destCoef /= resultAlpha; + sourceCoef /= resultAlpha; + aDest->red = sourceCoef * aSource.red + destCoef * aDest->red; + aDest->green = sourceCoef * aSource.green + destCoef * aDest->green; + aDest->blue = sourceCoef * aSource.blue + destCoef * aDest->blue; + aDest->alpha = resultAlpha; + } +} + static void GetLightAndDarkness(const GdkRGBA& aColor, double* aLightness, double* aDarkness) @@ -377,30 +388,39 @@ nsLookAndFeel::NativeGetColor(ColorID aID, nscolor& aColor) break; #else // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors - case eColorID_activeborder: + case eColorID_activeborder: { // active window border - gtk_style_context_get_border_color(mBackgroundStyle, + GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_WINDOW); + gtk_style_context_get_border_color(style, GTK_STATE_FLAG_NORMAL, &gdk_color); aColor = GDK_RGBA_TO_NS_RGBA(gdk_color); + ReleaseStyleContext(style); break; - case eColorID_inactiveborder: + } + case eColorID_inactiveborder: { // inactive window border - gtk_style_context_get_border_color(mBackgroundStyle, - GTK_STATE_FLAG_INSENSITIVE, + GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_WINDOW); + gtk_style_context_get_border_color(style, + GTK_STATE_FLAG_INSENSITIVE, &gdk_color); aColor = GDK_RGBA_TO_NS_RGBA(gdk_color); + ReleaseStyleContext(style); break; + } case eColorID_graytext: // disabled text in windows, menus, etc. case eColorID_inactivecaptiontext: // text in inactive window caption aColor = sMenuTextInactive; break; - case eColorID_inactivecaption: + case eColorID_inactivecaption: { // inactive window caption - gtk_style_context_get_background_color(mBackgroundStyle, + GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_WINDOW); + gtk_style_context_get_background_color(style, GTK_STATE_FLAG_INSENSITIVE, &gdk_color); aColor = GDK_RGBA_TO_NS_RGBA(gdk_color); + ReleaseStyleContext(style); break; + } #endif case eColorID_infobackground: // tooltip background color @@ -521,18 +541,24 @@ nsLookAndFeel::NativeGetColor(ColorID aID, nscolor& aColor) case eColorID__moz_fieldtext: aColor = sMozFieldText; break; - case eColorID__moz_buttondefault: - // default button border color - gtk_style_context_get_border_color(mButtonStyle, + case eColorID__moz_buttondefault: { + // default button border color + GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_BUTTON); + gtk_style_context_get_border_color(style, GTK_STATE_FLAG_NORMAL, &gdk_color); aColor = GDK_RGBA_TO_NS_RGBA(gdk_color); + ReleaseStyleContext(style); break; - case eColorID__moz_buttonhoverface: - gtk_style_context_get_background_color(mButtonStyle, + } + case eColorID__moz_buttonhoverface: { + GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_BUTTON); + gtk_style_context_get_background_color(style, GTK_STATE_FLAG_PRELIGHT, &gdk_color); aColor = GDK_RGBA_TO_NS_RGBA(gdk_color); + ReleaseStyleContext(style); break; + } case eColorID__moz_buttonhovertext: aColor = sButtonHoverText; break; @@ -1029,16 +1055,6 @@ nsLookAndFeel::GetFontImpl(FontID aID, nsString& aFontName, 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() { @@ -1129,78 +1145,55 @@ nsLookAndFeel::Init() 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); + style = ClaimStyleContext(MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL); gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color); sMozScrollbar = GDK_RGBA_TO_NS_RGBA(color); - g_object_unref(style); + ReleaseStyleContext(style); // Window colors - style = create_context(path); - gtk_style_context_save(style); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND); + style = ClaimStyleContext(MOZ_GTK_WINDOW); 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); + ReleaseStyleContext(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); + style = ClaimStyleContext(MOZ_GTK_TOOLTIP_BOX_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); + sInfoText = GDK_RGBA_TO_NS_RGBA(color); + ReleaseStyleContext(style); - style = gtk_widget_get_style_context(menu); + style = ClaimStyleContext(MOZ_GTK_MENUITEM); + { + GtkStyleContext* accelStyle = + CreateStyleForWidget(gtk_accel_label_new("M"), style); + gtk_style_context_get_color(accelStyle, GTK_STATE_FLAG_NORMAL, &color); + sMenuText = GDK_RGBA_TO_NS_RGBA(color); + gtk_style_context_get_color(accelStyle, GTK_STATE_FLAG_INSENSITIVE, &color); + sMenuTextInactive = GDK_RGBA_TO_NS_RGBA(color); + g_object_unref(accelStyle); + } + ReleaseStyleContext(style); + + style = ClaimStyleContext(MOZ_GTK_MENUPOPUP); gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color); sMenuBackground = GDK_RGBA_TO_NS_RGBA(color); + ReleaseStyleContext(style); - style = gtk_widget_get_style_context(menuitem); + style = ClaimStyleContext(MOZ_GTK_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); + ReleaseStyleContext(style); #endif // button styles @@ -1211,9 +1204,6 @@ nsLookAndFeel::Init() 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(); @@ -1227,7 +1217,9 @@ nsLookAndFeel::Init() gtk_container_add(GTK_CONTAINER(parent), button); gtk_container_add(GTK_CONTAINER(parent), treeView); gtk_container_add(GTK_CONTAINER(parent), linkButton); +#if (MOZ_WIDGET_GTK == 2) gtk_container_add(GTK_CONTAINER(parent), combobox); +#endif gtk_container_add(GTK_CONTAINER(parent), menuBar); gtk_menu_shell_append(GTK_MENU_SHELL(menuBar), menuBarItem); gtk_container_add(GTK_CONTAINER(window), parent); @@ -1310,11 +1302,19 @@ nsLookAndFeel::Init() } #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); + GdkRGBA bgColor; + // If the text window background is translucent, then the background of + // the textview root node is visible. + style = ClaimStyleContext(MOZ_GTK_TEXT_VIEW); + gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, + &bgColor); + ReleaseStyleContext(style); + + style = ClaimStyleContext(MOZ_GTK_TEXT_VIEW_TEXT); + gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, + &color); + ApplyColorOver(color, &bgColor); + sMozFieldBackground = GDK_RGBA_TO_NS_RGBA(bgColor); gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color); sMozFieldText = GDK_RGBA_TO_NS_RGBA(color); @@ -1327,26 +1327,34 @@ nsLookAndFeel::Init() static_cast<GtkStateFlags>(GTK_STATE_FLAG_FOCUSED|GTK_STATE_FLAG_SELECTED), &color); sTextSelectedText = GDK_RGBA_TO_NS_RGBA(color); - gtk_style_context_restore(style); + ReleaseStyleContext(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); + // Button text color + style = ClaimStyleContext(MOZ_GTK_BUTTON); + { + GtkStyleContext* labelStyle = + CreateStyleForWidget(gtk_label_new("M"), style); + gtk_style_context_get_color(labelStyle, GTK_STATE_FLAG_NORMAL, &color); + sButtonText = GDK_RGBA_TO_NS_RGBA(color); + gtk_style_context_get_color(labelStyle, GTK_STATE_FLAG_PRELIGHT, &color); + sButtonHoverText = GDK_RGBA_TO_NS_RGBA(color); + g_object_unref(labelStyle); + } + ReleaseStyleContext(style); // Combobox text color - style = gtk_widget_get_style_context(comboboxLabel); + style = ClaimStyleContext(MOZ_GTK_COMBOBOX_ENTRY_TEXTAREA); gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &color); sComboBoxText = GDK_RGBA_TO_NS_RGBA(color); + ReleaseStyleContext(style); // Menubar text and hover text colors - style = gtk_widget_get_style_context(menuBarItem); + style = ClaimStyleContext(MOZ_GTK_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); + ReleaseStyleContext(style); // GTK's guide to fancy odd row background colors: // 1) Check if a theme explicitly defines an odd row color @@ -1354,7 +1362,7 @@ nsLookAndFeel::Init() // 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); + style = ClaimStyleContext(MOZ_GTK_TREEVIEW); // Get odd row background color gtk_style_context_save(style); @@ -1362,8 +1370,7 @@ nsLookAndFeel::Init() 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); + ReleaseStyleContext(style); // 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 @@ -1448,12 +1455,6 @@ nsLookAndFeel::RefreshImpl() #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(); diff --git a/widget/gtk/nsLookAndFeel.h b/widget/gtk/nsLookAndFeel.h index 9058250b9..726859b41 100644 --- a/widget/gtk/nsLookAndFeel.h +++ b/widget/gtk/nsLookAndFeel.h @@ -33,9 +33,6 @@ public: protected: #if (MOZ_WIDGET_GTK == 2) struct _GtkStyle *mStyle; -#else - struct _GtkStyleContext *mBackgroundStyle; - struct _GtkStyleContext *mButtonStyle; #endif // Cached fonts diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index d97b35002..e4e69c1b4 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -6627,6 +6627,22 @@ nsWindow::GetDragInfo(WidgetMouseEvent* aMouseEvent, return false; } + if (mIsX11Display) { + // Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=789054 + // To avoid crashes disable double-click on WM without _NET_WM_MOVERESIZE. + // See _should_perform_ewmh_drag() at gdkwindow-x11.c + GdkScreen* screen = gdk_window_get_screen(gdk_window); + GdkAtom atom = gdk_atom_intern("_NET_WM_MOVERESIZE", FALSE); + if (!gdk_x11_screen_supports_net_wm_hint(screen, atom)) { + static unsigned int lastTimeStamp = 0; + if (lastTimeStamp != aMouseEvent->mTime) { + lastTimeStamp = aMouseEvent->mTime; + } else { + return false; + } + } + } + // FIXME: It would be nice to have the widget position at the time // of the event, but it's relatively unlikely that the widget has // moved since the mousedown. (On the other hand, it's quite likely |