Skip to content

Commit 884175b

Browse files
committed
Bug 1850827 - Implement rounded bottom corners in GTK. r=rmader
The implementation is uglier than it needs to be. We basically need to override the GTK styles for the window decorations with the desired radius. This is because of two reasons: * Adwaita on gtk3 doesn't provide a bottom corner radius. * Even if it did we couldn't reasonably query it, see comment 4. So in order for stuff to look sensible we need to make sure that we and GTK agree on what radius to use. Using the titlebar radius makes sense here. Differential Revision: https://phabricator.services.mozilla.com/D187343
1 parent f0d8d07 commit 884175b

File tree

9 files changed

+125
-30
lines changed

9 files changed

+125
-30
lines changed

browser/themes/linux/browser.css

+32-22
Original file line numberDiff line numberDiff line change
@@ -294,19 +294,41 @@ menuitem.bookmark-item {
294294
color: -moz-headerbarinactivetext;
295295
}
296296

297-
:root[tabsintitlebar] #navigator-toolbox-background {
298-
appearance: auto;
299-
-moz-default-appearance: -moz-window-titlebar-maximized;
300-
background-color: transparent;
301-
color: CaptionText;
302-
}
297+
:root[tabsintitlebar] {
298+
#navigator-toolbox-background {
299+
appearance: auto;
300+
-moz-default-appearance: -moz-window-titlebar-maximized;
301+
background-color: transparent;
302+
color: CaptionText;
303+
}
303304

304-
:root[tabsintitlebar] #navigator-toolbox-background:-moz-window-inactive {
305-
color: InactiveCaptionText;
305+
#navigator-toolbox-background:-moz-window-inactive {
306+
color: InactiveCaptionText;
307+
}
308+
309+
/* When temporarily showing the menu bar, make it at least as tall as the tab
310+
* bar such that the window controls don't appear to move up. */
311+
#toolbar-menubar[autohide="true"] {
312+
height: calc(var(--tab-min-height) + 2 * var(--tab-block-margin));
313+
}
306314
}
307315

308-
:root[tabsintitlebar][sizemode="normal"]:not([gtktiledwindow="true"]) #navigator-toolbox-background {
309-
-moz-default-appearance: -moz-window-titlebar;
316+
:root[tabsintitlebar][sizemode="normal"]:not([gtktiledwindow="true"]) {
317+
#navigator-toolbox-background {
318+
-moz-default-appearance: -moz-window-titlebar;
319+
}
320+
321+
#navigator-toolbox:-moz-lwtheme, dialog::backdrop {
322+
border-top-left-radius: env(-moz-gtk-csd-titlebar-radius);
323+
border-top-right-radius: env(-moz-gtk-csd-titlebar-radius);
324+
}
325+
326+
@media (-moz-gtk-csd-rounded-bottom-corners) {
327+
body {
328+
border-bottom-left-radius: env(-moz-gtk-csd-titlebar-radius);
329+
border-bottom-right-radius: env(-moz-gtk-csd-titlebar-radius);
330+
}
331+
}
310332
}
311333

