Skip to content

Commit bfd9dde

Browse files
my-name-ezdomferr
andauthored
Use gnome accent color as default color for the window border (#373)
* feat: use gnome accent color as default for window border color * preserve previous border color set and improve user settings * Disable the setting if accent colors are not supported * enable only on GNOME 47+ --------- Co-authored-by: Domenico Ferraro <[email protected]>
1 parent 7fe289f commit bfd9dde

File tree

6 files changed

+138
-36
lines changed

6 files changed

+138
-36
lines changed

resources/schemas/org.gnome.shell.extensions.tilingshell.gschema.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@
152152
<summary>Focused window border color</summary>
153153
<description>The color of the focused window's border.</description>
154154
</key>
155+
<key name="window-use-custom-border-color" type="b">
156+
<default>false</default>
157+
<summary>Use custom color</summary>
158+
<description>Use the color defined here for the focused window's border.</description>
159+
</key>
155160
<key name="window-border-width" type="u">
156161
<default>3</default>
157162
<summary>Focused window border width</summary>

src/components/windowBorderManager.ts

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class WindowBorder extends St.Bin {
2929
private readonly _signals: SignalHandling;
3030

3131
private _window: Meta.Window;
32+
private _interfaceSettings: Gio.Settings;
3233
private _windowMonitor: number;
3334
private _bindings: GObject.Binding[];
3435
private _enableScaling: boolean;
@@ -45,6 +46,9 @@ class WindowBorder extends St.Bin {
4546
this._bindings = [];
4647
this._borderWidth = 1;
4748
this._window = win;
49+
this._interfaceSettings = new Gio.Settings({
50+
schema_id: 'org.gnome.desktop.interface',
51+
});
4852
this._windowMonitor = win.get_monitor();
4953
this._enableScaling = enableScaling;
5054
this._delayedSmartBorderRadius = false;
@@ -321,6 +325,30 @@ class WindowBorder extends St.Bin {
321325
cached_radius;
322326
}
323327

328+
private _getGnomeAccentColor(): string {
329+
// get the system's accent color, fallback to user's custom color
330+
try {
331+
const accentColorName =
332+
this._interfaceSettings.get_string('accent-color');
333+
debug('accentColorName', accentColorName);
334+
return accentColorName;
335+
const gnomeAccentColorMapping: Record<string, string> = {
336+
blue: '#3584e4',
337+
teal: '#2190a4',
338+
green: '#3a944a',
339+
yellow: '#c88800',
340+
orange: '#ed5b00',
341+
red: '#e62d42',
342+
pink: '#d56199',
343+
purple: '#9141ac',
344+
slate: '#6f8396',
345+
};
346+
return gnomeAccentColorMapping[accentColorName];
347+
} catch (_unused) {
348+
return '#000000';
349+
}
350+
}
351+
324352
public updateStyle(): void {
325353
// handle scale factor of the monitor
326354
const monitorScalingFactor = this._enableScaling
@@ -335,6 +363,9 @@ class WindowBorder extends St.Bin {
335363
(alreadyScaled ? 1 : scalingFactor) *
336364
(Settings.WINDOW_BORDER_WIDTH /
337365
(alreadyScaled ? scalingFactor : 1));
366+
const borderColor = Settings.WINDOW_USE_CUSTOM_BORDER_COLOR
367+
? Settings.WINDOW_BORDER_COLOR
368+
: '-st-accent-color';
338369
const radius = this._borderRadiusValue.map((val) => {
339370
const valWithBorder = val === 0 ? val : val + borderWidth;
340371
return (
@@ -347,7 +378,7 @@ class WindowBorder extends St.Bin {
347378
? `${getScalingFactorSupportString(monitorScalingFactor)};`
348379
: '';
349380
this.set_style(
350-
`border-color: ${Settings.WINDOW_BORDER_COLOR}; border-width: ${borderWidth}px; border-radius: ${radius[St.Corner.TOPLEFT]}px ${radius[St.Corner.TOPRIGHT]}px ${radius[St.Corner.BOTTOMRIGHT]}px ${radius[St.Corner.BOTTOMLEFT]}px; ${scalingFactorSupportString}`,
381+
`border-color: ${borderColor}; border-width: ${borderWidth}px; border-radius: ${radius[St.Corner.TOPLEFT]}px ${radius[St.Corner.TOPRIGHT]}px ${radius[St.Corner.BOTTOMRIGHT]}px ${radius[St.Corner.BOTTOMLEFT]}px; ${scalingFactorSupportString}`,
351382
);
352383

353384
if (this._borderWidth !== borderWidth) {
@@ -384,11 +415,15 @@ export class WindowBorderManager {
384415

385416
private _border: WindowBorder | null;
386417
private _enableScaling: boolean;
418+
private _interfaceSettings: Gio.Settings;
387419

388420
constructor(enableScaling: boolean) {
389421
this._signals = new SignalHandling();
390422
this._border = null;
391423
this._enableScaling = enableScaling;
424+
this._interfaceSettings = new Gio.Settings({
425+
schema_id: 'org.gnome.desktop.interface',
426+
});
392427
}
393428

394429
public enable(): void {
@@ -415,7 +450,14 @@ export class WindowBorderManager {
415450
this._signals.connect(Settings, Settings.KEY_WINDOW_BORDER_COLOR, () =>
416451
this._border?.updateStyle(),
417452
);
418-
453+
this._signals.connect(
454+
Settings,
455+
Settings.KEY_WINDOW_USE_CUSTOM_BORDER_COLOR,
456+
() => this._border?.updateStyle(),
457+
);
458+
this._interfaceSettings.connect('changed::accent-color', () =>
459+
this._border?.updateStyle(),
460+
);
419461
this._signals.connect(Settings, Settings.KEY_WINDOW_BORDER_WIDTH, () =>
420462
this._border?.updateStyle(),
421463
);

src/extension.ts

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ import { Extension } from '@polyfill';
5353
import OverriddenAltTab from '@components/altTab/overriddenAltTab';
5454
import { LayoutSwitcherPopup } from '@components/layoutSwitcher/layoutSwitcher';
5555
import { unmaximizeWindow } from '@utils/gnomesupport';
56+
// @ts-expect-error "Module exists"
57+
import * as Config from 'resource:///org/gnome/Shell/Extensions/js/misc/config.js';
5658

5759
const debug = logger('extension');
5860

@@ -85,23 +87,38 @@ export default class TilingShellExtension extends Extension {
8587
}
8688

8789
private _validateSettings() {
88-
if (Settings.LAST_VERSION_NAME_INSTALLED === '14.0') {
90+
if (Settings.LAST_VERSION_NAME_INSTALLED === '17.0') {
8991
debug('apply compatibility changes');
90-
Settings.save_selected_layouts([]);
92+
// if users enabled window border, they set it custom in the past, so enable the custom border
93+
// keep using the custom border instead of using the accent color by default
94+
Settings.WINDOW_USE_CUSTOM_BORDER_COLOR =
95+
Settings.ENABLE_WINDOW_BORDER;
9196
}
97+
}
9298

93-
// Setting used for compatibility changes if necessary
94-
if (this.metadata['version-name']) {
95-
Settings.LAST_VERSION_NAME_INSTALLED =
96-
this.metadata['version-name'] || '0';
97-
}
99+
private _onInstall() {
100+
const GNOME_VERSION_MAJOR = Number(
101+
Config.PACKAGE_VERSION.split('.')[0],
102+
);
103+
// Force use of customer border color on GNOME < 47 since accent colors are not available
104+
Settings.WINDOW_USE_CUSTOM_BORDER_COLOR = GNOME_VERSION_MAJOR < 47;
98105
}
99106

100107
enable(): void {
101108
if (this._signals) this._signals.disconnect();
102109
this._signals = new SignalHandling();
103110

104111
Settings.initialize(this.getSettings());
112+
if (Settings.LAST_VERSION_NAME_INSTALLED === '0') {
113+
this._onInstall();
114+
115+
// Setting used for compatibility changes if necessary
116+
if (this.metadata['version-name']) {
117+
Settings.LAST_VERSION_NAME_INSTALLED =
118+
this.metadata['version-name'] || '0';
119+
}
120+
}
121+
105122
this._validateSettings();
106123

107124
// force initialization and tracking of windows

src/prefs.ts

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ function buildPrefsWidget(): Gtk.Widget {
5252
}
5353

5454
export default class TilingShellExtensionPreferences extends ExtensionPreferences {
55+
private GNOME_VERSION_MAJOR = Number(Config.PACKAGE_VERSION.split('.')[0]);
56+
5557
/**
5658
* This function is called when the preferences window is first created to fill
5759
* the `Adw.PreferencesWindow`.
@@ -130,41 +132,54 @@ export default class TilingShellExtensionPreferences extends ExtensionPreference
130132
),
131133
);
132134

133-
const windowBorderRow = new Adw.ExpanderRow({
135+
const windowBorderExpanderRow = new Adw.ExpanderRow({
134136
title: _('Window border'),
135137
subtitle: _('Show a border around focused window'),
136138
});
137-
appearenceGroup.add(windowBorderRow);
138-
windowBorderRow.add_row(
139+
appearenceGroup.add(windowBorderExpanderRow);
140+
windowBorderExpanderRow.add_row(
139141
this._buildSwitchRow(
140142
Settings.KEY_ENABLE_WINDOW_BORDER,
141143
_('Enable'),
142144
_('Show a border around focused window'),
143145
),
144146
);
145-
windowBorderRow.add_row(
147+
windowBorderExpanderRow.add_row(
146148
this._buildSwitchRow(
147149
Settings.KEY_ENABLE_SMART_WINDOW_BORDER_RADIUS,
148150
_('Smart border radius'),
149151
_('Dynamically adapt to the window’s actual border radius'),
150152
),
151153
);
152-
windowBorderRow.add_row(
154+
windowBorderExpanderRow.add_row(
153155
this._buildSpinButtonRow(
154156
Settings.KEY_WINDOW_BORDER_WIDTH,
155157
_('Width'),
156158
_('The size of the border'),
157159
1,
158160
),
159161
);
160-
windowBorderRow.add_row(
161-
this._buildColorRow(
162-
_('Border color'),
163-
_('Choose the color of the border'),
164-
this._getRGBAFromString(Settings.WINDOW_BORDER_COLOR),
165-
(val: string) => (Settings.WINDOW_BORDER_COLOR = val),
166-
),
162+
const colorButton = this._buildColorButton(
163+
this._getRGBAFromString(Settings.WINDOW_BORDER_COLOR),
164+
(val: string) => (Settings.WINDOW_BORDER_COLOR = val),
167165
);
166+
const windowBorderColorRow = new Adw.ActionRow({
167+
title: _('Border color'),
168+
subtitle: _('Choose the color of the border'),
169+
});
170+
windowBorderColorRow.add_suffix(colorButton);
171+
colorButton.set_visible(Settings.WINDOW_USE_CUSTOM_BORDER_COLOR);
172+
if (this.GNOME_VERSION_MAJOR >= 47) {
173+
const customColorDropDown = this._buildCustomColorDropDown(
174+
Settings.WINDOW_USE_CUSTOM_BORDER_COLOR,
175+
(use_custom_color: boolean) => {
176+
colorButton.set_visible(use_custom_color);
177+
Settings.WINDOW_USE_CUSTOM_BORDER_COLOR = use_custom_color;
178+
},
179+
);
180+
windowBorderColorRow.add_suffix(customColorDropDown);
181+
}
182+
windowBorderExpanderRow.add_row(windowBorderColorRow);
168183

169184
const animationsRow = new Adw.ExpanderRow({
170185
title: _('Animations'),
@@ -1199,12 +1214,10 @@ export default class TilingShellExtensionPreferences extends ExtensionPreference
11991214
return rgba;
12001215
}
12011216

1202-
_buildColorRow(
1203-
title: string,
1204-
subtitle: string,
1217+
_buildColorButton(
12051218
rgba: Gdk.RGBA,
12061219
onChange: (s: string) => void,
1207-
): Adw.ActionRow {
1220+
): Gtk.ColorButton {
12081221
const colorButton = new Gtk.ColorButton({
12091222
rgba,
12101223
use_alpha: true,
@@ -1213,13 +1226,30 @@ export default class TilingShellExtensionPreferences extends ExtensionPreference
12131226
colorButton.connect('color-set', () => {
12141227
onChange(colorButton.get_rgba().to_string());
12151228
});
1216-
const adwRow = new Adw.ActionRow({
1217-
title,
1218-
subtitle,
1219-
activatableWidget: colorButton,
1229+
return colorButton;
1230+
}
1231+
1232+
_buildCustomColorDropDown(
1233+
initialValue: boolean,
1234+
onChange: (_: boolean) => void,
1235+
styleClass?: string,
1236+
) {
1237+
const options = new Gtk.StringList();
1238+
options.append(_('Choose custom color')); // true
1239+
options.append(_('Use system accent color')); // false
1240+
const dropdown = new Gtk.DropDown({
1241+
model: options,
1242+
selected: initialValue ? 0 : 1,
12201243
});
1221-
adwRow.add_suffix(colorButton);
1222-
return adwRow;
1244+
dropdown.connect('notify::selected-item', (dd: Gtk.DropDown) => {
1245+
const index = dd.get_selected();
1246+
const selected = index === 0; // 0 is true, which means to use custom color
1247+
onChange(selected);
1248+
});
1249+
if (styleClass) dropdown.add_css_class(styleClass);
1250+
dropdown.set_vexpand(false);
1251+
dropdown.set_valign(Gtk.Align.CENTER);
1252+
return dropdown;
12231253
}
12241254

12251255
_buildFileChooserDialog(
@@ -1245,12 +1275,9 @@ export default class TilingShellExtensionPreferences extends ExtensionPreference
12451275
window.connect('map', () => {
12461276
fc.set_transient_for(window);
12471277
});
1248-
const [major] = Config.PACKAGE_VERSION.split('.').map((s: string) =>
1249-
Number(s),
1250-
);
12511278
// due to a bug, file chooser doesn't open on GNOME 42 when a filter is set
12521279
// filter is then enabled for GNOME 43+
1253-
if (major >= 43) fc.set_filter(filter);
1280+
if (this.GNOME_VERSION_MAJOR >= 43) fc.set_filter(filter);
12541281
fc.set_current_folder(Gio.File.new_for_path(GLib.get_home_dir()));
12551282
fc.connect('response', onResponse);
12561283

@@ -1484,7 +1511,7 @@ const ShortcutSettingButton = class extends Gtk.Button {
14841511
// Because the cairo module isn't real, we have to use these to ignore `any`.
14851512
// We keep them to the minimum possible scope to catch real errors.
14861513
/* eslint-disable @typescript-eslint/no-unsafe-call */
1487-
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
1514+
14881515
/* ctx.setLineCap(Cairo.LineCap.SQUARE);
14891516
//@ts-ignore
14901517
ctx.setAntialias(Cairo.Antialias.NONE);

src/settings/settings.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ export default class Settings {
7979
static KEY_LAST_VERSION_NAME_INSTALLED = 'last-version-name-installed';
8080
static KEY_OVERRIDDEN_SETTINGS = 'overridden-settings';
8181
static KEY_WINDOW_BORDER_COLOR = 'window-border-color';
82+
static KEY_WINDOW_USE_CUSTOM_BORDER_COLOR =
83+
'window-use-custom-border-color';
8284
static KEY_TILING_SYSTEM = 'enable-tiling-system';
8385
static KEY_SNAP_ASSIST = 'enable-snap-assist';
8486
static KEY_SHOW_INDICATOR = 'show-indicator';
@@ -395,6 +397,14 @@ export default class Settings {
395397
set_string(Settings.KEY_WINDOW_BORDER_COLOR, val);
396398
}
397399

400+
static get WINDOW_USE_CUSTOM_BORDER_COLOR(): boolean {
401+
return get_boolean(Settings.KEY_WINDOW_USE_CUSTOM_BORDER_COLOR);
402+
}
403+
404+
static set WINDOW_USE_CUSTOM_BORDER_COLOR(val: boolean) {
405+
set_boolean(Settings.KEY_WINDOW_USE_CUSTOM_BORDER_COLOR, val);
406+
}
407+
398408
static get WINDOW_BORDER_WIDTH(): number {
399409
return get_unsigned_number(Settings.KEY_WINDOW_BORDER_WIDTH);
400410
}

src/utils/gnomesupport.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export function getEventCoords(event: any): number[] {
3737
}
3838

3939
export function maximizeWindow(window: Meta.Window): void {
40+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
4041
window.get_maximized ? window.maximize(Meta.MaximizeFlags.BOTH):window.maximize();
4142
}
4243

0 commit comments

Comments
 (0)