Submitted By: Ken Moffat Date: 2016-08-03 Initial Package Version:48.0 Upstream Status: Applied Origin: Fedora Description: Without this, on versions of gtk+-3 > 3.18 the sliders for browser scrollbars do not appear. diff -up firefox-48.0/widget/gtk/gtk3drawing.cpp.gtk3-20 firefox-48.0/widget/gtk/gtk3drawing.cpp --- firefox-48.0/widget/gtk/gtk3drawing.cpp.gtk3-20 2016-07-25 22:22:07.000000000 +0200 +++ firefox-48.0/widget/gtk/gtk3drawing.cpp 2016-07-29 09:15:11.822285857 +0200 @@ -18,15 +18,9 @@ #include -static GtkWidget* gProtoWindow; static GtkWidget* gProtoLayout; -static GtkWidget* gButtonWidget; -static GtkWidget* gToggleButtonWidget; -static GtkWidget* gButtonArrowWidget; -static GtkWidget* gSpinWidget; static GtkWidget* gHScaleWidget; static GtkWidget* gVScaleWidget; -static GtkWidget* gEntryWidget; static GtkWidget* gComboBoxWidget; static GtkWidget* gComboBoxButtonWidget; static GtkWidget* gComboBoxArrowWidget; @@ -35,30 +29,15 @@ static GtkWidget* gComboBoxEntryWidget; static GtkWidget* gComboBoxEntryTextareaWidget; static GtkWidget* gComboBoxEntryButtonWidget; static GtkWidget* gComboBoxEntryArrowWidget; -static GtkWidget* gHandleBoxWidget; -static GtkWidget* gToolbarWidget; -static GtkWidget* gFrameWidget; -static GtkWidget* gProgressWidget; static GtkWidget* gTabWidget; -static GtkWidget* gTextViewWidget; -static GtkWidget* gTooltipWidget; -static GtkWidget* gMenuBarWidget; -static GtkWidget* gMenuBarItemWidget; -static GtkWidget* gMenuPopupWidget; -static GtkWidget* gMenuItemWidget; static GtkWidget* gImageMenuItemWidget; static GtkWidget* gCheckMenuItemWidget; static GtkWidget* gTreeViewWidget; static GtkTreeViewColumn* gMiddleTreeViewColumn; static GtkWidget* gTreeHeaderCellWidget; static GtkWidget* gTreeHeaderSortArrowWidget; -static GtkWidget* gExpanderWidget; -static GtkWidget* gToolbarSeparatorWidget; -static GtkWidget* gMenuSeparatorWidget; static GtkWidget* gHPanedWidget; static GtkWidget* gVPanedWidget; -static GtkWidget* gScrolledWindowWidget; -static GtkWidget* gInfoBar; static style_prop_t style_prop_func; static gboolean have_arrow_scaling; @@ -94,15 +73,6 @@ GetStateFlagsFromGtkWidgetState(GtkWidge return stateFlags; } -/* Because we have such an unconventional way of drawing widgets, signal to the GTK theme engine - that they are drawing for Mozilla instead of a conventional GTK app so they can do any specific - things they may want to do. */ -static void -moz_gtk_set_widget_name(GtkWidget* widget) -{ - gtk_widget_set_name(widget, "MozillaGtkWidget"); -} - gint moz_gtk_enable_style_props(style_prop_t styleGetProp) { @@ -111,15 +81,6 @@ moz_gtk_enable_style_props(style_prop_t } static gint -ensure_window_widget() -{ - if (!gProtoWindow) { - gProtoWindow = GetWidget(MOZ_GTK_WINDOW); - } - return MOZ_GTK_SUCCESS; -} - -static gint setup_widget_prototype(GtkWidget* widget) { if (!gProtoLayout) { @@ -130,16 +91,6 @@ setup_widget_prototype(GtkWidget* widget } static gint -ensure_button_widget() -{ - if (!gButtonWidget) { - gButtonWidget = gtk_button_new_with_label("M"); - setup_widget_prototype(gButtonWidget); - } - return MOZ_GTK_SUCCESS; -} - -static gint ensure_hpaned_widget() { if (!gHPanedWidget) { @@ -160,40 +111,6 @@ ensure_vpaned_widget() } static gint -ensure_toggle_button_widget() -{ - if (!gToggleButtonWidget) { - gToggleButtonWidget = gtk_toggle_button_new(); - setup_widget_prototype(gToggleButtonWidget); - } - return MOZ_GTK_SUCCESS; -} - -static gint -ensure_button_arrow_widget() -{ - if (!gButtonArrowWidget) { - ensure_toggle_button_widget(); - - gButtonArrowWidget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT); - gtk_container_add(GTK_CONTAINER(gToggleButtonWidget), gButtonArrowWidget); - gtk_widget_realize(gButtonArrowWidget); - gtk_widget_show(gButtonArrowWidget); - } - return MOZ_GTK_SUCCESS; -} - -static gint -ensure_spin_widget() -{ - if (!gSpinWidget) { - gSpinWidget = gtk_spin_button_new(NULL, 1, 0); - setup_widget_prototype(gSpinWidget); - } - return MOZ_GTK_SUCCESS; -} - -static gint ensure_scale_widget() { if (!gHScaleWidget) { @@ -207,16 +124,6 @@ ensure_scale_widget() return MOZ_GTK_SUCCESS; } -static gint -ensure_entry_widget() -{ - if (!gEntryWidget) { - gEntryWidget = gtk_entry_new(); - setup_widget_prototype(gEntryWidget); - } - return MOZ_GTK_SUCCESS; -} - /* We need to have pointers to the inner widgets (button, separator, arrow) * of the ComboBox to get the correct rendering from theme engines which * special cases their look. Since the inner layout can change, we ask GTK @@ -225,7 +132,7 @@ ensure_entry_widget() * g_object_add_weak_pointer(). * Note that if we don't find the inner widgets (which shouldn't happen), we * fallback to use generic "non-inner" widgets, and they don't need that kind - * of weak pointer since they are explicit children of gProtoWindow and as + * of weak pointer since they are explicit children of gProtoLayout and as * such GTK holds a strong reference to them. */ static void moz_gtk_get_combo_box_inner_button(GtkWidget *widget, gpointer client_data) @@ -297,16 +204,14 @@ ensure_combo_box_widgets() /* Shouldn't be reached with current internal gtk implementation; we * use a generic toggle button as last resort fallback to avoid * crashing. */ - ensure_toggle_button_widget(); - gComboBoxButtonWidget = gToggleButtonWidget; + gComboBoxButtonWidget = GetWidget(MOZ_GTK_TOGGLE_BUTTON); } if (!gComboBoxArrowWidget) { /* Shouldn't be reached with current internal gtk implementation; * we gButtonArrowWidget as last resort fallback to avoid * crashing. */ - ensure_button_arrow_widget(); - gComboBoxArrowWidget = gButtonArrowWidget; + gComboBoxArrowWidget = GetWidget(MOZ_GTK_BUTTON_ARROW); } /* We don't test the validity of gComboBoxSeparatorWidget since there @@ -316,15 +221,6 @@ ensure_combo_box_widgets() return MOZ_GTK_SUCCESS; } -static void -ensure_info_bar() -{ - if (!gInfoBar) { - gInfoBar = gtk_info_bar_new(); - setup_widget_prototype(gInfoBar); - } -} - /* We need to have pointers to the inner widgets (entry, button, arrow) of * the ComboBoxEntry to get the correct rendering from theme engines which * special cases their look. Since the inner layout can change, we ask GTK @@ -333,7 +229,7 @@ ensure_info_bar() * g_object_add_weak_pointer(). * Note that if we don't find the inner widgets (which shouldn't happen), we * fallback to use generic "non-inner" widgets, and they don't need that kind - * of weak pointer since they are explicit children of gProtoWindow and as + * of weak pointer since they are explicit children of gProtoLayout and as * such GTK holds a strong reference to them. */ static void moz_gtk_get_combo_box_entry_inner_widgets(GtkWidget *widget, @@ -385,8 +281,7 @@ ensure_combo_box_entry_widgets() NULL); if (!gComboBoxEntryTextareaWidget) { - ensure_entry_widget(); - gComboBoxEntryTextareaWidget = gEntryWidget; + gComboBoxEntryTextareaWidget = GetWidget(MOZ_GTK_ENTRY); } if (gComboBoxEntryButtonWidget) { @@ -412,68 +307,19 @@ ensure_combo_box_entry_widgets() /* Shouldn't be reached with current internal gtk implementation; * we use a generic toggle button as last resort fallback to avoid * crashing. */ - ensure_toggle_button_widget(); - gComboBoxEntryButtonWidget = gToggleButtonWidget; + gComboBoxEntryButtonWidget = GetWidget(MOZ_GTK_TOGGLE_BUTTON); } if (!gComboBoxEntryArrowWidget) { /* Shouldn't be reached with current internal gtk implementation; * we gButtonArrowWidget as last resort fallback to avoid * crashing. */ - ensure_button_arrow_widget(); - gComboBoxEntryArrowWidget = gButtonArrowWidget; + gComboBoxEntryArrowWidget = GetWidget(MOZ_GTK_BUTTON_ARROW); } return MOZ_GTK_SUCCESS; } - -static gint -ensure_handlebox_widget() -{ - if (!gHandleBoxWidget) { - gHandleBoxWidget = gtk_handle_box_new(); - setup_widget_prototype(gHandleBoxWidget); - } - return MOZ_GTK_SUCCESS; -} - -static gint -ensure_toolbar_widget() -{ - if (!gToolbarWidget) { - ensure_handlebox_widget(); - gToolbarWidget = gtk_toolbar_new(); - gtk_container_add(GTK_CONTAINER(gHandleBoxWidget), gToolbarWidget); - gtk_widget_realize(gToolbarWidget); - } - return MOZ_GTK_SUCCESS; -} - -static gint -ensure_toolbar_separator_widget() -{ - if (!gToolbarSeparatorWidget) { - ensure_toolbar_widget(); - gToolbarSeparatorWidget = GTK_WIDGET(gtk_separator_tool_item_new()); - setup_widget_prototype(gToolbarSeparatorWidget); - } - return MOZ_GTK_SUCCESS; -} - -static gint -ensure_tooltip_widget() -{ - if (!gTooltipWidget) { - gTooltipWidget = gtk_window_new(GTK_WINDOW_POPUP); - GtkStyleContext* style = gtk_widget_get_style_context(gTooltipWidget); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOOLTIP); - gtk_widget_realize(gTooltipWidget); - moz_gtk_set_widget_name(gTooltipWidget); - } - return MOZ_GTK_SUCCESS; -} - static gint ensure_tab_widget() { @@ -485,81 +331,11 @@ ensure_tab_widget() } static gint -ensure_progress_widget() -{ - if (!gProgressWidget) { - gProgressWidget = gtk_progress_bar_new(); - setup_widget_prototype(gProgressWidget); - } - return MOZ_GTK_SUCCESS; -} - -static gint -ensure_frame_widget() -{ - if (!gFrameWidget) { - gFrameWidget = gtk_frame_new(NULL); - setup_widget_prototype(gFrameWidget); - } - return MOZ_GTK_SUCCESS; -} - -static gint -ensure_menu_bar_widget() -{ - if (!gMenuBarWidget) { - gMenuBarWidget = gtk_menu_bar_new(); - setup_widget_prototype(gMenuBarWidget); - } - return MOZ_GTK_SUCCESS; -} - -static gint -ensure_menu_bar_item_widget() -{ - if (!gMenuBarItemWidget) { - ensure_menu_bar_widget(); - gMenuBarItemWidget = gtk_menu_item_new(); - gtk_menu_shell_append(GTK_MENU_SHELL(gMenuBarWidget), - gMenuBarItemWidget); - gtk_widget_realize(gMenuBarItemWidget); - } - return MOZ_GTK_SUCCESS; -} - -static gint -ensure_menu_popup_widget() -{ - if (!gMenuPopupWidget) { - ensure_window_widget(); - gMenuPopupWidget = gtk_menu_new(); - gtk_menu_attach_to_widget(GTK_MENU(gMenuPopupWidget), gProtoWindow, - NULL); - gtk_widget_realize(gMenuPopupWidget); - } - return MOZ_GTK_SUCCESS; -} - -static gint -ensure_menu_item_widget() -{ - if (!gMenuItemWidget) { - ensure_menu_popup_widget(); - gMenuItemWidget = gtk_menu_item_new_with_label("M"); - gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), - gMenuItemWidget); - gtk_widget_realize(gMenuItemWidget); - } - return MOZ_GTK_SUCCESS; -} - -static gint ensure_image_menu_item_widget() { if (!gImageMenuItemWidget) { - ensure_menu_popup_widget(); gImageMenuItemWidget = gtk_image_menu_item_new(); - gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), + gtk_menu_shell_append(GTK_MENU_SHELL(GetWidget(MOZ_GTK_MENUPOPUP)), gImageMenuItemWidget); gtk_widget_realize(gImageMenuItemWidget); } @@ -567,25 +343,11 @@ ensure_image_menu_item_widget() } static gint -ensure_menu_separator_widget() -{ - if (!gMenuSeparatorWidget) { - ensure_menu_popup_widget(); - gMenuSeparatorWidget = gtk_separator_menu_item_new(); - gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), - gMenuSeparatorWidget); - gtk_widget_realize(gMenuSeparatorWidget); - } - return MOZ_GTK_SUCCESS; -} - -static gint ensure_check_menu_item_widget() { if (!gCheckMenuItemWidget) { - ensure_menu_popup_widget(); - gCheckMenuItemWidget = gtk_check_menu_item_new_with_label("M"); - gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), + gCheckMenuItemWidget = gtk_check_menu_item_new(); + gtk_menu_shell_append(GTK_MENU_SHELL(GetWidget(MOZ_GTK_MENUPOPUP)), gCheckMenuItemWidget); gtk_widget_realize(gCheckMenuItemWidget); } @@ -646,37 +408,6 @@ ensure_tree_header_cell_widget() return MOZ_GTK_SUCCESS; } -static gint -ensure_expander_widget() -{ - if (!gExpanderWidget) { - gExpanderWidget = gtk_expander_new("M"); - setup_widget_prototype(gExpanderWidget); - } - return MOZ_GTK_SUCCESS; -} - -static gint -ensure_scrolled_window_widget() -{ - if (!gScrolledWindowWidget) { - gScrolledWindowWidget = gtk_scrolled_window_new(NULL, NULL); - setup_widget_prototype(gScrolledWindowWidget); - } - return MOZ_GTK_SUCCESS; -} - -static void -ensure_text_view_widget() -{ - if (gTextViewWidget) - return; - - gTextViewWidget = gtk_text_view_new(); - ensure_scrolled_window_widget(); - gtk_container_add(GTK_CONTAINER(gScrolledWindowWidget), gTextViewWidget); -} - gint moz_gtk_init() { @@ -729,26 +460,21 @@ moz_gtk_get_focus_outline_size(gint* foc { GtkBorder border; GtkBorder padding; - GtkStyleContext *style; - - ensure_entry_widget(); - style = gtk_widget_get_style_context(gEntryWidget); - + GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_ENTRY); gtk_style_context_get_border(style, GTK_STATE_FLAG_NORMAL, &border); gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding); *focus_h_width = border.left + padding.left; *focus_v_width = border.top + padding.top; + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } gint moz_gtk_menuitem_get_horizontal_padding(gint* horizontal_padding) { - ensure_menu_item_widget(); - - gtk_style_context_get_style(gtk_widget_get_style_context(gMenuItemWidget), - "horizontal-padding", horizontal_padding, - NULL); + gtk_widget_style_get(GetWidget(MOZ_GTK_MENUITEM), + "horizontal-padding", horizontal_padding, + nullptr); return MOZ_GTK_SUCCESS; } @@ -771,10 +497,11 @@ moz_gtk_button_get_default_overflow(gint { GtkBorder* default_outside_border; - ensure_button_widget(); - gtk_style_context_get_style(gtk_widget_get_style_context(gButtonWidget), + GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_BUTTON); + gtk_style_context_get_style(style, "default-outside-border", &default_outside_border, NULL); + ReleaseStyleContext(style); if (default_outside_border) { *border_top = default_outside_border->top; @@ -794,10 +521,11 @@ moz_gtk_button_get_default_border(gint* { GtkBorder* default_border; - ensure_button_widget(); - gtk_style_context_get_style(gtk_widget_get_style_context(gButtonWidget), + GtkStyleContext *style = ClaimStyleContext(MOZ_GTK_BUTTON); + gtk_style_context_get_style(style, "default-border", &default_border, NULL); + ReleaseStyleContext(style); if (default_border) { *border_top = default_border->top; @@ -831,17 +559,15 @@ static gint moz_gtk_window_paint(cairo_t *cr, GdkRectangle* rect, GtkTextDirection direction) { - GtkStyleContext* style; - - ensure_window_widget(); - gtk_widget_set_direction(gProtoWindow, direction); + GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_WINDOW, direction); - style = gtk_widget_get_style_context(gProtoWindow); gtk_style_context_save(style); gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND); gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height); gtk_style_context_restore(style); + ReleaseStyleContext(style); + return MOZ_GTK_SUCCESS; } @@ -1118,6 +844,36 @@ moz_gtk_scrollbar_button_paint(cairo_t * return MOZ_GTK_SUCCESS; } +static void +moz_gtk_update_scrollbar_style(GtkStyleContext* style, + WidgetNodeType widget, + GtkTextDirection direction) +{ + if (widget == MOZ_GTK_SCROLLBAR_HORIZONTAL) { + gtk_style_context_add_class(style, GTK_STYLE_CLASS_BOTTOM); + } else { + if (direction == GTK_TEXT_DIR_LTR) { + gtk_style_context_add_class(style, GTK_STYLE_CLASS_RIGHT); + gtk_style_context_remove_class(style, GTK_STYLE_CLASS_LEFT); + } else { + gtk_style_context_add_class(style, GTK_STYLE_CLASS_LEFT); + gtk_style_context_remove_class(style, GTK_STYLE_CLASS_RIGHT); + } + } +} + +static void +moz_gtk_draw_styled_frame(GtkStyleContext* style, cairo_t *cr, + GdkRectangle* rect, bool drawFocus) +{ + 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); + if (drawFocus) { + gtk_render_focus(style, cr, + rect->x, rect->y, rect->width, rect->height); + } +} + static gint moz_gtk_scrollbar_trough_paint(WidgetNodeType widget, cairo_t *cr, GdkRectangle* rect, @@ -1126,26 +882,34 @@ moz_gtk_scrollbar_trough_paint(WidgetNod GtkTextDirection direction) { if (flags & MOZ_GTK_TRACK_OPAQUE) { - GtkStyleContext* style = - gtk_widget_get_style_context(GTK_WIDGET(gProtoWindow)); - gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height); + GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_WINDOW, direction); + gtk_render_background(style, cr, + rect->x, rect->y, rect->width, rect->height); + ReleaseStyleContext(style); } - GtkStyleContext* style = - ClaimStyleContext(widget == MOZ_GTK_SCROLLBAR_HORIZONTAL ? - MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL : - MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL, - direction); - // TODO - integate with ClaimStyleContext()? - gtk_style_context_set_direction(style, direction); + bool isHorizontal = (widget == MOZ_GTK_SCROLLBAR_HORIZONTAL); + GtkStyleContext* 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); + // Draw all child CSS Nodes for Gtk >= 3.20 + if (gtk_check_version(3, 20, 0) == nullptr) { + style = ClaimStyleContext(widget, direction); + moz_gtk_update_scrollbar_style(style, widget, direction); + moz_gtk_draw_styled_frame(style, cr, rect, state->focused); + ReleaseStyleContext(style); - if (state->focused) { - gtk_render_focus(style, cr, - rect->x, rect->y, rect->width, rect->height); + style = ClaimStyleContext(isHorizontal ? + MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL : + MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL, + direction); + moz_gtk_draw_styled_frame(style, cr, rect, state->focused); + ReleaseStyleContext(style); } + style = ClaimStyleContext(isHorizontal ? + MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL : + MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL, + direction); + moz_gtk_draw_styled_frame(style, cr, rect, state->focused); ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; @@ -1160,12 +924,7 @@ moz_gtk_scrollbar_thumb_paint(WidgetNode GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); GtkBorder margin; - GtkStyleContext* style = ClaimStyleContext(widget, direction); - - // TODO - integate those with ClaimStyleContext()? - gtk_style_context_set_state(style, state_flags); - gtk_style_context_set_direction(style, direction); - + GtkStyleContext* style = ClaimStyleContext(widget, direction, state_flags); gtk_style_context_get_margin (style, state_flags, &margin); gtk_render_slider(style, cr, @@ -1185,17 +944,10 @@ static gint moz_gtk_spin_paint(cairo_t *cr, GdkRectangle* rect, GtkTextDirection direction) { - GtkStyleContext* style; - - ensure_spin_widget(); - gtk_widget_set_direction(gSpinWidget, direction); - style = gtk_widget_get_style_context(gSpinWidget); - gtk_style_context_save(style); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_SPINBUTTON); + GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_SPINBUTTON, direction); 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); - gtk_style_context_restore(style); - + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } @@ -1204,21 +956,14 @@ moz_gtk_spin_updown_paint(cairo_t *cr, G gboolean isDown, GtkWidgetState* state, GtkTextDirection direction) { - GdkRectangle arrow_rect; - GtkStyleContext* style; - - ensure_spin_widget(); - style = gtk_widget_get_style_context(gSpinWidget); - gtk_style_context_save(style); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_SPINBUTTON); - gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state)); - gtk_widget_set_direction(gSpinWidget, direction); + GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_SPINBUTTON, direction, + GetStateFlagsFromGtkWidgetState(state)); 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); - /* hard code these values */ + GdkRectangle arrow_rect; arrow_rect.width = 6; arrow_rect.height = 6; arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2; @@ -1229,7 +974,8 @@ moz_gtk_spin_updown_paint(cairo_t *cr, G isDown ? ARROW_DOWN : ARROW_UP, arrow_rect.x, arrow_rect.y, arrow_rect.width); - gtk_style_context_restore(style); + + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } @@ -1295,8 +1041,8 @@ moz_gtk_scale_thumb_paint(cairo_t *cr, G gtk_widget_set_direction(widget, direction); style = gtk_widget_get_style_context(widget); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_SLIDER); gtk_style_context_save(style); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_SLIDER); gtk_style_context_set_state(style, state_flags); /* determine the thumb size, and position the thumb in the center in the opposite axis */ @@ -1321,20 +1067,12 @@ moz_gtk_gripper_paint(cairo_t *cr, GdkRe GtkWidgetState* state, GtkTextDirection direction) { - GtkStyleContext* style; - - ensure_handlebox_widget(); - gtk_widget_set_direction(gHandleBoxWidget, direction); - - style = gtk_widget_get_style_context(gHandleBoxWidget); - gtk_style_context_save(style); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_GRIP); - gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state)); - + GtkStyleContext* style = + ClaimStyleContext(MOZ_GTK_GRIPPER, direction, + GetStateFlagsFromGtkWidgetState(state)); 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); - gtk_style_context_restore(style); - + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } @@ -1435,6 +1173,38 @@ moz_gtk_entry_paint(cairo_t *cr, GdkRect return MOZ_GTK_SUCCESS; } +static gint +moz_gtk_text_view_paint(cairo_t *cr, GdkRectangle* rect, + GtkWidgetState* state, + GtkTextDirection direction) +{ + GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); + + 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); + + 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); + + ReleaseStyleContext(style); + + return MOZ_GTK_SUCCESS; +} + static gint moz_gtk_treeview_paint(cairo_t *cr, GdkRectangle* rect, GtkWidgetState* state, @@ -1447,18 +1217,13 @@ moz_gtk_treeview_paint(cairo_t *cr, GdkR GtkBorder border; ensure_tree_view_widget(); - ensure_scrolled_window_widget(); - gtk_widget_set_direction(gTreeViewWidget, direction); - gtk_widget_set_direction(gScrolledWindowWidget, direction); /* only handle disabled and normal states, otherwise the whole background * area will be painted differently with other states */ state_flags = state->disabled ? GTK_STATE_FLAG_INSENSITIVE : GTK_STATE_FLAG_NORMAL; - style = gtk_widget_get_style_context(gScrolledWindowWidget); - gtk_style_context_save(style); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_FRAME); + style = ClaimStyleContext(MOZ_GTK_SCROLLED_WINDOW, direction); gtk_style_context_get_border(style, state_flags, &border); xthickness = border.left; ythickness = border.top; @@ -1473,7 +1238,7 @@ moz_gtk_treeview_paint(cairo_t *cr, GdkR rect->height - 2 * ythickness); gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height); - gtk_style_context_restore(style); + ReleaseStyleContext(style); gtk_style_context_restore(style_tree); return MOZ_GTK_SUCCESS; } @@ -1648,20 +1413,9 @@ moz_gtk_arrow_paint(cairo_t *cr, GdkRect GtkWidgetState* state, GtkArrowType arrow_type, GtkTextDirection direction) { - GtkStyleContext* style; - GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); GdkRectangle arrow_rect; gdouble arrow_angle; - ensure_button_arrow_widget(); - style = gtk_widget_get_style_context(gButtonArrowWidget); - gtk_style_context_save(style); - gtk_style_context_set_state(style, state_flags); - gtk_widget_set_direction(gButtonArrowWidget, direction); - - calculate_arrow_rect(gButtonArrowWidget, rect, &arrow_rect, - direction); - if (direction == GTK_TEXT_DIR_RTL) { arrow_type = (arrow_type == GTK_ARROW_LEFT) ? GTK_ARROW_RIGHT : GTK_ARROW_LEFT; @@ -1680,10 +1434,17 @@ moz_gtk_arrow_paint(cairo_t *cr, GdkRect arrow_angle = ARROW_UP; break; } - if (arrow_type != GTK_ARROW_NONE) - gtk_render_arrow(style, cr, arrow_angle, - arrow_rect.x, arrow_rect.y, arrow_rect.width); - gtk_style_context_restore(style); + if (arrow_type == GTK_ARROW_NONE) + return MOZ_GTK_SUCCESS; + + calculate_arrow_rect(GetWidget(MOZ_GTK_BUTTON_ARROW), rect, &arrow_rect, + direction); + GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); + GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_BUTTON_ARROW, + direction, state_flags); + gtk_render_arrow(style, cr, arrow_angle, + arrow_rect.x, arrow_rect.y, arrow_rect.width); + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } @@ -1776,19 +1537,10 @@ static gint moz_gtk_toolbar_paint(cairo_t *cr, GdkRectangle* rect, GtkTextDirection direction) { - GtkStyleContext* style; - - ensure_toolbar_widget(); - gtk_widget_set_direction(gToolbarWidget, direction); - - style = gtk_widget_get_style_context(gToolbarWidget); - gtk_style_context_save(style); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOOLBAR); - + GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TOOLBAR, direction); 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); - gtk_style_context_restore(style); - + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } @@ -1798,7 +1550,6 @@ static gint moz_gtk_toolbar_separator_paint(cairo_t *cr, GdkRectangle* rect, GtkTextDirection direction) { - GtkStyleContext* style; gint separator_width; gint paint_width; gboolean wide_separators; @@ -1807,16 +1558,14 @@ moz_gtk_toolbar_separator_paint(cairo_t const double start_fraction = 0.2; const double end_fraction = 0.8; - ensure_toolbar_separator_widget(); - gtk_widget_set_direction(gToolbarSeparatorWidget, direction); - - style = gtk_widget_get_style_context(gToolbarSeparatorWidget); - - gtk_style_context_get_style(gtk_widget_get_style_context(gToolbarWidget), + GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TOOLBAR); + gtk_style_context_get_style(style, "wide-separators", &wide_separators, "separator-width", &separator_width, NULL); + ReleaseStyleContext(style); + style = ClaimStyleContext(MOZ_GTK_TOOLBAR_SEPARATOR, direction); if (wide_separators) { if (separator_width > rect->width) separator_width = rect->width; @@ -1840,7 +1589,7 @@ moz_gtk_toolbar_separator_paint(cairo_t rect->x + (rect->width - paint_width) / 2, rect->y + rect->height * end_fraction); } - + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } @@ -1848,14 +1597,10 @@ static gint moz_gtk_tooltip_paint(cairo_t *cr, GdkRectangle* rect, GtkTextDirection direction) { - GtkStyleContext* style; - - ensure_tooltip_widget(); - gtk_widget_set_direction(gTooltipWidget, direction); - - style = gtk_widget_get_style_context(gTooltipWidget); + GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TOOLTIP, direction); 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); return MOZ_GTK_SUCCESS; } @@ -1870,14 +1615,11 @@ moz_gtk_resizer_paint(cairo_t *cr, GdkRe // 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. - ensure_text_view_widget(); - gtk_widget_set_direction(gTextViewWidget, GTK_TEXT_DIR_LTR); - - style = gtk_widget_get_style_context(gTextViewWidget); - gtk_style_context_save(style); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_VIEW); + 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); - gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state)); // Workaround unico not respecting the text direction for resizers. // See bug 1174248. @@ -1891,7 +1633,7 @@ moz_gtk_resizer_paint(cairo_t *cr, GdkRe gtk_render_handle(style, cr, rect->x, rect->y, rect->width, rect->height); cairo_restore(cr); - gtk_style_context_restore(style); + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } @@ -1900,16 +1642,9 @@ static gint moz_gtk_frame_paint(cairo_t *cr, GdkRectangle* rect, GtkTextDirection direction) { - GtkStyleContext* style; - - ensure_frame_widget(); - gtk_widget_set_direction(gFrameWidget, direction); - style = gtk_widget_get_style_context(gFrameWidget); - gtk_style_context_save(style); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_FRAME); - + GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_FRAME, direction); gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height); - gtk_style_context_restore(style); + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } @@ -1917,18 +1652,11 @@ static gint moz_gtk_progressbar_paint(cairo_t *cr, GdkRectangle* rect, GtkTextDirection direction) { - GtkStyleContext* style; - - ensure_progress_widget(); - gtk_widget_set_direction(gProgressWidget, direction); - - style = gtk_widget_get_style_context(gProgressWidget); - gtk_style_context_save(style); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_TROUGH); - + GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_PROGRESS_TROUGH, + direction); 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); - gtk_style_context_restore(style); + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } @@ -1940,13 +1668,15 @@ moz_gtk_progress_chunk_paint(cairo_t *cr { GtkStyleContext* style; - ensure_progress_widget(); - gtk_widget_set_direction(gProgressWidget, direction); - - style = gtk_widget_get_style_context(gProgressWidget); - gtk_style_context_save(style); - gtk_style_context_remove_class(style, GTK_STYLE_CLASS_TROUGH); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_PROGRESSBAR); + 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); + } if (widget == MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE || widget == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE) { @@ -1990,7 +1720,7 @@ moz_gtk_progress_chunk_paint(cairo_t *cr } else { gtk_render_activity(style, cr, rect->x, rect->y, rect->width, rect->height); } - gtk_style_context_restore(style); + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } @@ -2324,10 +2054,10 @@ moz_gtk_menu_bar_paint(cairo_t *cr, GdkR { GtkStyleContext* style; - ensure_menu_bar_widget(); - gtk_widget_set_direction(gMenuBarWidget, direction); + GtkWidget* widget = GetWidget(MOZ_GTK_MENUBAR); + gtk_widget_set_direction(widget, direction); - style = gtk_widget_get_style_context(gMenuBarWidget); + style = gtk_widget_get_style_context(widget); gtk_style_context_save(style); gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR); gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height); @@ -2343,14 +2073,14 @@ moz_gtk_menu_popup_paint(cairo_t *cr, Gd { GtkStyleContext* style; - ensure_menu_popup_widget(); - gtk_widget_set_direction(gMenuPopupWidget, direction); + GtkWidget* widget = GetWidget(MOZ_GTK_MENUPOPUP); + gtk_widget_set_direction(widget, direction); // Draw a backing toplevel. This fixes themes that don't provide a menu // background, and depend on the GtkMenu's implementation window to provide it. moz_gtk_window_paint(cr, rect, direction); - style = gtk_widget_get_style_context(gMenuPopupWidget); + style = gtk_widget_get_style_context(widget); gtk_style_context_save(style); gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENU); @@ -2373,12 +2103,10 @@ moz_gtk_menu_separator_paint(cairo_t *cr gint x, y, w; GtkBorder padding; - ensure_menu_separator_widget(); - gtk_widget_set_direction(gMenuSeparatorWidget, direction); - - border_width = gtk_container_get_border_width(GTK_CONTAINER(gMenuSeparatorWidget)); - - style = gtk_widget_get_style_context(gMenuSeparatorWidget); + border_width = + gtk_container_get_border_width(GTK_CONTAINER( + GetWidget(MOZ_GTK_MENUSEPARATOR))); + style = ClaimStyleContext(MOZ_GTK_MENUSEPARATOR, direction); gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding); x = rect->x + border_width; @@ -2408,42 +2136,36 @@ moz_gtk_menu_separator_paint(cairo_t *cr } gtk_style_context_restore(style); + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } // See gtk_menu_item_draw() for reference. static gint -moz_gtk_menu_item_paint(cairo_t *cr, GdkRectangle* rect, - GtkWidgetState* state, - gint flags, GtkTextDirection direction) +moz_gtk_menu_item_paint(WidgetNodeType widget, cairo_t *cr, GdkRectangle* rect, + GtkWidgetState* state, GtkTextDirection direction) { - GtkStyleContext* style; - GtkWidget* item_widget; - guint border_width; gint x, y, w, h; if (state->inHover && !state->disabled) { - if (flags & MOZ_TOPLEVEL_MENU_ITEM) { - ensure_menu_bar_item_widget(); - item_widget = gMenuBarItemWidget; - } else { - ensure_menu_item_widget(); - item_widget = gMenuItemWidget; - } - style = gtk_widget_get_style_context(item_widget); - gtk_style_context_save(style); + guint border_width = + gtk_container_get_border_width(GTK_CONTAINER(GetWidget(widget))); + GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); + GtkStyleContext* style = + ClaimStyleContext(widget, direction, state_flags); - if (flags & MOZ_TOPLEVEL_MENU_ITEM) { - gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR); + 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_widget_set_direction(item_widget, direction); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUITEM); - gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state)); - - border_width = gtk_container_get_border_width(GTK_CONTAINER(item_widget)); - x = rect->x + border_width; y = rect->y + border_width; w = rect->width - border_width * 2; @@ -2451,7 +2173,11 @@ moz_gtk_menu_item_paint(cairo_t *cr, Gdk gtk_render_background(style, cr, x, y, w, h); gtk_render_frame(style, cr, x, y, w, h); - gtk_style_context_restore(style); + + if (pre_3_6) { + gtk_style_context_restore(style); + } + ReleaseStyleContext(style); } return MOZ_GTK_SUCCESS; @@ -2462,21 +2188,13 @@ moz_gtk_menu_arrow_paint(cairo_t *cr, Gd GtkWidgetState* state, GtkTextDirection direction) { - GtkStyleContext* style; GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); - - ensure_menu_item_widget(); - gtk_widget_set_direction(gMenuItemWidget, direction); - - style = gtk_widget_get_style_context(gMenuItemWidget); - gtk_style_context_save(style); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUITEM); - gtk_style_context_set_state(style, state_flags); + GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_MENUITEM, + direction, state_flags); gtk_render_arrow(style, cr, (direction == GTK_TEXT_DIR_LTR) ? ARROW_RIGHT : ARROW_LEFT, rect->x, rect->y, rect->width); - gtk_style_context_restore(style); - + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } @@ -2494,7 +2212,7 @@ moz_gtk_check_menu_item_paint(cairo_t *c gint indicator_size, horizontal_padding; gint x, y; - moz_gtk_menu_item_paint(cr, rect, state, FALSE, direction); + moz_gtk_menu_item_paint(MOZ_GTK_MENUITEM, cr, rect, state, direction); ensure_check_menu_item_widget(); gtk_widget_set_direction(gCheckMenuItemWidget, direction); @@ -2545,21 +2263,13 @@ static gint moz_gtk_info_bar_paint(cairo_t *cr, GdkRectangle* rect, GtkWidgetState* state) { - GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); - GtkStyleContext *style; - ensure_info_bar(); - - style = gtk_widget_get_style_context(gInfoBar); - gtk_style_context_save(style); - - gtk_style_context_set_state(style, state_flags); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_INFO); - + GtkStyleContext *style = + ClaimStyleContext(MOZ_GTK_INFO_BAR, GTK_TEXT_DIR_LTR, + GetStateFlagsFromGtkWidgetState(state)); 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); - - gtk_style_context_restore(style); + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } @@ -2605,18 +2315,18 @@ moz_gtk_get_widget_border(WidgetNodeType case MOZ_GTK_BUTTON: case MOZ_GTK_TOOLBAR_BUTTON: { - ensure_button_widget(); - style = gtk_widget_get_style_context(gButtonWidget); + style = ClaimStyleContext(MOZ_GTK_BUTTON); - *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gButtonWidget)); + *left = *top = *right = *bottom = + gtk_container_get_border_width(GTK_CONTAINER(GetWidget(MOZ_GTK_BUTTON))); if (widget == MOZ_GTK_TOOLBAR_BUTTON) { gtk_style_context_save(style); gtk_style_context_add_class(style, "image-button"); } - + moz_gtk_add_style_padding(style, left, top, right, bottom); - + if (widget == MOZ_GTK_TOOLBAR_BUTTON) gtk_style_context_restore(style); @@ -2624,12 +2334,13 @@ moz_gtk_get_widget_border(WidgetNodeType // -moz-focus-inner border (Bug 1228281). *left -= 1; *top -= 1; *right -= 1; *bottom -= 1; moz_gtk_add_style_border(style, left, top, right, bottom); + + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } case MOZ_GTK_ENTRY: { - ensure_entry_widget(); - style = gtk_widget_get_style_context(gEntryWidget); + style = ClaimStyleContext(MOZ_GTK_ENTRY); // XXX: Subtract 1 pixel from the padding to account for the default // padding in forms.css. See bug 1187385. @@ -2637,16 +2348,15 @@ moz_gtk_get_widget_border(WidgetNodeType moz_gtk_add_style_padding(style, left, top, right, bottom); moz_gtk_add_style_border(style, left, top, right, bottom); + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } + case MOZ_GTK_TEXT_VIEW: case MOZ_GTK_TREEVIEW: { - ensure_scrolled_window_widget(); - style = gtk_widget_get_style_context(gScrolledWindowWidget); - gtk_style_context_save(style); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_FRAME); + style = ClaimStyleContext(MOZ_GTK_SCROLLED_WINDOW); moz_gtk_add_style_border(style, left, top, right, bottom); - gtk_style_context_restore(style); + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } case MOZ_GTK_TREE_HEADER_CELL: @@ -2726,14 +2436,12 @@ moz_gtk_get_widget_border(WidgetNodeType w = gTabWidget; break; case MOZ_GTK_PROGRESSBAR: - ensure_progress_widget(); - w = gProgressWidget; + w = GetWidget(MOZ_GTK_PROGRESSBAR); break; case MOZ_GTK_SPINBUTTON_ENTRY: case MOZ_GTK_SPINBUTTON_UP: case MOZ_GTK_SPINBUTTON_DOWN: - ensure_spin_widget(); - w = gSpinWidget; + w = GetWidget(MOZ_GTK_SPINBUTTON); break; case MOZ_GTK_SCALE_HORIZONTAL: ensure_scale_widget(); @@ -2744,8 +2452,7 @@ moz_gtk_get_widget_border(WidgetNodeType w = gVScaleWidget; break; case MOZ_GTK_FRAME: - ensure_frame_widget(); - w = gFrameWidget; + w = GetWidget(MOZ_GTK_FRAME); break; case MOZ_GTK_CHECKBUTTON_CONTAINER: case MOZ_GTK_RADIOBUTTON_CONTAINER: @@ -2761,19 +2468,17 @@ moz_gtk_get_widget_border(WidgetNodeType return MOZ_GTK_SUCCESS; } case MOZ_GTK_MENUPOPUP: - ensure_menu_popup_widget(); - w = gMenuPopupWidget; + w = GetWidget(MOZ_GTK_MENUPOPUP); break; + case MOZ_GTK_MENUBARITEM: case MOZ_GTK_MENUITEM: case MOZ_GTK_CHECKMENUITEM: case MOZ_GTK_RADIOMENUITEM: { - if (widget == MOZ_GTK_MENUITEM) { - ensure_menu_item_widget(); - ensure_menu_bar_item_widget(); - w = gMenuItemWidget; - } - else { + if (widget == MOZ_GTK_MENUBARITEM || widget == MOZ_GTK_MENUITEM) { + // Bug 1274143 for MOZ_GTK_MENUBARITEM + w = GetWidget(MOZ_GTK_MENUITEM); + } else { ensure_check_menu_item_widget(); w = gCheckMenuItemWidget; } @@ -2784,9 +2489,16 @@ moz_gtk_get_widget_border(WidgetNodeType return MOZ_GTK_SUCCESS; } case MOZ_GTK_INFO_BAR: - ensure_info_bar(); - w = gInfoBar; + w = GetWidget(MOZ_GTK_INFO_BAR); break; + case MOZ_GTK_TOOLTIP: + { + style = ClaimStyleContext(MOZ_GTK_TOOLTIP); + moz_gtk_add_style_border(style, left, top, right, bottom); + moz_gtk_add_style_padding(style, left, top, right, bottom); + ReleaseStyleContext(style); + return MOZ_GTK_SUCCESS; + } /* These widgets have no borders, since they are not containers. */ case MOZ_GTK_CHECKBUTTON_LABEL: case MOZ_GTK_RADIOBUTTON_LABEL: @@ -2810,7 +2522,6 @@ moz_gtk_get_widget_border(WidgetNodeType case MOZ_GTK_MENUSEPARATOR: /* These widgets have no borders.*/ case MOZ_GTK_SPINBUTTON: - case MOZ_GTK_TOOLTIP: case MOZ_GTK_WINDOW: case MOZ_GTK_RESIZER: case MOZ_GTK_MENUARROW: @@ -2908,8 +2619,7 @@ moz_gtk_get_arrow_size(WidgetNodeType wi widget = gComboBoxArrowWidget; break; default: - ensure_button_arrow_widget(); - widget = gButtonArrowWidget; + widget = GetWidget(MOZ_GTK_BUTTON_ARROW); break; } @@ -2924,11 +2634,9 @@ moz_gtk_get_toolbar_separator_width(gint { gboolean wide_separators; gint separator_width; - GtkStyleContext* style; GtkBorder border; - ensure_toolbar_widget(); - style = gtk_widget_get_style_context(gToolbarWidget); + GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_TOOLBAR); gtk_style_context_get_style(style, "space-size", size, "wide-separators", &wide_separators, @@ -2937,17 +2645,18 @@ moz_gtk_get_toolbar_separator_width(gint /* Just in case... */ gtk_style_context_get_border(style, GTK_STATE_FLAG_NORMAL, &border); *size = MAX(*size, (wide_separators ? separator_width : border.left)); + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } gint moz_gtk_get_expander_size(gint* size) { - ensure_expander_widget(); - gtk_style_context_get_style(gtk_widget_get_style_context(gExpanderWidget), + GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_EXPANDER); + gtk_style_context_get_style(style, "expander-size", size, NULL); - + ReleaseStyleContext(style); return MOZ_GTK_SUCCESS; } @@ -2972,11 +2681,11 @@ moz_gtk_get_menu_separator_height(gint * GtkStyleContext* style; guint border_width; - ensure_menu_separator_widget(); - - border_width = gtk_container_get_border_width(GTK_CONTAINER(gMenuSeparatorWidget)); + border_width = + gtk_container_get_border_width(GTK_CONTAINER( + GetWidget(MOZ_GTK_MENUSEPARATOR))); - style = gtk_widget_get_style_context(gMenuSeparatorWidget); + style = ClaimStyleContext(MOZ_GTK_MENUSEPARATOR); gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding); gtk_style_context_save(style); @@ -2988,6 +2697,7 @@ moz_gtk_get_menu_separator_height(gint * NULL); gtk_style_context_restore(style); + ReleaseStyleContext(style); *size = padding.top + padding.bottom + border_width*2; *size += (wide_separators) ? separator_height : 1; @@ -2998,8 +2708,7 @@ moz_gtk_get_menu_separator_height(gint * void moz_gtk_get_entry_min_height(gint* height) { - ensure_entry_widget(); - GtkStyleContext* style = gtk_widget_get_style_context(gEntryWidget); + GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_ENTRY); if (!gtk_check_version(3, 20, 0)) { gtk_style_context_get(style, gtk_style_context_get_state(style), "min-height", height, @@ -3014,6 +2723,7 @@ moz_gtk_get_entry_min_height(gint* heigh gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding); *height += (border.top + border.bottom + padding.top + padding.bottom); + ReleaseStyleContext(style); } void @@ -3094,8 +2804,7 @@ moz_gtk_images_in_buttons() gboolean result; GtkSettings* settings; - ensure_button_widget(); - settings = gtk_widget_get_settings(gButtonWidget); + settings = gtk_widget_get_settings(GetWidget(MOZ_GTK_BUTTON)); g_object_get(settings, "gtk-button-images", &result, NULL); return result; @@ -3116,14 +2825,14 @@ moz_gtk_widget_paint(WidgetNodeType widg case MOZ_GTK_BUTTON: case MOZ_GTK_TOOLBAR_BUTTON: if (state->depressed) { - ensure_toggle_button_widget(); return moz_gtk_button_paint(cr, rect, state, (GtkReliefStyle) flags, - gToggleButtonWidget, direction); + GetWidget(MOZ_GTK_TOGGLE_BUTTON), + direction); } - ensure_button_widget(); return moz_gtk_button_paint(cr, rect, state, - (GtkReliefStyle) flags, gButtonWidget, + (GtkReliefStyle) flags, + GetWidget(MOZ_GTK_BUTTON), direction); break; case MOZ_GTK_CHECKBUTTON: @@ -3171,9 +2880,9 @@ moz_gtk_widget_paint(WidgetNodeType widg state, direction); break; case MOZ_GTK_SPINBUTTON_ENTRY: - ensure_spin_widget(); + // TODO - use MOZ_GTK_SPINBUTTON_ENTRY style directly return moz_gtk_entry_paint(cr, rect, state, - gSpinWidget, direction); + GetWidget(MOZ_GTK_SPINBUTTON), direction); break; case MOZ_GTK_GRIPPER: return moz_gtk_gripper_paint(cr, rect, state, @@ -3198,9 +2907,11 @@ moz_gtk_widget_paint(WidgetNodeType widg (GtkExpanderStyle) flags, direction); break; case MOZ_GTK_ENTRY: - ensure_entry_widget(); - return moz_gtk_entry_paint(cr, rect, state, - gEntryWidget, direction); + return moz_gtk_entry_paint(cr, rect, state, GetWidget(MOZ_GTK_ENTRY), + direction); + break; + case MOZ_GTK_TEXT_VIEW: + return moz_gtk_text_view_paint(cr, rect, state, direction); break; case MOZ_GTK_DROPDOWN: return moz_gtk_combo_box_paint(cr, rect, state, direction); @@ -3271,9 +2982,9 @@ moz_gtk_widget_paint(WidgetNodeType widg return moz_gtk_menu_separator_paint(cr, rect, direction); break; + case MOZ_GTK_MENUBARITEM: case MOZ_GTK_MENUITEM: - return moz_gtk_menu_item_paint(cr, rect, state, flags, - direction); + return moz_gtk_menu_item_paint(widget, cr, rect, state, direction); break; case MOZ_GTK_MENUARROW: return moz_gtk_menu_arrow_paint(cr, rect, state, @@ -3333,25 +3044,16 @@ gboolean moz_gtk_has_scrollbar_buttons(v gint moz_gtk_shutdown() { - if (gTooltipWidget) - gtk_widget_destroy(gTooltipWidget); /* This will destroy all of our widgets */ - ResetWidgetCache(); /* TODO - replace it with appropriate widget */ if (gTreeHeaderSortArrowWidget) gtk_widget_destroy(gTreeHeaderSortArrowWidget); - gProtoWindow = NULL; gProtoLayout = NULL; - gButtonWidget = NULL; - gToggleButtonWidget = NULL; - gButtonArrowWidget = NULL; - gSpinWidget = NULL; gHScaleWidget = NULL; gVScaleWidget = NULL; - gEntryWidget = NULL; gComboBoxWidget = NULL; gComboBoxButtonWidget = NULL; gComboBoxSeparatorWidget = NULL; @@ -3360,29 +3062,15 @@ moz_gtk_shutdown() gComboBoxEntryButtonWidget = NULL; gComboBoxEntryArrowWidget = NULL; gComboBoxEntryTextareaWidget = NULL; - gHandleBoxWidget = NULL; - gToolbarWidget = NULL; - gFrameWidget = NULL; - gProgressWidget = NULL; gTabWidget = NULL; - gTextViewWidget = nullptr; - gTooltipWidget = NULL; - gMenuBarWidget = NULL; - gMenuBarItemWidget = NULL; - gMenuPopupWidget = NULL; - gMenuItemWidget = NULL; gImageMenuItemWidget = NULL; gCheckMenuItemWidget = NULL; gTreeViewWidget = NULL; gMiddleTreeViewColumn = NULL; gTreeHeaderCellWidget = NULL; gTreeHeaderSortArrowWidget = NULL; - gExpanderWidget = NULL; - gToolbarSeparatorWidget = NULL; - gMenuSeparatorWidget = NULL; gHPanedWidget = NULL; gVPanedWidget = NULL; - gScrolledWindowWidget = NULL; is_initialized = FALSE; diff -up firefox-48.0/widget/gtk/gtkdrawing.h.gtk3-20 firefox-48.0/widget/gtk/gtkdrawing.h --- firefox-48.0/widget/gtk/gtkdrawing.h.gtk3-20 2016-07-25 22:22:07.000000000 +0200 +++ firefox-48.0/widget/gtk/gtkdrawing.h 2016-07-29 09:15:11.822285857 +0200 @@ -69,12 +69,6 @@ typedef enum { MOZ_GTK_TAB_SELECTED = 1 << 10 } GtkTabFlags; -/** flags for menuitems **/ -typedef enum { - /* menuitem is part of the menubar */ - MOZ_TOPLEVEL_MENU_ITEM = 1 << 0 -} GtkMenuItemFlags; - /* function type for moz_gtk_enable_style_props */ typedef gint (*style_prop_t)(GtkStyle*, const gchar*, gint); @@ -93,6 +87,10 @@ typedef enum { MOZ_GTK_BUTTON, /* Paints a button with image and no text */ MOZ_GTK_TOOLBAR_BUTTON, + /* Paints a toggle button */ + MOZ_GTK_TOGGLE_BUTTON, + /* Paints a button arrow */ + MOZ_GTK_BUTTON_ARROW, /* Paints the container part of a GtkCheckButton. */ MOZ_GTK_CHECKBUTTON_CONTAINER, @@ -115,6 +113,7 @@ typedef enum { /* Horizontal GtkScrollbar counterparts */ MOZ_GTK_SCROLLBAR_HORIZONTAL, + MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL, /* Paints the trough (track) of a GtkScrollbar. */ MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL, /* Paints the slider (thumb) of a GtkScrollbar. */ @@ -122,6 +121,7 @@ typedef enum { /* Vertical GtkScrollbar counterparts */ MOZ_GTK_SCROLLBAR_VERTICAL, + MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL, MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL, MOZ_GTK_SCROLLBAR_THUMB_VERTICAL, @@ -140,6 +140,10 @@ typedef enum { MOZ_GTK_GRIPPER, /* Paints a GtkEntry. */ MOZ_GTK_ENTRY, + /* Paints a GtkExpander. */ + MOZ_GTK_EXPANDER, + /* Paints a GtkTextView. */ + MOZ_GTK_TEXT_VIEW, /* Paints a GtkOptionMenu. */ MOZ_GTK_DROPDOWN, /* Paints a dropdown arrow (a GtkButton containing a down GtkArrow). */ @@ -159,6 +163,8 @@ typedef enum { MOZ_GTK_RESIZER, /* Paints a GtkProgressBar. */ MOZ_GTK_PROGRESSBAR, + /* Paints a trough (track) of a GtkProgressBar */ + MOZ_GTK_PROGRESS_TROUGH, /* Paints a progress chunk of a GtkProgressBar. */ MOZ_GTK_PROGRESS_CHUNK, /* Paints a progress chunk of an indeterminated GtkProgressBar. */ @@ -187,7 +193,9 @@ typedef enum { MOZ_GTK_MENUARROW, /* Paints an arrow in a toolbar button. flags is a GtkArrowType. */ MOZ_GTK_TOOLBARBUTTON_ARROW, - /* Paints items of menubar and popups. */ + /* Paints items of menubar. */ + MOZ_GTK_MENUBARITEM, + /* Paints items of popup menus. */ MOZ_GTK_MENUITEM, MOZ_GTK_CHECKMENUITEM, MOZ_GTK_RADIOMENUITEM, @@ -202,6 +210,8 @@ typedef enum { MOZ_GTK_WINDOW_CONTAINER, /* Paints a GtkInfoBar, for notifications. */ MOZ_GTK_INFO_BAR, + /* Used for scrolled window shell. */ + MOZ_GTK_SCROLLED_WINDOW, MOZ_GTK_WIDGET_NODE_COUNT } WidgetNodeType; diff -up firefox-48.0/widget/gtk/mozgtk/mozgtk.c.gtk3-20 firefox-48.0/widget/gtk/mozgtk/mozgtk.c --- firefox-48.0/widget/gtk/mozgtk/mozgtk.c.gtk3-20 2016-07-25 22:22:07.000000000 +0200 +++ firefox-48.0/widget/gtk/mozgtk/mozgtk.c 2016-07-29 09:15:11.823285862 +0200 @@ -517,6 +517,7 @@ STUB(gdk_event_get_source_device) STUB(gdk_window_get_type) STUB(gdk_x11_window_get_xid) STUB(gdk_x11_display_get_type) +STUB(gtk_box_new) STUB(gtk_cairo_should_draw_window) STUB(gtk_cairo_transform_to_window) STUB(gtk_combo_box_text_append) @@ -570,6 +571,7 @@ STUB(gtk_tree_view_column_get_button) STUB(gtk_widget_get_preferred_size) STUB(gtk_widget_get_state_flags) STUB(gtk_widget_get_style_context) +STUB(gtk_widget_path_append_for_widget) STUB(gtk_widget_path_append_type) STUB(gtk_widget_path_copy) STUB(gtk_widget_path_free) @@ -587,6 +589,10 @@ STUB(gtk_color_chooser_get_type) STUB(gtk_color_chooser_set_rgba) STUB(gtk_color_chooser_get_rgba) STUB(gtk_color_chooser_set_use_alpha) +STUB(gtk_check_menu_item_new) +STUB(gtk_style_context_get_direction) +STUB(gtk_style_context_invalidate) +STUB(gtk_tooltip_get_type) #endif #ifdef GTK2_SYMBOLS diff -up firefox-48.0/widget/gtk/nsLookAndFeel.cpp.gtk3-20 firefox-48.0/widget/gtk/nsLookAndFeel.cpp --- firefox-48.0/widget/gtk/nsLookAndFeel.cpp.gtk3-20 2016-06-01 06:11:44.000000000 +0200 +++ firefox-48.0/widget/gtk/nsLookAndFeel.cpp 2016-07-29 09:15:54.943459700 +0200 @@ -31,6 +31,7 @@ #if MOZ_WIDGET_GTK != 2 #include +#include "WidgetStyleCache.h" #endif using mozilla::LookAndFeel; @@ -1135,15 +1136,24 @@ nsLookAndFeel::Init() 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 - gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOOLTIP); - gtk_style_context_add_class(style, GTK_STYLE_CLASS_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); - gtk_style_context_get_color(style, GTK_STATE_FLAG_NORMAL, &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); - g_object_unref(style); + ReleaseStyleContext(style); // menu foreground & menu background GtkWidget *accel_label = gtk_accel_label_new("M"); diff -up firefox-48.0/widget/gtk/nsNativeThemeGTK.cpp.gtk3-20 firefox-48.0/widget/gtk/nsNativeThemeGTK.cpp --- firefox-48.0/widget/gtk/nsNativeThemeGTK.cpp.gtk3-20 2016-07-25 22:22:07.000000000 +0200 +++ firefox-48.0/widget/gtk/nsNativeThemeGTK.cpp 2016-07-29 09:15:11.824285865 +0200 @@ -354,10 +354,8 @@ nsNativeThemeGTK::GetGtkWidgetAndState(u if (isTopLevel) { aState->inHover = menuFrame->IsOpen(); - *aWidgetFlags |= MOZ_TOPLEVEL_MENU_ITEM; } else { aState->inHover = CheckBooleanAttr(aFrame, nsGkAtoms::menuactive); - *aWidgetFlags &= ~MOZ_TOPLEVEL_MENU_ITEM; } aState->active = FALSE; @@ -510,8 +508,14 @@ nsNativeThemeGTK::GetGtkWidgetAndState(u break; case NS_THEME_NUMBER_INPUT: case NS_THEME_TEXTFIELD: + aGtkWidgetType = MOZ_GTK_ENTRY; + break; case NS_THEME_TEXTFIELD_MULTILINE: +#if (MOZ_WIDGET_GTK == 3) + aGtkWidgetType = MOZ_GTK_TEXT_VIEW; +#else aGtkWidgetType = MOZ_GTK_ENTRY; +#endif break; case NS_THEME_LISTBOX: case NS_THEME_TREEVIEW: @@ -673,6 +677,13 @@ nsNativeThemeGTK::GetGtkWidgetAndState(u aGtkWidgetType = MOZ_GTK_MENUPOPUP; break; case NS_THEME_MENUITEM: + { + nsMenuFrame *menuFrame = do_QueryFrame(aFrame); + if (menuFrame && menuFrame->IsOnMenuBar()) { + aGtkWidgetType = MOZ_GTK_MENUBARITEM; + break; + } + } aGtkWidgetType = MOZ_GTK_MENUITEM; break; case NS_THEME_MENUSEPARATOR: diff -up firefox-48.0/widget/gtk/WidgetStyleCache.cpp.gtk3-20 firefox-48.0/widget/gtk/WidgetStyleCache.cpp --- firefox-48.0/widget/gtk/WidgetStyleCache.cpp.gtk3-20 2016-07-25 22:22:07.000000000 +0200 +++ firefox-48.0/widget/gtk/WidgetStyleCache.cpp 2016-07-29 09:15:11.825285869 +0200 @@ -22,7 +22,7 @@ static bool sStyleContextNeedsRestore; static GtkStyleContext* sCurrentStyleContext; #endif static GtkStyleContext* -GetStyleInternal(WidgetNodeType aNodeType); +GetCssNodeStyleInternal(WidgetNodeType aNodeType); static GtkWidget* CreateWindowWidget() @@ -67,12 +67,175 @@ CreateCheckboxWidget() static GtkWidget* CreateRadiobuttonWidget() { - GtkWidget* widget = gtk_radio_button_new_with_label(NULL, "M"); + GtkWidget* widget = gtk_radio_button_new_with_label(nullptr, "M"); AddToWindowContainer(widget); return widget; } static GtkWidget* +CreateMenuBarWidget() +{ + GtkWidget* widget = gtk_menu_bar_new(); + AddToWindowContainer(widget); + return widget; +} + +static GtkWidget* +CreateMenuPopupWidget() +{ + GtkWidget* widget = gtk_menu_new(); + gtk_menu_attach_to_widget(GTK_MENU(widget), GetWidget(MOZ_GTK_WINDOW), + nullptr); + return widget; +} + +static GtkWidget* +CreateMenuItemWidget(WidgetNodeType aShellType) +{ + GtkWidget* widget = gtk_menu_item_new(); + gtk_menu_shell_append(GTK_MENU_SHELL(GetWidget(aShellType)), widget); + return widget; +} + +static GtkWidget* +CreateProgressWidget() +{ + GtkWidget* widget = gtk_progress_bar_new(); + AddToWindowContainer(widget); + return widget; +} + +static GtkWidget* +CreateTooltipWidget() +{ + MOZ_ASSERT(gtk_check_version(3, 20, 0) != nullptr, + "CreateTooltipWidget should be used for Gtk < 3.20 only."); + GtkWidget* widget = CreateWindowWidget(); + GtkStyleContext* style = gtk_widget_get_style_context(widget); + gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOOLTIP); + return widget; +} + +static GtkWidget* +CreateExpanderWidget() +{ + GtkWidget* widget = gtk_expander_new("M"); + AddToWindowContainer(widget); + return widget; +} + +static GtkWidget* +CreateFrameWidget() +{ + GtkWidget* widget = gtk_frame_new(nullptr); + AddToWindowContainer(widget); + return widget; +} + +static GtkWidget* +CreateGripperWidget() +{ + GtkWidget* widget = gtk_handle_box_new(); + AddToWindowContainer(widget); + return widget; +} + +static GtkWidget* +CreateToolbarWidget() +{ + GtkWidget* widget = gtk_toolbar_new(); + gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_GRIPPER)), widget); + gtk_widget_realize(widget); + return widget; +} + +static GtkWidget* +CreateToolbarSeparatorWidget() +{ + GtkWidget* widget = GTK_WIDGET(gtk_separator_tool_item_new()); + AddToWindowContainer(widget); + return widget; +} + +static GtkWidget* +CreateInfoBarWidget() +{ + GtkWidget* widget = gtk_info_bar_new(); + AddToWindowContainer(widget); + return widget; +} + +static GtkWidget* +CreateButtonWidget() +{ + GtkWidget* widget = gtk_button_new_with_label("M"); + AddToWindowContainer(widget); + return widget; +} + +static GtkWidget* +CreateToggleButtonWidget() +{ + GtkWidget* widget = gtk_toggle_button_new(); + AddToWindowContainer(widget); + return widget; +} + +static GtkWidget* +CreateButtonArrowWidget() +{ + GtkWidget* widget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT); + gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_TOGGLE_BUTTON)), widget); + gtk_widget_realize(widget); + gtk_widget_show(widget); + return widget; +} + +static GtkWidget* +CreateSpinWidget() +{ + GtkWidget* widget = gtk_spin_button_new(nullptr, 1, 0); + AddToWindowContainer(widget); + return widget; +} + +static GtkWidget* +CreateEntryWidget() +{ + GtkWidget* widget = gtk_entry_new(); + AddToWindowContainer(widget); + return widget; +} + +static GtkWidget* +CreateScrolledWindowWidget() +{ + GtkWidget* widget = gtk_scrolled_window_new(nullptr, nullptr); + AddToWindowContainer(widget); + return widget; +} + +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(); + gtk_menu_shell_append(GTK_MENU_SHELL(GetWidget(MOZ_GTK_MENUPOPUP)), + widget); + gtk_widget_realize(widget); + return widget; +} + + +static GtkWidget* CreateWidget(WidgetNodeType aWidgetType) { switch (aWidgetType) { @@ -80,16 +243,54 @@ CreateWidget(WidgetNodeType aWidgetType) return CreateWindowWidget(); case MOZ_GTK_WINDOW_CONTAINER: return CreateWindowContainerWidget(); + case MOZ_GTK_CHECKBUTTON_CONTAINER: + return CreateCheckboxWidget(); + case MOZ_GTK_PROGRESSBAR: + return CreateProgressWidget(); + case MOZ_GTK_RADIOBUTTON_CONTAINER: + return CreateRadiobuttonWidget(); case MOZ_GTK_SCROLLBAR_HORIZONTAL: return CreateScrollbarWidget(aWidgetType, GTK_ORIENTATION_HORIZONTAL); case MOZ_GTK_SCROLLBAR_VERTICAL: return CreateScrollbarWidget(aWidgetType, GTK_ORIENTATION_VERTICAL); - case MOZ_GTK_CHECKBUTTON_CONTAINER: - return CreateCheckboxWidget(); - case MOZ_GTK_RADIOBUTTON_CONTAINER: - return CreateRadiobuttonWidget(); + case MOZ_GTK_MENUBAR: + return CreateMenuBarWidget(); + case MOZ_GTK_MENUPOPUP: + return CreateMenuPopupWidget(); + case MOZ_GTK_MENUBARITEM: + return CreateMenuItemWidget(MOZ_GTK_MENUBAR); + case MOZ_GTK_MENUITEM: + return CreateMenuItemWidget(MOZ_GTK_MENUPOPUP); + case MOZ_GTK_MENUSEPARATOR: + return CreateMenuSeparatorWidget(); + case MOZ_GTK_EXPANDER: + return CreateExpanderWidget(); + case MOZ_GTK_FRAME: + return CreateFrameWidget(); + case MOZ_GTK_GRIPPER: + return CreateGripperWidget(); + case MOZ_GTK_TOOLBAR: + return CreateToolbarWidget(); + case MOZ_GTK_TOOLBAR_SEPARATOR: + return CreateToolbarSeparatorWidget(); + case MOZ_GTK_INFO_BAR: + return CreateInfoBarWidget(); + case MOZ_GTK_SPINBUTTON: + return CreateSpinWidget(); + case MOZ_GTK_BUTTON: + return CreateButtonWidget(); + case MOZ_GTK_TOGGLE_BUTTON: + return CreateToggleButtonWidget(); + case MOZ_GTK_BUTTON_ARROW: + return CreateButtonArrowWidget(); + case MOZ_GTK_ENTRY: + return CreateEntryWidget(); + case MOZ_GTK_SCROLLED_WINDOW: + return CreateScrolledWindowWidget(); + case MOZ_GTK_TEXT_VIEW: + return CreateTextViewWidget(); default: /* Not implemented */ return nullptr; @@ -107,17 +308,42 @@ GetWidget(WidgetNodeType aWidgetType) return widget; } -static GtkStyleContext* -CreateCSSNode(const char* aName, GtkStyleContext *aParentStyle) +GtkStyleContext* +CreateStyleForWidget(GtkWidget* aWidget, GtkStyleContext* aParentStyle) +{ + GtkWidgetPath* path = aParentStyle ? + gtk_widget_path_copy(gtk_style_context_get_path(aParentStyle)) : + gtk_widget_path_new(); + + // Work around https://bugzilla.gnome.org/show_bug.cgi?id=767312 + // which exists in GTK+ 3.20. + gtk_widget_get_style_context(aWidget); + + gtk_widget_path_append_for_widget(path, aWidget); + // Release any floating reference on aWidget. + g_object_ref_sink(aWidget); + g_object_unref(aWidget); + + GtkStyleContext *context = gtk_style_context_new(); + gtk_style_context_set_path(context, path); + gtk_style_context_set_parent(context, aParentStyle); + gtk_widget_path_unref(path); + + return context; +} + +GtkStyleContext* +CreateCSSNode(const char* aName, GtkStyleContext* aParentStyle, GType aType) { static auto sGtkWidgetPathIterSetObjectName = reinterpret_cast (dlsym(RTLD_DEFAULT, "gtk_widget_path_iter_set_object_name")); - GtkWidgetPath* path = - gtk_widget_path_copy(gtk_style_context_get_path(aParentStyle)); + GtkWidgetPath* path = aParentStyle ? + gtk_widget_path_copy(gtk_style_context_get_path(aParentStyle)) : + gtk_widget_path_new(); - gtk_widget_path_append_type(path, G_TYPE_NONE); + gtk_widget_path_append_type(path, aType); (*sGtkWidgetPathIterSetObjectName)(path, -1, aName); @@ -130,95 +356,168 @@ CreateCSSNode(const char* aName, GtkStyl } static GtkStyleContext* -GetChildNodeStyle(WidgetNodeType aStyleType, - WidgetNodeType aWidgetType, - const gchar* aStyleClass, - WidgetNodeType aParentNodeType) +CreateChildCSSNode(const char* aName, WidgetNodeType aParentNodeType) { - GtkStyleContext* style; - - if (gtk_check_version(3, 20, 0) != nullptr) { - style = gtk_widget_get_style_context(sWidgetStorage[aWidgetType]); - - gtk_style_context_save(style); - MOZ_ASSERT(!sStyleContextNeedsRestore); - sStyleContextNeedsRestore = true; - - gtk_style_context_add_class(style, aStyleClass); - } - else { - style = sStyleStorage[aStyleType]; - if (!style) { - style = CreateCSSNode(aStyleClass, GetStyleInternal(aParentNodeType)); - MOZ_ASSERT(!sStyleContextNeedsRestore); - sStyleStorage[aStyleType] = style; - } - } + return CreateCSSNode(aName, GetCssNodeStyleInternal(aParentNodeType)); +} +static GtkStyleContext* +GetWidgetStyleWithClass(WidgetNodeType aWidgetType, const gchar* aStyleClass) +{ + GtkStyleContext* style = gtk_widget_get_style_context(GetWidget(aWidgetType)); + gtk_style_context_save(style); + MOZ_ASSERT(!sStyleContextNeedsRestore); + sStyleContextNeedsRestore = true; + gtk_style_context_add_class(style, aStyleClass); return style; } +/* GetCssNodeStyleInternal is used by Gtk >= 3.20 */ static GtkStyleContext* -GetStyleInternal(WidgetNodeType aNodeType) +GetCssNodeStyleInternal(WidgetNodeType aNodeType) { + GtkStyleContext* style = sStyleStorage[aNodeType]; + if (style) + return style; + switch (aNodeType) { - case MOZ_GTK_SCROLLBAR_HORIZONTAL: - /* Root CSS node / widget for scrollbars */ + case MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL: + style = CreateChildCSSNode("contents", + MOZ_GTK_SCROLLBAR_HORIZONTAL); break; case MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL: - return GetChildNodeStyle(aNodeType, - MOZ_GTK_SCROLLBAR_HORIZONTAL, - GTK_STYLE_CLASS_TROUGH, - MOZ_GTK_SCROLLBAR_HORIZONTAL); - + style = CreateChildCSSNode(GTK_STYLE_CLASS_TROUGH, + MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL); + break; case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL: - return GetChildNodeStyle(aNodeType, - MOZ_GTK_SCROLLBAR_HORIZONTAL, - GTK_STYLE_CLASS_SLIDER, - MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL); - - case MOZ_GTK_SCROLLBAR_VERTICAL: - /* Root CSS node / widget for scrollbars */ + style = CreateChildCSSNode(GTK_STYLE_CLASS_SLIDER, + MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL); + break; + case MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL: + style = CreateChildCSSNode("contents", + MOZ_GTK_SCROLLBAR_VERTICAL); break; case MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL: - return GetChildNodeStyle(aNodeType, - MOZ_GTK_SCROLLBAR_VERTICAL, - GTK_STYLE_CLASS_TROUGH, - MOZ_GTK_SCROLLBAR_VERTICAL); - + style = CreateChildCSSNode(GTK_STYLE_CLASS_TROUGH, + MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL); + break; case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL: - return GetChildNodeStyle(aNodeType, - MOZ_GTK_SCROLLBAR_VERTICAL, - GTK_STYLE_CLASS_SLIDER, - MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL); - - case MOZ_GTK_RADIOBUTTON_CONTAINER: - /* Root CSS node / widget for checkboxes */ + style = CreateChildCSSNode(GTK_STYLE_CLASS_SLIDER, + MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL); break; case MOZ_GTK_RADIOBUTTON: - return GetChildNodeStyle(aNodeType, - MOZ_GTK_RADIOBUTTON_CONTAINER, - GTK_STYLE_CLASS_RADIO, - MOZ_GTK_RADIOBUTTON_CONTAINER); - case MOZ_GTK_CHECKBUTTON_CONTAINER: - /* Root CSS node / widget for radiobuttons */ + style = CreateChildCSSNode(GTK_STYLE_CLASS_RADIO, + MOZ_GTK_RADIOBUTTON_CONTAINER); break; case MOZ_GTK_CHECKBUTTON: - return GetChildNodeStyle(aNodeType, - MOZ_GTK_CHECKBUTTON_CONTAINER, - GTK_STYLE_CLASS_CHECK, - MOZ_GTK_CHECKBUTTON_CONTAINER); - default: + style = CreateChildCSSNode(GTK_STYLE_CLASS_CHECK, + MOZ_GTK_CHECKBUTTON_CONTAINER); + break; + case MOZ_GTK_PROGRESS_TROUGH: + /* Progress bar background (trough) */ + style = CreateChildCSSNode(GTK_STYLE_CLASS_TROUGH, + MOZ_GTK_PROGRESSBAR); + break; + case MOZ_GTK_PROGRESS_CHUNK: + 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, + GTK_STYLE_CLASS_GRIP); + case MOZ_GTK_INFO_BAR: + // TODO - create from CSS node + return GetWidgetStyleWithClass(MOZ_GTK_INFO_BAR, + GTK_STYLE_CLASS_INFO); + case MOZ_GTK_SPINBUTTON_ENTRY: + // TODO - create from CSS node + return GetWidgetStyleWithClass(MOZ_GTK_SPINBUTTON, + GTK_STYLE_CLASS_ENTRY); + case MOZ_GTK_SCROLLED_WINDOW: + // 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); + default: + // TODO - create style from style path + GtkWidget* widget = GetWidget(aNodeType); + return gtk_widget_get_style_context(widget); } - GtkWidget* widget = GetWidget(aNodeType); - if (widget) { - return gtk_widget_get_style_context(widget); - } + MOZ_ASSERT(style, "missing style context for node type"); + sStyleStorage[aNodeType] = style; + return style; +} - MOZ_ASSERT_UNREACHABLE("missing style context for node type"); - return nullptr; +/* GetWidgetStyleInternal is used by Gtk < 3.20 */ +static GtkStyleContext* +GetWidgetStyleInternal(WidgetNodeType aNodeType) +{ + switch (aNodeType) { + case MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL: + return GetWidgetStyleWithClass(MOZ_GTK_SCROLLBAR_HORIZONTAL, + GTK_STYLE_CLASS_TROUGH); + case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL: + return GetWidgetStyleWithClass(MOZ_GTK_SCROLLBAR_HORIZONTAL, + GTK_STYLE_CLASS_SLIDER); + case MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL: + return GetWidgetStyleWithClass(MOZ_GTK_SCROLLBAR_VERTICAL, + GTK_STYLE_CLASS_TROUGH); + case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL: + return GetWidgetStyleWithClass(MOZ_GTK_SCROLLBAR_VERTICAL, + GTK_STYLE_CLASS_SLIDER); + case MOZ_GTK_RADIOBUTTON: + return GetWidgetStyleWithClass(MOZ_GTK_RADIOBUTTON_CONTAINER, + GTK_STYLE_CLASS_RADIO); + case MOZ_GTK_CHECKBUTTON: + return GetWidgetStyleWithClass(MOZ_GTK_CHECKBUTTON_CONTAINER, + 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; + return style; + } + case MOZ_GTK_GRIPPER: + return GetWidgetStyleWithClass(MOZ_GTK_GRIPPER, + GTK_STYLE_CLASS_GRIP); + case MOZ_GTK_INFO_BAR: + return GetWidgetStyleWithClass(MOZ_GTK_INFO_BAR, + GTK_STYLE_CLASS_INFO); + case MOZ_GTK_SPINBUTTON_ENTRY: + return GetWidgetStyleWithClass(MOZ_GTK_SPINBUTTON, + GTK_STYLE_CLASS_ENTRY); + 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); + default: + GtkWidget* widget = GetWidget(aNodeType); + MOZ_ASSERT(widget); + return gtk_widget_get_style_context(widget); + } } void @@ -245,13 +544,39 @@ ResetWidgetCache(void) GtkStyleContext* ClaimStyleContext(WidgetNodeType aNodeType, GtkTextDirection aDirection, - StyleFlags aFlags) + GtkStateFlags aStateFlags, StyleFlags aFlags) { - GtkStyleContext* style = GetStyleInternal(aNodeType); + MOZ_ASSERT(!sStyleContextNeedsRestore); + GtkStyleContext* style; + if (gtk_check_version(3, 20, 0) != nullptr) { + style = GetWidgetStyleInternal(aNodeType); + } else { + style = GetCssNodeStyleInternal(aNodeType); + } #ifdef DEBUG MOZ_ASSERT(!sCurrentStyleContext); sCurrentStyleContext = style; #endif + GtkStateFlags oldState = gtk_style_context_get_state(style); + GtkTextDirection oldDirection = gtk_style_context_get_direction(style); + if (oldState != aStateFlags || oldDirection != aDirection) { + // From GTK 3.8, set_state() will overwrite the direction, so set + // direction after state. + gtk_style_context_set_state(style, aStateFlags); + gtk_style_context_set_direction(style, aDirection); + + // This invalidate is necessary for unsaved style contexts from GtkWidgets + // in pre-3.18 GTK, because automatic invalidation of such contexts + // was delayed until a resize event runs. + // + // https://bugzilla.mozilla.org/show_bug.cgi?id=1272194#c7 + // + // Avoid calling invalidate on saved contexts to avoid performing + // build_properties() (in 3.16 stylecontext.c) unnecessarily early. + if (!sStyleContextNeedsRestore) { + gtk_style_context_invalidate(style); + } + } return style; } diff -up firefox-48.0/widget/gtk/WidgetStyleCache.h.gtk3-20 firefox-48.0/widget/gtk/WidgetStyleCache.h --- firefox-48.0/widget/gtk/WidgetStyleCache.h.gtk3-20 2016-07-25 22:22:07.000000000 +0200 +++ firefox-48.0/widget/gtk/WidgetStyleCache.h 2016-07-29 09:15:11.825285869 +0200 @@ -21,10 +21,24 @@ enum : StyleFlags { GtkWidget* GetWidget(WidgetNodeType aNodeType); +/* + * Return a new style context based on aWidget, as a child of aParentStyle. + * If aWidget still has a floating reference, then it is sunk and released. + */ +GtkStyleContext* +CreateStyleForWidget(GtkWidget* aWidget, GtkStyleContext* aParentStyle); + +// CreateCSSNode is implemented for gtk >= 3.20 only. +GtkStyleContext* +CreateCSSNode(const char* aName, + GtkStyleContext* aParentStyle, + GType aType = G_TYPE_NONE); + // Callers must call ReleaseStyleContext() on the returned context. GtkStyleContext* ClaimStyleContext(WidgetNodeType aNodeType, GtkTextDirection aDirection = GTK_TEXT_DIR_LTR, + GtkStateFlags aStateFlags = GTK_STATE_FLAG_NORMAL, StyleFlags aFlags = NO_STYLE_FLAGS); void ReleaseStyleContext(GtkStyleContext* style);