--- a/widget/gtk/WidgetStyleCache.cpp
+++ b/widget/gtk/WidgetStyleCache.cpp
@@ -123,16 +123,50 @@ CreateTooltipWidget()
"CreateTooltipWidget should be used for Gtk < 3.20 only.");
GtkWidget* widget = CreateWindowWidget(MOZ_GTK_WINDOW);
GtkStyleContext* style = gtk_widget_get_style_context(widget);
gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOOLTIP);
return widget;
}
static GtkWidget*
+CreateHeaderBar()
+{
+ MOZ_ASSERT(gtk_check_version(3, 10, 0) == nullptr,
+ "GtkHeaderBar is only available on GTK 3.10+.");
+
+ static auto sGtkHeaderBarNewPtr = (GtkWidget* (*)())
+ dlsym(RTLD_DEFAULT, "gtk_header_bar_new");
+ static const char* MOZ_GTK_STYLE_CLASS_TITLEBAR = "titlebar";
+
+ GtkWidget* widget = sGtkHeaderBarNewPtr();
+ AddToWindowContainer(widget);
+
+ GtkStyleContext* style = gtk_widget_get_style_context(widget);
+ gtk_style_context_add_class(style, MOZ_GTK_STYLE_CLASS_TITLEBAR);
+
+ return widget;
+}
+
+static GtkWidget*
+CreateHeaderBarButton()
+{
+ static const char* MOZ_GTK_STYLE_CLASS_TITLEBUTTON = "titlebutton";
+
+ GtkWidget* widget = gtk_button_new();
+ gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_HEADER_BAR)), widget);
+
+ GtkStyleContext* style = gtk_widget_get_style_context(widget);
+ gtk_style_context_add_class(style, MOZ_GTK_STYLE_CLASS_TITLEBUTTON);
+
+ return widget;
+
+}
+
+static GtkWidget*
CreateWidget(WidgetNodeType aWidgetType)
{
switch (aWidgetType) {
case MOZ_GTK_WINDOW:
case MOZ_GTK_WINDOW_CSD:
case MOZ_GTK_WINDOW_SOLID_CSD:
return CreateWindowWidget(aWidgetType);
case MOZ_GTK_WINDOW_CONTAINER:
@@ -152,16 +186,20 @@ CreateWidget(WidgetNodeType aWidgetType)
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_HEADER_BAR:
+ return CreateHeaderBar();
+ case MOZ_GTK_HEADER_BAR_BUTTON:
+ return CreateHeaderBarButton();
default:
/* Not implemented */
return nullptr;
}
}
GtkWidget*
GetWidget(WidgetNodeType aWidgetType)
@@ -381,16 +419,22 @@ ResetWidgetCache(void)
mozilla::PodArrayZero(sWidgetStorage);
}
GtkStyleContext*
ClaimStyleContext(WidgetNodeType aNodeType, GtkTextDirection aDirection,
GtkStateFlags aStateFlags, StyleFlags aFlags)
{
MOZ_ASSERT(!sStyleContextNeedsRestore);
+
+ GtkWidget* window = GetWidget(MOZ_GTK_WINDOW);
+ GtkStyleContext* windowStyle = gtk_widget_get_style_context(window);
+ if (aFlags & MOZ_WINDOW_MAXIMIZED)
+ gtk_style_context_add_class(windowStyle, "maximized");
+
GtkStyleContext* style;
if (gtk_check_version(3, 20, 0) != nullptr) {
style = GetWidgetStyleInternal(aNodeType);
} else {
style = GetCssNodeStyleInternal(aNodeType);
}
#ifdef DEBUG
MOZ_ASSERT(!sCurrentStyleContext);
@@ -425,9 +469,13 @@ ReleaseStyleContext(GtkStyleContext* aSt
if (sStyleContextNeedsRestore) {
gtk_style_context_restore(aStyleContext);
}
sStyleContextNeedsRestore = false;
#ifdef DEBUG
MOZ_ASSERT(sCurrentStyleContext == aStyleContext);
sCurrentStyleContext = nullptr;
#endif
+
+ GtkWidget* window = GetWidget(MOZ_GTK_WINDOW);
+ GtkStyleContext* style = gtk_widget_get_style_context(window);
+ gtk_style_context_remove_class(style, "maximized");
}
--- a/widget/gtk/gtk3drawing.cpp
+++ b/widget/gtk/gtk3drawing.cpp
@@ -854,16 +854,34 @@ moz_gtk_button_paint(cairo_t *cr, GdkRec
height -= (border.top + border.bottom);
gtk_render_focus(style, cr, x, y, width, height);
}
gtk_style_context_restore(style);
return MOZ_GTK_SUCCESS;
}
static gint
+moz_gtk_header_bar_button_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkWidgetState* state,
+ GtkReliefStyle relief, GtkWidget* widget,
+ GtkTextDirection direction)
+{
+ GtkBorder margin;
+ GtkStyleContext* style = gtk_widget_get_style_context(widget);
+ gtk_style_context_get_margin(style, GTK_STATE_FLAG_NORMAL, &margin);
+
+ rect->x += margin.left;
+ rect->y += margin.top;
+ rect->width -= margin.left + margin.right;
+ rect->height -= margin.top + margin.bottom;
+
+ return moz_gtk_button_paint(cr, rect, state, relief, widget, direction);
+}
+
+static gint
moz_gtk_toggle_paint(cairo_t *cr, GdkRectangle* rect,
GtkWidgetState* state,
gboolean selected, gboolean inconsistent,
gboolean isradio, GtkTextDirection direction)
{
GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
gint indicator_size, indicator_spacing;
gint x, y, width, height;
@@ -2579,16 +2597,39 @@ moz_gtk_info_bar_paint(cairo_t *cr, GdkR
rect->height);
gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
gtk_style_context_restore(style);
return MOZ_GTK_SUCCESS;
}
+static gint
+moz_gtk_header_bar_paint(cairo_t *cr, GdkRectangle* rect, GtkWidgetState* state,
+ GtkCSDFlags flags)
+{
+ GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
+ GtkStyleContext *style;
+ StyleFlags style_flags = 0;
+
+ if (flags & MOZ_GTK_CSD_MAXIMIZED)
+ style_flags |= MOZ_WINDOW_MAXIMIZED;
+
+ style = ClaimStyleContext(MOZ_GTK_HEADER_BAR, GTK_TEXT_DIR_LTR,
+ state_flags, style_flags);
+
+ 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;
+}
+
static void
moz_gtk_add_style_border(GtkStyleContext* style,
gint* left, gint* top, gint* right, gint* bottom)
{
GtkBorder border;
gtk_style_context_get_border(style, GTK_STATE_FLAG_NORMAL, &border);
@@ -2823,16 +2864,33 @@ moz_gtk_get_widget_border(WidgetNodeType
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;
}
+ case MOZ_GTK_HEADER_BAR:
+ {
+ style = ClaimStyleContext(MOZ_GTK_HEADER_BAR);
+ 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;
+ }
+ case MOZ_GTK_HEADER_BAR_BUTTON:
+ {
+ style = ClaimStyleContext(MOZ_GTK_HEADER_BAR_BUTTON);
+ moz_gtk_add_style_border(style, left, top, right, bottom);
+ moz_gtk_add_style_padding(style, left, top, right, bottom);
+ moz_gtk_add_style_margin(style, left, top, right, bottom);
+ ReleaseStyleContext(style);
+ return MOZ_GTK_SUCCESS;
+ }
case MOZ_GTK_WINDOW_DECORATION:
{
moz_gtk_get_window_decoration_extents(top, right, bottom, left);
style = ClaimStyleContext(MOZ_GTK_WINDOW_DECORATION);
moz_gtk_add_style_border(style, left, top, right, bottom);
moz_gtk_add_style_padding(style, left, top, right, bottom);
ReleaseStyleContext(style);
@@ -3181,16 +3239,22 @@ moz_gtk_widget_paint(WidgetNodeType widg
(GtkReliefStyle) flags,
gToggleButtonWidget, direction);
}
ensure_button_widget();
return moz_gtk_button_paint(cr, rect, state,
(GtkReliefStyle) flags, gButtonWidget,
direction);
break;
+ case MOZ_GTK_HEADER_BAR_BUTTON:
+ return moz_gtk_header_bar_button_paint(cr, rect, state,
+ (GtkReliefStyle) flags,
+ GetWidget(MOZ_GTK_HEADER_BAR_BUTTON),
+ direction);
+ break;
case MOZ_GTK_CHECKBUTTON:
case MOZ_GTK_RADIOBUTTON:
return moz_gtk_toggle_paint(cr, rect, state,
!!(flags & MOZ_GTK_WIDGET_CHECKED),
!!(flags & MOZ_GTK_WIDGET_INCONSISTENT),
(widget == MOZ_GTK_RADIOBUTTON),
direction);
break;
@@ -3360,16 +3424,20 @@ moz_gtk_widget_paint(WidgetNodeType widg
return moz_gtk_hpaned_paint(cr, rect, state);
break;
case MOZ_GTK_WINDOW:
return moz_gtk_window_paint(cr, rect, direction);
break;
case MOZ_GTK_INFO_BAR:
return moz_gtk_info_bar_paint(cr, rect, state);
break;
+ case MOZ_GTK_HEADER_BAR:
+ return moz_gtk_header_bar_paint(cr, rect, state,
+ (GtkCSDFlags) flags);
+ break;
case MOZ_GTK_WINDOW_DECORATION:
return moz_gtk_window_decoration_paint(cr, rect, direction);
break;
case MOZ_GTK_WINDOW_DECORATION_SOLID:
return moz_gtk_window_decoration_solid_paint(cr, rect, direction);
break;
default:
g_warning("Unknown widget type: %d", widget);
--- a/widget/gtk/nsNativeThemeGTK.cpp
+++ b/widget/gtk/nsNativeThemeGTK.cpp
@@ -701,16 +701,30 @@ nsNativeThemeGTK::GetGtkWidgetAndState(u
break;
case NS_THEME_WINDOW:
case NS_THEME_DIALOG:
aGtkWidgetType = MOZ_GTK_WINDOW;
break;
case NS_THEME_GTK_INFO_BAR:
aGtkWidgetType = MOZ_GTK_INFO_BAR;
break;
+ case NS_THEME_WINDOW_TITLEBAR:
+ case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED:
+ aGtkWidgetType = MOZ_GTK_HEADER_BAR;
+ if (aWidgetFlags) {
+ *aWidgetFlags = aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED ?
+ MOZ_GTK_CSD_MAXIMIZED : 0;
+ }
+ break;
+ case NS_THEME_WINDOW_BUTTON_CLOSE:
+ case NS_THEME_WINDOW_BUTTON_MINIMIZE:
+ case NS_THEME_WINDOW_BUTTON_MAXIMIZE:
+ case NS_THEME_WINDOW_BUTTON_RESTORE:
+ aGtkWidgetType = MOZ_GTK_HEADER_BAR_BUTTON;
+ break;
case NS_THEME_GTK_WINDOW_DECORATION:
{
nsWindow* window = static_cast<nsWindow*>(aFrame->GetNearestWidget());
if (window && !window->UseSolidCSD()) {
aGtkWidgetType = MOZ_GTK_WINDOW_DECORATION;
} else {
aGtkWidgetType = MOZ_GTK_WINDOW_DECORATION_SOLID;
}
@@ -1605,16 +1619,20 @@ nsNativeThemeGTK::GetMinimumWidgetSize(n
case NS_THEME_CHECKBOX_CONTAINER:
case NS_THEME_RADIO_CONTAINER:
case NS_THEME_CHECKBOX_LABEL:
case NS_THEME_RADIO_LABEL:
case NS_THEME_BUTTON:
case NS_THEME_MENULIST:
case NS_THEME_TOOLBARBUTTON:
case NS_THEME_TREEHEADERCELL:
+ case NS_THEME_WINDOW_BUTTON_CLOSE:
+ case NS_THEME_WINDOW_BUTTON_MINIMIZE:
+ case NS_THEME_WINDOW_BUTTON_MAXIMIZE:
+ case NS_THEME_WINDOW_BUTTON_RESTORE:
{
if (aWidgetType == NS_THEME_MENULIST) {
// Include the arrow size.
moz_gtk_get_arrow_size(MOZ_GTK_DROPDOWN,
&aResult->width, &aResult->height);
}
// else the minimum size is missing consideration of container
// descendants; the value returned here will not be helpful, but the
@@ -1872,16 +1890,27 @@ nsNativeThemeGTK::ThemeSupportsWidget(ns
case NS_THEME_WINDOW:
case NS_THEME_DIALOG:
#if (MOZ_WIDGET_GTK == 3)
case NS_THEME_GTK_INFO_BAR:
case NS_THEME_GTK_WINDOW_DECORATION:
#endif
return !IsWidgetStyled(aPresContext, aFrame, aWidgetType);
+ case NS_THEME_WINDOW_BUTTON_CLOSE:
+ case NS_THEME_WINDOW_BUTTON_MINIMIZE:
+ case NS_THEME_WINDOW_BUTTON_MAXIMIZE:
+ case NS_THEME_WINDOW_BUTTON_RESTORE:
+ case NS_THEME_WINDOW_TITLEBAR:
+ case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED:
+ // GtkHeaderBar is available on GTK 3.10+, which is used for styling
+ // title bars and title buttons.
+ return gtk_check_version(3, 10, 0) == nullptr &&
+ !IsWidgetStyled(aPresContext, aFrame, aWidgetType);
+
case NS_THEME_MENULIST_BUTTON:
if (aFrame && aFrame->GetWritingMode().IsVertical()) {
return false;
}
// "Native" dropdown buttons cause padding and margin problems, but only
// in HTML so allow them in XUL.
return (!aFrame || IsFrameContentNodeInNamespace(aFrame, kNameSpaceID_XUL)) &&
!IsWidgetStyled(aPresContext, aFrame, aWidgetType);