Bug 1560702 - Improve hit boxes of titlebar buttons. r=stransky,desktop-theme-reviewers,dao

In order to do it, expose the button padding to CSS via env(), and make
the buttons just use the regular drawing.

This slightly changes the padding to the end of the titlebar to match
one half of the inter-button spacing, rather that however much padding
the headerbar has.

We could improve on this slightly by also exposing the headerbar padding
and applying that to the last button, but that's not terribly easy to do
due to us supporting re-ordering of the titlebar buttons, and reversing
their placement, so it'd involve some rather hacky CSS. Not impossible,
but not trivial, and this looks good enough IMO.

Differential Revision: https://phabricator.services.mozilla.com/D202616
This commit is contained in:
Emilio Cobos Álvarez 2024-02-27 10:28:56 +00:00
parent bd5da96c6d
commit 7875df041f
14 changed files with 126 additions and 180 deletions

View file

@ -214,64 +214,70 @@
* can swallow those events. */
.titlebar-buttonbox {
z-index: 1;
align-items: center;
align-items: stretch;
}
/* When using lightweight themes, use our own buttons since native ones might
* assume a native background in order to be visible. */
.titlebar-button:-moz-lwtheme {
appearance: none;
border-radius: 100%;
@media (-moz-gtk-csd-reversed-placement) {
.titlebar-buttonbox-container {
order: -1;
}
}
&:hover {
.titlebar-button {
appearance: none;
align-items: center;
padding: 0;
padding-inline: calc(env(-moz-gtk-csd-titlebar-button-spacing) / 2);
> .toolbarbutton-icon {
appearance: auto;
}
/* When using lightweight themes, use our own buttons since native ones might
* assume a native background in order to be visible. */
&:-moz-lwtheme {
padding-inline: 3px;
> .toolbarbutton-icon {
appearance: none;
border-radius: 100%;
background-position: center center;
background-repeat: no-repeat;
-moz-context-properties: stroke;
stroke: currentColor;
/* Roughly the Adwaita size */
width: 24px;
height: 24px;
}
}
&:hover > .toolbarbutton-icon {
background-color: color-mix(in srgb, currentColor 12%, transparent);
}
&:hover:active {
&:hover:active > .toolbarbutton-icon {
background-color: color-mix(in srgb, currentColor 20%, transparent);
}
&:focus-visible {
&:focus-visible > .toolbarbutton-icon {
outline: var(--focus-outline);
outline-offset: var(--focus-outline-inset);
}
> .toolbarbutton-icon {
padding: 6px;
-moz-context-properties: stroke;
stroke: currentColor;
}
}
/* Render titlebar command buttons according to system config.
* Use full scale icons here as the Gtk+ does. */
.titlebar-max {
appearance: auto;
-moz-default-appearance: -moz-window-button-maximize;
order: env(-moz-gtk-csd-maximize-button-position);
&:-moz-lwtheme {
list-style-image: url(chrome://browser/skin/window-controls/maximize.svg);
> .toolbarbutton-icon {
-moz-default-appearance: -moz-window-button-maximize;
background-image: url(chrome://browser/skin/window-controls/maximize.svg);
}
}
.titlebar-restore {
appearance: auto;
-moz-default-appearance: -moz-window-button-restore;
order: env(-moz-gtk-csd-maximize-button-position);
&:-moz-lwtheme {
list-style-image: url(chrome://browser/skin/window-controls/restore.svg);
}
}
@media not (-moz-gtk-csd-minimize-button) {
.titlebar-min {
display: none;
&:-moz-lwtheme {
list-style-image: url(chrome://browser/skin/window-controls/restore.svg);
}
> .toolbarbutton-icon {
-moz-default-appearance: -moz-window-button-restore;
background-image: url(chrome://browser/skin/window-controls/restore.svg);
}
}
@ -283,21 +289,20 @@
}
.titlebar-close {
appearance: auto;
-moz-default-appearance: -moz-window-button-close;
order: env(-moz-gtk-csd-close-button-position);
&:-moz-lwtheme {
list-style-image: url(chrome://browser/skin/window-controls/close.svg);
> .toolbarbutton-icon {
-moz-default-appearance: -moz-window-button-close;
background-image: url(chrome://browser/skin/window-controls/close.svg);
}
&:hover {
background-color: #d70022;
color: white;
}
&:hover > .toolbarbutton-icon {
background-color: #d70022;
color: white;
}
&:hover:active {
background-color: #ff0039;
}
&:hover:active > .toolbarbutton-icon {
background-color: #ff0039;
}
@media not (-moz-gtk-csd-close-button) {
@ -306,21 +311,14 @@
}
.titlebar-min {
appearance: auto;
-moz-default-appearance: -moz-window-button-minimize;
order: env(-moz-gtk-csd-minimize-button-position);
&:-moz-lwtheme {
list-style-image: url(chrome://browser/skin/window-controls/minimize.svg);
> .toolbarbutton-icon {
-moz-default-appearance: -moz-window-button-minimize;
background-image: url(chrome://browser/skin/window-controls/minimize.svg);
}
@media not (-moz-gtk-csd-minimize-button) {
display: none;
}
}
@media (-moz-gtk-csd-reversed-placement) {
.titlebar-buttonbox-container {
order: -1;
}
}

View file

@ -555,15 +555,16 @@ void nsImageFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) {
//
// TODO(emilio): We might want to do the same for regular list-style-image or
// even simple content: url() changes.
if (mKind == Kind::XULImage) {
if (!mContent->AsElement()->HasNonEmptyAttr(nsGkAtoms::src) && aOldStyle &&
if (mKind == Kind::XULImage && aOldStyle) {
if (!mContent->AsElement()->HasNonEmptyAttr(nsGkAtoms::src) &&
aOldStyle->StyleList()->mListStyleImage !=
StyleList()->mListStyleImage) {
UpdateXULImage();
}
if (!mOwnedRequest && aOldStyle &&
aOldStyle->StyleDisplay()->EffectiveAppearance() !=
StyleDisplay()->EffectiveAppearance()) {
// If we have no image our intrinsic size might be themed. We need to
// update the size even if the effective appearance hasn't changed to
// deal correctly with theme changes.
if (!mOwnedRequest) {
UpdateIntrinsicSize();
}
}

View file

@ -122,7 +122,12 @@ macro_rules! lnf_int_variable {
}};
}
static CHROME_ENVIRONMENT_VARIABLES: [EnvironmentVariable; 7] = [
static CHROME_ENVIRONMENT_VARIABLES: [EnvironmentVariable; 8] = [
lnf_int_variable!(
atom!("-moz-gtk-csd-titlebar-button-spacing"),
TitlebarButtonSpacing,
int_pixels
),
lnf_int_variable!(
atom!("-moz-gtk-csd-titlebar-radius"),
TitlebarRadius,

View file

@ -289,6 +289,9 @@ class LookAndFeel {
/** GTK titlebar radius */
TitlebarRadius,
/** GTK button-to-button spacing in the inline axis */
TitlebarButtonSpacing,
/**
* Corresponding to dynamic-range.
* https://drafts.csswg.org/mediaqueries-5/#dynamic-range

View file

@ -644,10 +644,7 @@ static void CreateHeaderBarButtons() {
GtkWidget* headerBar = sWidgetStorage[MOZ_GTK_HEADER_BAR];
MOZ_ASSERT(headerBar, "We're missing header bar widget!");
gint buttonSpacing = 6;
g_object_get(headerBar, "spacing", &buttonSpacing, nullptr);
GtkWidget* buttonBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, buttonSpacing);
GtkWidget* buttonBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_container_add(GTK_CONTAINER(headerBar), buttonBox);
// We support only LTR headerbar layout for now.
gtk_style_context_add_class(gtk_widget_get_style_context(buttonBox),

View file

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -264,7 +264,6 @@ static void CalculateToolbarButtonMetrics(WidgetNodeType aAppearance,
gint iconWidth, iconHeight;
if (!gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &iconWidth, &iconHeight)) {
NS_WARNING("Failed to get Gtk+ icon size for titlebar button!");
// Use some reasonable fallback size
iconWidth = 16;
iconHeight = 16;
@ -292,37 +291,7 @@ static void CalculateToolbarButtonMetrics(WidgetNodeType aAppearance,
// Place icon at button center.
aMetrics->iconXPosition = (width - iconWidth) / 2;
aMetrics->iconYPosition = (height - iconHeight) / 2;
aMetrics->minSizeWithBorderMargin.width = width;
aMetrics->minSizeWithBorderMargin.height = height;
}
// We support LTR layout only here for now.
static void CalculateToolbarButtonSpacing(WidgetNodeType aAppearance,
ToolbarButtonGTKMetrics* aMetrics) {
GtkStyleContext* style = GetStyleContext(aAppearance);
gtk_style_context_get_margin(style, gtk_style_context_get_state(style),
&aMetrics->buttonMargin);
// Get titlebar spacing, a default one is 6 pixels (gtk/gtkheaderbar.c)
gint buttonSpacing = 6;
g_object_get(GetWidget(MOZ_GTK_HEADER_BAR), "spacing", &buttonSpacing,
nullptr);
// We apply spacing as a margin equally to both adjacent buttons.
buttonSpacing /= 2;
if (!aMetrics->firstButton) {
aMetrics->buttonMargin.left += buttonSpacing;
}
if (!aMetrics->lastButton) {
aMetrics->buttonMargin.right += buttonSpacing;
}
aMetrics->minSizeWithBorderMargin.width +=
aMetrics->buttonMargin.right + aMetrics->buttonMargin.left;
aMetrics->minSizeWithBorderMargin.height +=
aMetrics->buttonMargin.top + aMetrics->buttonMargin.bottom;
aMetrics->minSizeWithBorder = {width, height};
}
size_t GetGtkHeaderBarButtonLayout(Span<ButtonLayout> aButtonLayout,
@ -388,26 +357,14 @@ static void EnsureToolbarMetrics() {
memset(&sToolbarMetrics, 0, sizeof(sToolbarMetrics));
// Calculate titlebar button visibility and positions.
ButtonLayout aButtonLayout[TOOLBAR_BUTTONS];
ButtonLayout buttonLayout[TOOLBAR_BUTTONS];
size_t activeButtonNums =
GetGtkHeaderBarButtonLayout(Span(aButtonLayout), nullptr);
GetGtkHeaderBarButtonLayout(Span(buttonLayout), nullptr);
for (size_t i = 0; i < activeButtonNums; i++) {
int buttonIndex =
(aButtonLayout[i].mType - MOZ_GTK_HEADER_BAR_BUTTON_CLOSE);
ToolbarButtonGTKMetrics* metrics = sToolbarMetrics.button + buttonIndex;
metrics->visible = true;
// Mark first button
if (!i) {
metrics->firstButton = true;
}
// Mark last button.
if (i == (activeButtonNums - 1)) {
metrics->lastButton = true;
}
CalculateToolbarButtonMetrics(aButtonLayout[i].mType, metrics);
CalculateToolbarButtonSpacing(aButtonLayout[i].mType, metrics);
for (const auto& layout : Span(buttonLayout, activeButtonNums)) {
int buttonIndex = layout.mType - MOZ_GTK_HEADER_BAR_BUTTON_CLOSE;
ToolbarButtonGTKMetrics* metrics = &sToolbarMetrics.button[buttonIndex];
CalculateToolbarButtonMetrics(layout.mType, metrics);
}
sToolbarMetrics.initialized = true;
@ -506,26 +463,27 @@ static gint moz_gtk_button_paint(cairo_t* cr, const GdkRectangle* rect,
return MOZ_GTK_SUCCESS;
}
static gint moz_gtk_header_bar_button_paint(cairo_t* cr,
const GdkRectangle* aRect,
static gint moz_gtk_header_bar_button_paint(cairo_t* cr, GdkRectangle* aRect,
GtkWidgetState* state,
GtkReliefStyle relief,
WidgetNodeType aIconWidgetType,
GtkTextDirection direction) {
GdkRectangle rect = *aRect;
// We need to inset our calculated margin because it also
// contains titlebar button spacing.
const ToolbarButtonGTKMetrics* metrics = GetToolbarButtonMetrics(
aIconWidgetType == MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE_RESTORE
? MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE
: aIconWidgetType);
Inset(&rect, metrics->buttonMargin);
GtkWidget* buttonWidget = GetWidget(aIconWidgetType);
if (!buttonWidget) {
return MOZ_GTK_UNKNOWN_WIDGET;
}
moz_gtk_button_paint(cr, &rect, state, relief, buttonWidget, direction);
const ToolbarButtonGTKMetrics* metrics = GetToolbarButtonMetrics(
aIconWidgetType == MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE_RESTORE
? MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE
: aIconWidgetType);
// Vertically center and clamp the rect to the desired size.
if (aRect->height > metrics->minSizeWithBorder.height) {
gint diff = aRect->height - metrics->minSizeWithBorder.height;
aRect->y += diff / 2;
aRect->height = metrics->minSizeWithBorder.height;
}
moz_gtk_button_paint(cr, aRect, state, relief, buttonWidget, direction);
GtkWidget* iconWidget =
gtk_bin_get_child(GTK_BIN(GetWidget(aIconWidgetType)));
@ -544,8 +502,9 @@ static gint moz_gtk_header_bar_button_paint(cairo_t* cr,
gtk_style_context_set_state(style, state_flags);
/* This is available since Gtk+ 3.10 as well as GtkHeaderBar */
gtk_render_icon_surface(style, cr, surface, rect.x + metrics->iconXPosition,
rect.y + metrics->iconYPosition);
gtk_render_icon_surface(style, cr, surface,
aRect->x + metrics->iconXPosition,
aRect->y + metrics->iconYPosition);
gtk_style_context_restore(style);
}
@ -1700,22 +1659,6 @@ gint moz_gtk_get_widget_border(WidgetNodeType widget, gint* left, gint* top,
return MOZ_GTK_SUCCESS;
}
case MOZ_GTK_HEADER_BAR_BUTTON_BOX: {
style = GetStyleContext(MOZ_GTK_HEADER_BAR);
moz_gtk_add_border_padding(style, left, top, right, bottom);
*top = *bottom = 0;
bool leftButtonsPlacement = false;
GetGtkHeaderBarButtonLayout({}, &leftButtonsPlacement);
if (direction == GTK_TEXT_DIR_RTL) {
leftButtonsPlacement = !leftButtonsPlacement;
}
if (leftButtonsPlacement) {
*right = 0;
} else {
*left = 0;
}
return MOZ_GTK_SUCCESS;
}
/* These widgets have no borders, since they are not containers. */
case MOZ_GTK_SPLITTER_HORIZONTAL:
case MOZ_GTK_SPLITTER_VERTICAL:

View file

@ -76,13 +76,9 @@ typedef struct {
} ToggleGTKMetrics;
typedef struct {
MozGtkSize minSizeWithBorderMargin;
GtkBorder buttonMargin;
MozGtkSize minSizeWithBorder;
gint iconXPosition;
gint iconYPosition;
bool visible;
bool firstButton;
bool lastButton;
} ToolbarButtonGTKMetrics;
#define TOOLBAR_BUTTONS 3
@ -269,8 +265,6 @@ enum WidgetNodeType : int {
MOZ_GTK_HEADER_BAR,
/* Paints a GtkHeaderBar in maximized state */
MOZ_GTK_HEADER_BAR_MAXIMIZED,
/* Container for GtkHeaderBar buttons */
MOZ_GTK_HEADER_BAR_BUTTON_BOX,
/* Paints GtkHeaderBar title buttons.
* Keep the order here as MOZ_GTK_HEADER_BAR_BUTTON_* are processed
* as an array from MOZ_GTK_HEADER_BAR_BUTTON_CLOSE to the last one.

View file

@ -1031,6 +1031,11 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
aResult = EffectiveTheme().mTitlebarRadius;
break;
}
case IntID::TitlebarButtonSpacing: {
EnsureInit();
aResult = EffectiveTheme().mTitlebarButtonSpacing;
break;
}
case IntID::AllowOverlayScrollbarsOverlap: {
aResult = 1;
break;
@ -1972,6 +1977,10 @@ void nsLookAndFeel::PerThemeData::Init() {
mTitlebar = GetColorPair(style, GTK_STATE_FLAG_NORMAL);
mTitlebarInactive = GetColorPair(style, GTK_STATE_FLAG_BACKDROP);
mTitlebarRadius = IsSolidCSDStyleUsed() ? 0 : GetBorderRadius(style);
// Get titlebar spacing, a default one is 6 pixels (gtk/gtkheaderbar.c)
mTitlebarButtonSpacing = 6;
g_object_get(GetWidget(MOZ_GTK_HEADER_BAR), "spacing",
&mTitlebarButtonSpacing, nullptr);
}
// We special-case the header bar color in Adwaita, Yaru and Breeze to be the

View file

@ -137,6 +137,7 @@ class nsLookAndFeel final : public nsXPLookAndFeel {
float mCaretRatio = 0.0f;
int32_t mTitlebarRadius = 0;
int32_t mTitlebarButtonSpacing = 0;
char16_t mInvisibleCharacter = 0;
bool mMenuSupportsDrag = false;

View file

@ -191,6 +191,10 @@ bool nsNativeThemeGTK::GetGtkWidgetAndState(StyleAppearance aAppearance,
aAppearance == StyleAppearance::Toolbarbutton ||
aAppearance == StyleAppearance::Dualbutton ||
aAppearance == StyleAppearance::ToolbarbuttonDropdown ||
aAppearance == StyleAppearance::MozWindowButtonMinimize ||
aAppearance == StyleAppearance::MozWindowButtonRestore ||
aAppearance == StyleAppearance::MozWindowButtonMaximize ||
aAppearance == StyleAppearance::MozWindowButtonClose ||
aAppearance == StyleAppearance::Menulist ||
aAppearance == StyleAppearance::MenulistButton) {
aState->active &= aState->inHover;
@ -392,9 +396,6 @@ bool nsNativeThemeGTK::GetGtkWidgetAndState(StyleAppearance aAppearance,
case StyleAppearance::MozWindowTitlebarMaximized:
aGtkWidgetType = MOZ_GTK_HEADER_BAR_MAXIMIZED;
break;
case StyleAppearance::MozWindowButtonBox:
aGtkWidgetType = MOZ_GTK_HEADER_BAR_BUTTON_BOX;
break;
case StyleAppearance::MozWindowButtonClose:
aGtkWidgetType = MOZ_GTK_HEADER_BAR_BUTTON_CLOSE;
break;
@ -676,16 +677,6 @@ CSSIntMargin nsNativeThemeGTK::GetExtraSizeForWidget(
return extra;
}
bool nsNativeThemeGTK::IsWidgetVisible(StyleAppearance aAppearance) {
switch (aAppearance) {
case StyleAppearance::MozWindowButtonBox:
return false;
default:
break;
}
return true;
}
NS_IMETHODIMP
nsNativeThemeGTK::DrawWidgetBackground(gfxContext* aContext, nsIFrame* aFrame,
StyleAppearance aAppearance,
@ -702,8 +693,7 @@ nsNativeThemeGTK::DrawWidgetBackground(gfxContext* aContext, nsIFrame* aFrame,
GtkTextDirection direction = GetTextDirection(aFrame);
gint flags;
if (!IsWidgetVisible(aAppearance) ||
!GetGtkWidgetAndState(aAppearance, aFrame, gtkWidgetType, &state,
if (!GetGtkWidgetAndState(aAppearance, aFrame, gtkWidgetType, &state,
&flags)) {
return NS_OK;
}
@ -937,7 +927,6 @@ bool nsNativeThemeGTK::GetWidgetPadding(nsDeviceContext* aContext,
switch (aAppearance) {
case StyleAppearance::Toolbarbutton:
case StyleAppearance::Tooltip:
case StyleAppearance::MozWindowButtonBox:
case StyleAppearance::MozWindowButtonClose:
case StyleAppearance::MozWindowButtonMinimize:
case StyleAppearance::MozWindowButtonMaximize:
@ -1072,23 +1061,23 @@ LayoutDeviceIntSize nsNativeThemeGTK::GetMinimumWidgetSize(
case StyleAppearance::MozWindowButtonClose: {
const ToolbarButtonGTKMetrics* metrics =
GetToolbarButtonMetrics(MOZ_GTK_HEADER_BAR_BUTTON_CLOSE);
result.width = metrics->minSizeWithBorderMargin.width;
result.height = metrics->minSizeWithBorderMargin.height;
result.width = metrics->minSizeWithBorder.width;
result.height = metrics->minSizeWithBorder.height;
break;
}
case StyleAppearance::MozWindowButtonMinimize: {
const ToolbarButtonGTKMetrics* metrics =
GetToolbarButtonMetrics(MOZ_GTK_HEADER_BAR_BUTTON_MINIMIZE);
result.width = metrics->minSizeWithBorderMargin.width;
result.height = metrics->minSizeWithBorderMargin.height;
result.width = metrics->minSizeWithBorder.width;
result.height = metrics->minSizeWithBorder.height;
break;
}
case StyleAppearance::MozWindowButtonMaximize:
case StyleAppearance::MozWindowButtonRestore: {
const ToolbarButtonGTKMetrics* metrics =
GetToolbarButtonMetrics(MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE);
result.width = metrics->minSizeWithBorderMargin.width;
result.height = metrics->minSizeWithBorderMargin.height;
result.width = metrics->minSizeWithBorder.width;
result.height = metrics->minSizeWithBorder.height;
break;
}
case StyleAppearance::Button:
@ -1288,7 +1277,6 @@ nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext,
case StyleAppearance::Range:
case StyleAppearance::RangeThumb:
case StyleAppearance::Splitter:
case StyleAppearance::MozWindowButtonBox:
case StyleAppearance::MozWindowButtonClose:
case StyleAppearance::MozWindowButtonMinimize:
case StyleAppearance::MozWindowButtonMaximize:

View file

@ -93,7 +93,6 @@ class nsNativeThemeGTK final : public mozilla::widget::Theme {
WidgetNodeType& aGtkWidgetType,
GtkWidgetState* aState, gint* aWidgetFlags);
mozilla::CSSIntMargin GetExtraSizeForWidget(nsIFrame*, StyleAppearance);
bool IsWidgetVisible(StyleAppearance aAppearance);
void RefreshWidgetWindow(nsIFrame* aFrame);
WidgetNodeType NativeThemeToGtkTheme(StyleAppearance aAppearance,

View file

@ -57,6 +57,12 @@ NS_IMPL_ISUPPORTS(nsNativeTheme, nsITimerCallback, nsINamed)
aAppearance == StyleAppearance::ButtonArrowPrevious ||
aAppearance == StyleAppearance::ButtonArrowNext ||
aAppearance == StyleAppearance::ButtonArrowUp ||
#ifdef MOZ_WIDGET_GTK
aAppearance == StyleAppearance::MozWindowButtonClose ||
aAppearance == StyleAppearance::MozWindowButtonMinimize ||
aAppearance == StyleAppearance::MozWindowButtonRestore ||
aAppearance == StyleAppearance::MozWindowButtonMaximize ||
#endif
aAppearance == StyleAppearance::ButtonArrowDown) {
aFrame = aFrame->GetParent();
frameContent = aFrame->GetContent();

View file

@ -184,6 +184,7 @@ static const char sIntPrefs[][45] = {
"ui.systemScrollbarSize",
"ui.touchDeviceSupportPresent",
"ui.titlebarRadius",
"ui.titlebarButtonSpacing",
"ui.dynamicRange",
"ui.videoDynamicRange",
"ui.panelAnimations",

View file

@ -2264,6 +2264,7 @@ STATIC_ATOMS = [
Atom("_moz_swipe_animation_enabled", "-moz-swipe-animation-enabled"),
Atom("_moz_gtk_csd_available", "-moz-gtk-csd-available"),
Atom("_moz_gtk_csd_titlebar_radius", "-moz-gtk-csd-titlebar-radius"),
Atom("_moz_gtk_csd_titlebar_button_spacing", "-moz-gtk-csd-titlebar-button-spacing"),
Atom("_moz_gtk_csd_minimize_button", "-moz-gtk-csd-minimize-button"),
Atom("_moz_gtk_csd_minimize_button_position", "-moz-gtk-csd-minimize-button-position"),
Atom("_moz_gtk_csd_maximize_button", "-moz-gtk-csd-maximize-button"),