--- a/gfx/src/nsThemeConstants.h
+++ b/gfx/src/nsThemeConstants.h
@@ -287,8 +287,9 @@
#define NS_THEME_MAC_VIBRANCY_LIGHT 243
#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_GTK_WINDOW_DECORATION 249
--- 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
@@ -862,16 +862,17 @@ const KTableEntry nsCSSProps::kAppearanc
{ 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_UNKNOWN, -1 }
};
const KTableEntry nsCSSProps::kBackfaceVisibilityKTable[] = {
{ eCSSKeyword_visible, NS_STYLE_BACKFACE_VISIBILITY_VISIBLE },
{ eCSSKeyword_hidden, NS_STYLE_BACKFACE_VISIBILITY_HIDDEN },
{ eCSSKeyword_UNKNOWN, -1 }
--- a/widget/gtk/WidgetStyleCache.cpp
+++ b/widget/gtk/WidgetStyleCache.cpp
@@ -20,21 +20,32 @@ static GtkStyleContext* sStyleStorage[MO
static bool sStyleContextNeedsRestore;
#ifdef DEBUG
static GtkStyleContext* sCurrentStyleContext;
#endif
static GtkStyleContext*
GetCssNodeStyleInternal(WidgetNodeType aNodeType);
static GtkWidget*
-CreateWindowWidget()
+CreateWindowWidget(WidgetNodeType type)
{
GtkWidget *widget = gtk_window_new(GTK_WINDOW_POPUP);
gtk_widget_realize(widget);
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);
@@ -105,28 +116,30 @@ 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*
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();
@@ -259,16 +272,24 @@ GetCssNodeStyleInternal(WidgetNodeType a
/* 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_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;
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;
default:
// TODO - create style from style path
GtkWidget* widget = GetWidget(aNodeType);
--- a/widget/gtk/gtk3drawing.cpp
+++ b/widget/gtk/gtk3drawing.cpp
@@ -720,16 +720,40 @@ moz_gtk_splitter_get_metrics(gint orient
} else {
ensure_vpaned_widget();
gtk_style_context_get_style(gtk_widget_get_style_context(gVPanedWidget),
"handle_size", size, NULL);
}
return MOZ_GTK_SUCCESS;
}
+void
+moz_gtk_get_window_decoration_extents(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_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 clip;
+ sGtkRenderBackgroundGetClip(style, 0, 0, 0, 0, &clip);
+
+ *top = -clip.y;
+ *right = clip.width + clip.x;
+ *bottom = clip.height + clip.y;
+ *left = -clip.x;
+
+ ReleaseStyleContext(style);
+}
+
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);
@@ -737,16 +761,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_decoration_extents(&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;
@@ -2544,16 +2607,31 @@ moz_gtk_add_style_padding(GtkStyleContex
gtk_style_context_get_padding(style, GTK_STATE_FLAG_NORMAL, &padding);
*left += padding.left;
*right += padding.right;
*top += padding.top;
*bottom += padding.bottom;
}
+
+static void
+moz_gtk_add_style_margin(GtkStyleContext* style,
+ gint* left, gint* top, gint* right, gint* bottom)
+{
+ GtkBorder margin;
+
+ gtk_style_context_get_margin(style, GTK_STATE_FLAG_NORMAL, &margin);
+
+ *left += margin.left;
+ *right += margin.right;
+ *top += margin.top;
+ *bottom += margin.bottom;
+}
+
gint
moz_gtk_get_widget_border(WidgetNodeType widget, gint* left, gint* top,
gint* right, gint* bottom, GtkTextDirection direction,
gboolean inhtml)
{
GtkWidget* w;
GtkStyleContext* style;
*left = *top = *right = *bottom = 0;
@@ -2745,16 +2823,36 @@ 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_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);
+ return MOZ_GTK_SUCCESS;
+ }
+ case MOZ_GTK_WINDOW_DECORATION_SOLID:
+ {
+ style = ClaimStyleContext(MOZ_GTK_WINDOW_DECORATION_SOLID);
+ 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;
+ }
+
/* These widgets have no borders, since they are not containers. */
case MOZ_GTK_CHECKBUTTON_LABEL:
case MOZ_GTK_RADIOBUTTON_LABEL:
case MOZ_GTK_SPLITTER_HORIZONTAL:
case MOZ_GTK_SPLITTER_VERTICAL:
case MOZ_GTK_CHECKBUTTON:
case MOZ_GTK_RADIOBUTTON:
case MOZ_GTK_SCROLLBAR_BUTTON:
@@ -3262,16 +3360,22 @@ 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_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);
}
return MOZ_GTK_UNKNOWN_WIDGET;
}
GtkWidget* moz_gtk_get_scrollbar_widget(void)
--- a/widget/gtk/gtkdrawing.h
+++ b/widget/gtk/gtkdrawing.h
@@ -197,16 +197,24 @@ typedef enum {
/* Paints a GtkVPaned separator */
MOZ_GTK_SPLITTER_HORIZONTAL,
/* Paints a GtkHPaned separator */
MOZ_GTK_SPLITTER_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,
MOZ_GTK_WIDGET_NODE_COUNT
} WidgetNodeType;
/*** General library functions ***/
/**
@@ -458,16 +466,24 @@ gint moz_gtk_get_menu_separator_height(g
* 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);
/**
+ * 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_decoration_extents(gint* top, gint* right, gint* bottom,
+ gint* left);
+
+/**
* Retrieve an actual GTK scrollbar widget for style analysis. It will not
* be modified.
*/
GtkWidget* moz_gtk_get_scrollbar_widget(void);
/**
* Get the YTHICKNESS of a tab (notebook extension).
*/
--- 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"
@@ -700,16 +701,26 @@ 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_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;
+ }
+ break;
+ }
default:
return false;
}
return true;
}
#if (MOZ_WIDGET_GTK == 2)
@@ -1857,16 +1868,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_MENULIST_BUTTON:
if (aFrame && aFrame->GetWritingMode().IsVertical()) {
return false;
}
// "Native" dropdown buttons cause padding and margin problems, but only
@@ -1943,12 +1955,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->UseSolidCSD() ? eOpaque : eTransparent;
+ return eOpaque;
+ }
}
return eUnknownTransparency;
}
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -6839,16 +6839,39 @@ nsWindow::ClearCachedResources()
for (GList* list = children; list; list = list->next) {
nsWindow* window = get_window_for_gdk_window(GDK_WINDOW(list->data));
if (window) {
window->ClearCachedResources();
}
}
}
+bool
+nsWindow::HasARGBVisual() const
+{
+ if (!mGdkWindow) {
+ NS_WARNING("nsWindow::HasARGBVisual called before realization!");
+ return false;
+ }
+ return gdk_window_get_visual(mGdkWindow)
+ == gdk_screen_get_rgba_visual(gdk_screen_get_default());
+}
+
+bool
+nsWindow::IsComposited() const
+{
+ return gdk_screen_is_composited(gdk_screen_get_default());
+}
+
+bool
+nsWindow::UseSolidCSD() const
+{
+ return !HasARGBVisual() || !IsComposited();
+}
+
gint
nsWindow::GdkScaleFactor()
{
#if (MOZ_WIDGET_GTK >= 3)
// Available as of GTK 3.10+
static auto sGdkWindowGetScaleFactorPtr = (gint (*)(GdkWindow*))
dlsym(RTLD_DEFAULT, "gdk_window_get_scale_factor");
if (sGdkWindowGetScaleFactorPtr && mGdkWindow)
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -348,16 +348,23 @@ public:
virtual nsresult SynthesizeNativeTouchPoint(uint32_t aPointerId,
TouchPointerState aPointerState,
LayoutDeviceIntPoint aPoint,
double aPointerPressure,
uint32_t aPointerOrientation,
nsIObserver* aObserver) override;
#endif
+ bool HasARGBVisual() const;
+ bool IsComposited() const;
+
+ // If true, 'solid' client side decorations (without an alpha channel)
+ // should be used if available.
+ bool UseSolidCSD() const;
+
// HiDPI scale conversion
gint GdkScaleFactor();
// To GDK
gint DevicePixelsToGdkCoordRoundUp(int pixels);
gint DevicePixelsToGdkCoordRoundDown(int pixels);
GdkPoint DevicePixelsToGdkPointRoundDown(LayoutDeviceIntPoint point);
GdkRectangle DevicePixelsToGdkSizeRoundUp(LayoutDeviceIntSize pixelSize);