--- a/gfx/src/nsThemeConstants.h
+++ b/gfx/src/nsThemeConstants.h
@@ -292,8 +292,9 @@
#define NS_THEME_MAC_VIBRANCY_DARK 244
#define NS_THEME_MAC_DISCLOSURE_BUTTON_OPEN 245
#define NS_THEME_MAC_DISCLOSURE_BUTTON_CLOSED 246
#define NS_THEME_GTK_INFO_BAR 247
#define NS_THEME_MAC_SOURCE_LIST 248
#define NS_THEME_MAC_SOURCE_LIST_SELECTION 249
#define NS_THEME_MAC_ACTIVE_SOURCE_LIST_SELECTION 250
+#define NS_THEME_GTK_WINDOW_DECORATION 251
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -68,16 +68,17 @@ CSS_KEY(-moz-fixed, _moz_fixed)
CSS_KEY(-moz-grabbing, _moz_grabbing)
CSS_KEY(-moz-grab, _moz_grab)
CSS_KEY(-moz-grid-group, _moz_grid_group)
CSS_KEY(-moz-grid-line, _moz_grid_line)
CSS_KEY(-moz-grid, _moz_grid)
CSS_KEY(-moz-groupbox, _moz_groupbox)
CSS_KEY(-moz-gtk-info-bar, _moz_gtk_info_bar)
CSS_KEY(-moz-gtk-info-bar-text, _moz_gtk_info_bar_text)
+CSS_KEY(-moz-gtk-window-decoration, _moz_gtk_window_decoration)
CSS_KEY(-moz-hidden-unscrollable, _moz_hidden_unscrollable)
CSS_KEY(-moz-hyperlinktext, _moz_hyperlinktext)
CSS_KEY(-moz-html-cellhighlight, _moz_html_cellhighlight)
CSS_KEY(-moz-html-cellhighlighttext, _moz_html_cellhighlighttext)
CSS_KEY(-moz-image-rect, _moz_image_rect)
CSS_KEY(-moz-info, _moz_info)
CSS_KEY(-moz-inline-box, _moz_inline_box)
CSS_KEY(-moz-inline-grid, _moz_inline_grid)
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -863,16 +863,17 @@ const KTableEntry nsCSSProps::kMozAppear
{ eCSSKeyword__moz_window_button_box, NS_THEME_WINDOW_BUTTON_BOX },
{ eCSSKeyword__moz_window_button_box_maximized, NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED },
{ eCSSKeyword__moz_win_exclude_glass, NS_THEME_WIN_EXCLUDE_GLASS },
{ eCSSKeyword__moz_mac_vibrancy_light, NS_THEME_MAC_VIBRANCY_LIGHT },
{ eCSSKeyword__moz_mac_vibrancy_dark, NS_THEME_MAC_VIBRANCY_DARK },
{ eCSSKeyword__moz_mac_disclosure_button_open, NS_THEME_MAC_DISCLOSURE_BUTTON_OPEN },
{ eCSSKeyword__moz_mac_disclosure_button_closed, NS_THEME_MAC_DISCLOSURE_BUTTON_CLOSED },
{ eCSSKeyword__moz_gtk_info_bar, NS_THEME_GTK_INFO_BAR },
+ { eCSSKeyword__moz_gtk_window_decoration, NS_THEME_GTK_WINDOW_DECORATION },
{ eCSSKeyword__moz_mac_source_list, NS_THEME_MAC_SOURCE_LIST },
{ eCSSKeyword__moz_mac_source_list_selection, NS_THEME_MAC_SOURCE_LIST_SELECTION },
{ eCSSKeyword__moz_mac_active_source_list_selection, NS_THEME_MAC_ACTIVE_SOURCE_LIST_SELECTION },
{ eCSSKeyword_UNKNOWN, -1 }
};
const KTableEntry nsCSSProps::kBackfaceVisibilityKTable[] = {
{ eCSSKeyword_visible, NS_STYLE_BACKFACE_VISIBILITY_VISIBLE },
--- a/widget/gtk/WidgetStyleCache.cpp
+++ b/widget/gtk/WidgetStyleCache.cpp
@@ -21,20 +21,31 @@ static GtkWidget* sWidgetStorage[MOZ_GTK
static GtkStyleContext* sStyleStorage[MOZ_GTK_WIDGET_NODE_COUNT];
static GtkStyleContext*
GetWidgetRootStyle(WidgetNodeType aNodeType);
static GtkStyleContext*
GetCssNodeStyleInternal(WidgetNodeType aNodeType);
static GtkWidget*
-CreateWindowWidget()
+CreateWindowWidget(WidgetNodeType type)
{
GtkWidget *widget = gtk_window_new(GTK_WINDOW_POPUP);
gtk_widget_set_name(widget, "MozillaGtkWidget");
+ GtkStyleContext* style = gtk_widget_get_style_context(widget);
+ switch (type) {
+ case MOZ_GTK_WINDOW_CSD:
+ gtk_style_context_add_class(style, "csd");
+ break;
+ case MOZ_GTK_WINDOW_SOLID_CSD:
+ gtk_style_context_add_class(style, "solid-csd");
+ break;
+ default:
+ break;
+ }
return widget;
}
static GtkWidget*
CreateWindowContainerWidget()
{
GtkWidget *widget = gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_WINDOW)), widget);
@@ -96,17 +107,17 @@ CreateProgressWidget()
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();
+ 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*
CreateExpanderWidget()
{
@@ -583,17 +594,19 @@ CreateHeaderBarButton(WidgetNodeType aWi
return widget;
}
static GtkWidget*
CreateWidget(WidgetNodeType aWidgetType)
{
switch (aWidgetType) {
case MOZ_GTK_WINDOW:
- return CreateWindowWidget();
+ case MOZ_GTK_WINDOW_CSD:
+ case MOZ_GTK_WINDOW_SOLID_CSD:
+ return CreateWindowWidget(aWidgetType);
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();
@@ -1088,16 +1101,24 @@ GetCssNodeStyleInternal(WidgetNodeType a
case MOZ_GTK_NOTEBOOK_HEADER:
case MOZ_GTK_TABPANELS:
case MOZ_GTK_TAB_SCROLLARROW:
{
// TODO - create from CSS node
GtkWidget* widget = GetWidget(MOZ_GTK_NOTEBOOK);
return gtk_widget_get_style_context(widget);
}
+ case MOZ_GTK_WINDOW_DECORATION:
+ style = CreateChildCSSNode("decoration",
+ MOZ_GTK_WINDOW_CSD);
+ break;
+ case MOZ_GTK_WINDOW_DECORATION_SOLID:
+ style = CreateChildCSSNode("decoration",
+ MOZ_GTK_WINDOW_SOLID_CSD);
+ break;
default:
return GetWidgetRootStyle(aNodeType);
}
MOZ_ASSERT(style, "missing style context for node type");
sStyleStorage[aNodeType] = style;
return style;
}
--- a/widget/gtk/gtk3drawing.cpp
+++ b/widget/gtk/gtk3drawing.cpp
@@ -34,19 +34,35 @@ static ScrollbarGTKMetrics sScrollbarMet
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);
+static void
+moz_gtk_add_style_margin(GtkStyleContext* style,
+ gint* left, gint* top, gint* right, gint* bottom);
+static void
+moz_gtk_add_style_border(GtkStyleContext* style,
+ gint* left, gint* top, gint* right, gint* bottom);
+static void
+moz_gtk_add_style_padding(GtkStyleContext* style,
+ gint* left, gint* top, gint* right, gint* bottom);
+static void moz_gtk_add_margin_border_padding(GtkStyleContext *style,
+ gint* left, gint* top,
+ gint* right, gint* bottom);
+static void moz_gtk_add_border_padding(GtkStyleContext *style,
+ gint* left, gint* top,
+ gint* right, gint* bottom);
static GtkBorder
GetMarginBorderPadding(GtkStyleContext* aStyle);
+
// 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
// adjusted to match GTK behavior. Although GTK sets insensitive and focus
// flags in the generic GtkWidget base class, GTK adds prelight and active
// flags only to widgets that are expected to demonstrate prelight or active
// states. This contrasts with HTML where any element may have :active and
// :hover states, and so Gecko's GtkStateFlags do not necessarily map to GTK
@@ -235,16 +251,56 @@ moz_gtk_splitter_get_metrics(gint orient
} else {
style = ClaimStyleContext(MOZ_GTK_SPLITTER_VERTICAL);
}
gtk_style_context_get_style(style, "handle_size", size, NULL);
ReleaseStyleContext(style);
return MOZ_GTK_SUCCESS;
}
+void
+moz_gtk_get_window_border(gint* top, gint* right, gint* bottom, gint* left)
+{
+ MOZ_ASSERT(gtk_check_version(3, 20, 0) == nullptr,
+ "Window decorations are only supported on GTK 3.20+.");
+
+ GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_WINDOW);
+
+ *top = *right = *bottom = *left = 0;
+ moz_gtk_add_border_padding(style, left, top, right, bottom);
+ GtkBorder windowMargin;
+ gtk_style_context_get_margin(style, GTK_STATE_FLAG_NORMAL, &windowMargin);
+
+ ReleaseStyleContext(style);
+
+ style = ClaimStyleContext(MOZ_GTK_WINDOW_DECORATION);
+
+ // Available on GTK 3.20+.
+ static auto sGtkRenderBackgroundGetClip =
+ (void (*)(GtkStyleContext*, gdouble, gdouble, gdouble, gdouble, GdkRectangle*))
+ dlsym(RTLD_DEFAULT, "gtk_render_background_get_clip");
+
+ GdkRectangle shadowClip;
+ sGtkRenderBackgroundGetClip(style, 0, 0, 0, 0, &shadowClip);
+ ReleaseStyleContext(style);
+
+ // Transfer returned inset rectangle to GtkBorder
+ GtkBorder shadowBorder = {
+ static_cast<gint16>(-shadowClip.x), // left
+ static_cast<gint16>(shadowClip.width + shadowClip.x), // right
+ static_cast<gint16>(-shadowClip.y), // top
+ static_cast<gint16>(shadowClip.height + shadowClip.y), // bottom
+ };
+
+ *left += MAX(windowMargin.left, shadowBorder.left);
+ *right += MAX(windowMargin.right, shadowBorder.right);
+ *top += MAX(windowMargin.top, shadowBorder.top);
+ *bottom += MAX(windowMargin.bottom, shadowBorder.bottom);
+}
+
static gint
moz_gtk_window_paint(cairo_t *cr, GdkRectangle* rect,
GtkTextDirection direction)
{
GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_WINDOW, direction);
gtk_style_context_save(style);
gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND);
@@ -252,16 +308,55 @@ moz_gtk_window_paint(cairo_t *cr, GdkRec
gtk_style_context_restore(style);
ReleaseStyleContext(style);
return MOZ_GTK_SUCCESS;
}
static gint
+moz_gtk_window_decoration_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkTextDirection direction)
+{
+ gint top, right, bottom, left;
+ moz_gtk_get_window_border(&top, &right, &bottom, &left);
+
+ GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_WINDOW_DECORATION,
+ direction);
+
+ rect->x += left;
+ rect->y += top;
+ rect->width -= left + right;
+ rect->height -= top + bottom;
+
+ 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 gint
+moz_gtk_window_decoration_solid_paint(cairo_t *cr, GdkRectangle* rect,
+ GtkTextDirection direction)
+{
+ GtkStyleContext* style = ClaimStyleContext(MOZ_GTK_WINDOW_DECORATION_SOLID,
+ 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;
+
+}
+
+static gint
moz_gtk_button_paint(cairo_t *cr, GdkRectangle* rect,
GtkWidgetState* state,
GtkReliefStyle relief, GtkWidget* widget,
GtkTextDirection direction)
{
GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
GtkStyleContext* style = gtk_widget_get_style_context(widget);
gint x = rect->x, y=rect->y, width=rect->width, height=rect->height;
@@ -2310,16 +2405,28 @@ moz_gtk_get_widget_border(WidgetNodeType
GtkStyleContext* labelStyle = ClaimStyleContext(MOZ_GTK_TOOLTIP_BOX_LABEL);
moz_gtk_add_margin_border_padding(labelStyle,
left, top, right, bottom);
ReleaseStyleContext(labelStyle);
return MOZ_GTK_SUCCESS;
}
+ case MOZ_GTK_WINDOW_DECORATION:
+ {
+ moz_gtk_get_window_border(top, right, bottom, left);
+ return MOZ_GTK_SUCCESS;
+ }
+ case MOZ_GTK_WINDOW_DECORATION_SOLID:
+ {
+ style = ClaimStyleContext(MOZ_GTK_WINDOW_DECORATION_SOLID);
+ moz_gtk_add_border_padding(style, left, top, right, bottom);
+ ReleaseStyleContext(style);
+ return MOZ_GTK_SUCCESS;
+ }
case MOZ_GTK_HEADER_BAR:
case MOZ_GTK_HEADER_BAR_MAXIMIZED:
{
style = ClaimStyleContext(widget);
moz_gtk_add_border_padding(style, left, top, right, bottom);
ReleaseStyleContext(style);
return MOZ_GTK_SUCCESS;
}
@@ -3016,16 +3123,22 @@ moz_gtk_widget_paint(WidgetNodeType widg
return moz_gtk_vpaned_paint(cr, rect, state);
break;
case MOZ_GTK_SPLITTER_VERTICAL:
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_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;
case MOZ_GTK_INFO_BAR:
return moz_gtk_info_bar_paint(cr, rect, state);
break;
case MOZ_GTK_HEADER_BAR:
case MOZ_GTK_HEADER_BAR_MAXIMIZED:
return moz_gtk_header_bar_paint(widget, cr, rect, state);
break;
default:
--- a/widget/gtk/gtkdrawing.h
+++ b/widget/gtk/gtkdrawing.h
@@ -265,16 +265,24 @@ typedef enum {
/* Paints a GtkVPaned separator */
MOZ_GTK_SPLITTER_SEPARATOR_HORIZONTAL,
/* Paints a GtkHPaned separator */
MOZ_GTK_SPLITTER_SEPARATOR_VERTICAL,
/* Paints the background of a window, dialog or page. */
MOZ_GTK_WINDOW,
/* Window container for all widgets */
MOZ_GTK_WINDOW_CONTAINER,
+ /* Window with the 'csd' style class. */
+ MOZ_GTK_WINDOW_CSD,
+ /* Window with the 'csd' style class. */
+ MOZ_GTK_WINDOW_SOLID_CSD,
+ /* Client-side window decoration node. Available on GTK 3.20+. */
+ MOZ_GTK_WINDOW_DECORATION,
+ /* Solid client-side window decoration node. Available on GTK 3.20+. */
+ MOZ_GTK_WINDOW_DECORATION_SOLID,
/* Paints a GtkInfoBar, for notifications. */
MOZ_GTK_INFO_BAR,
/* Used for widget tree construction. */
MOZ_GTK_COMBOBOX,
/* Paints a GtkComboBox button widget. */
MOZ_GTK_COMBOBOX_BUTTON,
/* Paints a GtkComboBox arrow widget. */
MOZ_GTK_COMBOBOX_ARROW,
@@ -546,16 +554,25 @@ gint moz_gtk_get_menu_separator_height(g
* Get the desired size of a splitter
* orientation: [IN] GTK_ORIENTATION_HORIZONTAL or GTK_ORIENTATION_VERTICAL
* size: [OUT] width or height of the splitter handle
*
* returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
*/
gint moz_gtk_splitter_get_metrics(gint orientation, gint* size);
+#if (MOZ_WIDGET_GTK == 3)
+/**
+ * Gets the margins to be used for window decorations, typically the extra space
+ * required to draw a drop shadow (obtained from gtk_render_background_get_clip).
+ * Only available on GTK 3.20+.
+ */
+void moz_gtk_get_window_border(gint* top, gint* right, gint* bottom, gint* left);
+#endif
+
/**
* Get the YTHICKNESS of a tab (notebook extension).
*/
gint
moz_gtk_get_tab_thickness(WidgetNodeType aNodeType);
#if (MOZ_WIDGET_GTK == 2)
#ifdef __cplusplus
--- a/widget/gtk/nsNativeThemeGTK.cpp
+++ b/widget/gtk/nsNativeThemeGTK.cpp
@@ -19,16 +19,17 @@
#include "nsGfxCIID.h"
#include "nsTransform2D.h"
#include "nsMenuFrame.h"
#include "prlink.h"
#include "nsIDOMHTMLInputElement.h"
#include "nsRenderingContext.h"
#include "nsGkAtoms.h"
#include "nsAttrValueInlines.h"
+#include "nsWindow.h"
#include "mozilla/EventStates.h"
#include "mozilla/Services.h"
#include <gdk/gdkprivate.h>
#include <gtk/gtk.h>
#include "gfxContext.h"
@@ -693,16 +694,26 @@ nsNativeThemeGTK::GetGtkWidgetAndState(u
break;
case NS_THEME_RADIOMENUITEM:
aGtkWidgetType = MOZ_GTK_RADIOMENUITEM;
break;
case NS_THEME_WINDOW:
case NS_THEME_DIALOG:
aGtkWidgetType = MOZ_GTK_WINDOW;
break;
+ case NS_THEME_GTK_WINDOW_DECORATION:
+ {
+ nsWindow* window = static_cast<nsWindow*>(aFrame->GetNearestWidget());
+ if (window && window->IsComposited()) {
+ aGtkWidgetType = MOZ_GTK_WINDOW_DECORATION;
+ } else {
+ aGtkWidgetType = MOZ_GTK_WINDOW_DECORATION_SOLID;
+ }
+ break;
+ }
case NS_THEME_GTK_INFO_BAR:
aGtkWidgetType = MOZ_GTK_INFO_BAR;
break;
case NS_THEME_WINDOW_TITLEBAR:
aGtkWidgetType = MOZ_GTK_HEADER_BAR;
break;
case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED:
aGtkWidgetType = MOZ_GTK_HEADER_BAR_MAXIMIZED;
@@ -1898,16 +1909,17 @@ nsNativeThemeGTK::ThemeSupportsWidget(ns
case NS_THEME_MENUSEPARATOR:
case NS_THEME_CHECKMENUITEM:
case NS_THEME_RADIOMENUITEM:
case NS_THEME_SPLITTER:
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:
@@ -1995,12 +2007,19 @@ nsNativeThemeGTK::GetWidgetTransparency(
// Tooltips use gtk_paint_flat_box() on Gtk2
// but are shaped on Gtk3
case NS_THEME_TOOLTIP:
#if (MOZ_WIDGET_GTK == 2)
return eOpaque;
#else
return eTransparent;
#endif
+ case NS_THEME_GTK_WINDOW_DECORATION:
+ {
+ nsWindow* window = static_cast<nsWindow*>(aFrame->GetNearestWidget());
+ if (window)
+ return window->IsComposited() ? eTransparent : eOpaque;
+ return eOpaque;
+ }
}
return eUnknownTransparency;
}
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -120,16 +120,17 @@ public:
double aHeight,
bool aRepaint) override;
virtual void Resize (double aX,
double aY,
double aWidth,
double aHeight,
bool aRepaint) override;
virtual bool IsEnabled() const override;
+ bool IsComposited() const;
void SetZIndex(int32_t aZIndex) override;
virtual void SetSizeMode(nsSizeMode aMode) override;
virtual void Enable(bool aState) override;
virtual nsresult SetFocus(bool aRaise = false) override;
virtual LayoutDeviceIntRect GetScreenBounds() override;
virtual LayoutDeviceIntRect GetClientBounds() override;
virtual LayoutDeviceIntSize GetClientSize() override;
@@ -432,17 +433,16 @@ private:
CheckForRollup(0, 0, false, true);
}
bool GetDragInfo(mozilla::WidgetMouseEvent* aMouseEvent,
GdkWindow** aWindow, gint* aButton,
gint* aRootX, gint* aRootY);
void ClearCachedResources();
nsIWidgetListener* GetListener();
- bool IsComposited() const;
GtkWidget *mShell;
MozContainer *mContainer;
GdkWindow *mGdkWindow;
uint32_t mHasMappedToplevel : 1,
mIsFullyObscured : 1,