312334
/*
@@ -322,18 +344,6 @@ menuitem.bookmark-item {
322344
color: inherit;
323345
}
324346

325-
:root[tabsintitlebar][sizemode="normal"]:not([gtktiledwindow="true"]) #navigator-toolbox:-moz-lwtheme,
326-
:root[tabsintitlebar][sizemode="normal"]:not([gtktiledwindow="true"]) dialog::backdrop {
327-
border-top-left-radius: env(-moz-gtk-csd-titlebar-radius);
328-
border-top-right-radius: env(-moz-gtk-csd-titlebar-radius);
329-
}
330-
331-
/* When temporarily showing the menu bar, make it at least as tall as the tab
332-
* bar such that the window controls don't appear to move up. */
333-
:root[tabsintitlebar] #toolbar-menubar[autohide="true"] {
334-
height: calc(var(--tab-min-height) + 2 * var(--tab-block-margin));
335-
}
336-
337347
/* The button box must appear on top of the navigator-toolbox in order for
338348
* click and hover mouse events to work properly for the button in the restored
339349
* window state. Otherwise, elements in the navigator-toolbox, like the menubar,

modules/libpref/init/StaticPrefList.yaml

+10
Original file line numberDiff line numberDiff line change
@@ -15271,6 +15271,16 @@
1527115271
value: true
1527215272
mirror: always
1527315273

15274+
# Whether we enable rounded bottom corners on GTK by default.
15275+
#
15276+
# The implementation is a bit hacky (see details in bug 1850827) so behind a
15277+
# pref for emergency purposes.
15278+
- name: widget.gtk.rounded-bottom-corners.enabled
15279+
type: bool
15280+
value: true
15281+
mirror: always
15282+
rust: true
15283+
1527415284
# Whether selection colors for the non-system theme get passed from the system
1527515285
# GTK theme.
1527615286
- name: widget.gtk.alt-theme.selection

servo/components/style/gecko/media_features.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,7 @@ macro_rules! bool_pref_feature {
684684
/// to support new types in these entries and (2) ensuring that either
685685
/// nsPresContext::MediaFeatureValuesChanged is called when the value that
686686
/// would be returned by the evaluator function could change.
687-
pub static MEDIA_FEATURES: [QueryFeatureDescription; 60] = [
687+
pub static MEDIA_FEATURES: [QueryFeatureDescription; 61] = [
688688
feature!(
689689
atom!("width"),
690690
AllowsRanges::Yes,
@@ -992,9 +992,11 @@ pub static MEDIA_FEATURES: [QueryFeatureDescription; 60] = [
992992
),
993993
lnf_int_feature!(atom!("-moz-system-dark-theme"), SystemUsesDarkTheme),
994994
lnf_int_feature!(atom!("-moz-panel-animations"), PanelAnimations),
995-
// media query for popover attribute
996995
bool_pref_feature!(atom!("-moz-popover-enabled"), "dom.element.popover.enabled"),
997-
// media query for MathML Core's implementation of mi
996+
bool_pref_feature!(
997+
atom!("-moz-gtk-csd-rounded-bottom-corners"),
998+
"widget.gtk.rounded-bottom-corners.enabled"
999+
),
9981000
bool_pref_feature!(
9991001
atom!("-moz-mathml-core-mi"),
10001002
"mathml.legacy_mathvariant_attribute.disabled"

widget/gtk/GRefPtr.h

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ GOBJECT_TRAITS(GdkPixbuf)
4040
GOBJECT_TRAITS(GCancellable)
4141
GOBJECT_TRAITS(GtkIMContext)
4242
GOBJECT_TRAITS(GUnixFDList)
43+
GOBJECT_TRAITS(GtkCssProvider)
4344

4445
#undef GOBJECT_TRAITS
4546

widget/gtk/MozContainerWayland.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,11 @@ static wl_region* moz_container_wayland_create_opaque_region(
524524
wl_region_subtract(region, aX, aY, aCornerRadius, aCornerRadius);
525525
wl_region_subtract(region, aX + aWidth - aCornerRadius, aY, aCornerRadius,
526526
aCornerRadius);
527+
wl_region_subtract(region, aX, aY + aHeight - aCornerRadius, aCornerRadius,
528+
aCornerRadius);
529+
wl_region_subtract(region, aX + aWidth - aCornerRadius,
530+
aY + aHeight - aCornerRadius, aCornerRadius,
531+
aCornerRadius);
527532
}
528533
return region;
529534
}

widget/gtk/nsLookAndFeel.cpp

+45-2
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ nsLookAndFeel::nsLookAndFeel() {
187187
}
188188

189189
nsLookAndFeel::~nsLookAndFeel() {
190+
ClearRoundedCornerProvider();
190191
if (mDBusSettingsProxy) {
191192
g_signal_handlers_disconnect_by_func(
192193
mDBusSettingsProxy, FuncToGpointer(settings_changed_signal_cb), this);
@@ -1210,8 +1211,9 @@ void nsLookAndFeel::RestoreSystemTheme() {
12101211
"gtk-application-prefer-dark-theme",
12111212
mSystemTheme.mPreferDarkTheme, nullptr);
12121213
}
1213-
moz_gtk_refresh();
12141214
mSystemThemeOverridden = false;
1215+
UpdateRoundedBottomCornerStyles();
1216+
moz_gtk_refresh();
12151217
}
12161218

12171219
static bool AnyColorChannelIsDifferent(nscolor aColor) {
@@ -1327,6 +1329,46 @@ void nsLookAndFeel::ConfigureAndInitializeAltTheme() {
13271329
// Right now we're using the opposite color-scheme theme, make sure to record
13281330
// it.
13291331
mSystemThemeOverridden = true;
1332+
UpdateRoundedBottomCornerStyles();
1333+
}
1334+
1335+
void nsLookAndFeel::ClearRoundedCornerProvider() {
1336+
if (mRoundedCornerProvider) {
1337+
gtk_style_context_remove_provider_for_screen(
1338+
gdk_screen_get_default(),
1339+
GTK_STYLE_PROVIDER(mRoundedCornerProvider.get()));
1340+
mRoundedCornerProvider = nullptr;
1341+
}
1342+
}
1343+
1344+
void nsLookAndFeel::UpdateRoundedBottomCornerStyles() {
1345+
ClearRoundedCornerProvider();
1346+
if (!StaticPrefs::widget_gtk_rounded_bottom_corners_enabled()) {
1347+
return;
1348+
}
1349+
int32_t radius = EffectiveTheme().mTitlebarRadius;
1350+
if (!radius) {
1351+
return;
1352+
}
1353+
mRoundedCornerProvider = dont_AddRef(gtk_css_provider_new());
1354+
nsPrintfCString string(
1355+
"window.csd decoration {"
1356+
"border-bottom-right-radius: %dpx;"
1357+
"border-bottom-left-radius: %dpx;"
1358+
"}\n",
1359+
radius, radius);
1360+
GUniquePtr<GError> error;
1361+
if (!gtk_css_provider_load_from_data(mRoundedCornerProvider.get(),
1362+
string.get(), string.Length(),
1363+
getter_Transfers(error))) {
1364+
NS_WARNING(nsPrintfCString("Failed to load provider: %s - %s\n",
1365+
string.get(), error ? error->message : nullptr)
1366+
.get());
1367+
}
1368+
gtk_style_context_add_provider_for_screen(
1369+
gdk_screen_get_default(),
1370+
GTK_STYLE_PROVIDER(mRoundedCornerProvider.get()),
1371+
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
13301372
}
13311373

13321374
Maybe<ColorScheme> nsLookAndFeel::ComputeColorSchemeSetting() {
@@ -1546,8 +1588,9 @@ void nsLookAndFeel::ConfigureFinalEffectiveTheme() {
15461588
"gtk-application-prefer-dark-theme",
15471589
mAltTheme.mPreferDarkTheme, nullptr);
15481590
}
1549-
moz_gtk_refresh();
15501591
mSystemThemeOverridden = true;
1592+
UpdateRoundedBottomCornerStyles();
1593+
moz_gtk_refresh();
15511594
}
15521595
}
15531596

widget/gtk/nsLookAndFeel.h

+6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
enum WidgetNodeType : int;
1717
struct _GtkStyle;
1818
typedef struct _GDBusProxy GDBusProxy;
19+
typedef struct _GtkCssProvider GtkCssProvider;
1920

2021
class nsLookAndFeel final : public nsXPLookAndFeel {
2122
public:
@@ -174,6 +175,11 @@ class nsLookAndFeel final : public nsXPLookAndFeel {
174175
int32_t mCSDMinimizeButtonPosition = 0;
175176
int32_t mCSDCloseButtonPosition = 0;
176177

178+
RefPtr<GtkCssProvider> mRoundedCornerProvider;
179+
void UpdateRoundedBottomCornerStyles();
180+
181+
void ClearRoundedCornerProvider();
182+
177183
void EnsureInit() {
178184
if (mInitialized) {
179185
return;

widget/gtk/nsWindow.cpp

+20-3
Original file line numberDiff line numberDiff line change
@@ -6922,7 +6922,8 @@ LayoutDeviceIntCoord nsWindow::GetTitlebarRadius() {
69226922
// to draw transparent corners of default Gtk titlebar.
69236923
// Both implementations (cairo_region_t and wl_region) needs to be synced.
69246924
static void SubtractTitlebarCorners(cairo_region_t* aRegion, int aX, int aY,
6925-
int aWindowWidth, int aTitlebarRadius) {
6925+
int aWindowWidth, int aWindowHeight,
6926+
int aTitlebarRadius) {
69266927
if (!aTitlebarRadius) {
69276928
return;
69286929
}
@@ -6935,9 +6936,23 @@ static void SubtractTitlebarCorners(cairo_region_t* aRegion, int aX, int aY,
69356936
aTitlebarRadius,
69366937
};
69376938
cairo_region_subtract_rectangle(aRegion, &rect);
6939+
rect = {
6940+
aX,
6941+
aY + aWindowHeight - aTitlebarRadius,
6942+
aTitlebarRadius,
6943+
aTitlebarRadius,
6944+
};
6945+
cairo_region_subtract_rectangle(aRegion, &rect);
6946+
rect = {
6947+
aX + aWindowWidth - aTitlebarRadius,
6948+
aY + aWindowHeight - aTitlebarRadius,
6949+
aTitlebarRadius,
6950+
aTitlebarRadius,
6951+
};
6952+
cairo_region_subtract_rectangle(aRegion, &rect);
69386953
}
69396954

6940-
void nsWindow::UpdateTopLevelOpaqueRegion(void) {
6955+
void nsWindow::UpdateTopLevelOpaqueRegion() {
69416956
if (!mCompositedScreen) {
69426957
return;
69436958
}
@@ -6962,8 +6977,10 @@ void nsWindow::UpdateTopLevelOpaqueRegion(void) {
69626977
cairo_rectangle_int_t rect = {x, y, width, height};
69636978
cairo_region_union_rectangle(region, &rect);
69646979

6980+
// TODO: We actually could get a proper opaque region from layout, see
6981+
// nsIWidget::UpdateOpaqueRegion. This could simplify titlebar drawing.
69656982
int radius = DoDrawTilebarCorners() ? int(GetTitlebarRadius()) : 0;
6966-
SubtractTitlebarCorners(region, x, y, width, radius);
6983+
SubtractTitlebarCorners(region, x, y, width, height, radius);
69676984

69686985
gdk_window_set_opaque_region(window, region);
69696986

xpcom/ds/StaticAtoms.py

+1
Original file line numberDiff line numberDiff line change
@@ -2258,6 +2258,7 @@
22582258
Atom("_moz_gtk_csd_close_button", "-moz-gtk-csd-close-button"),
22592259
Atom("_moz_gtk_csd_close_button_position", "-moz-gtk-csd-close-button-position"),
22602260
Atom("_moz_gtk_csd_reversed_placement", "-moz-gtk-csd-reversed-placement"),
2261+
Atom("_moz_gtk_csd_rounded_bottom_corners", "-moz-gtk-csd-rounded-bottom-corners"),
22612262
Atom("_moz_content_prefers_color_scheme", "-moz-content-prefers-color-scheme"),
22622263
Atom("_moz_content_preferred_color_scheme", "-moz-content-preferred-color-scheme"),
22632264
Atom("_moz_system_dark_theme", "-moz-system-dark-theme"),

0 commit comments

Comments
 (0)