status/backgroundApps: Show spinner when closing

It can take a little while for an app to quit after the user
clicked the close button, and another for the portal to pick
up the change.

In order to provide feedback to the user that the request is
being handled, replace the close button with a spinner.

https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/6441

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2732>
This commit is contained in:
Florian Müllner 2023-04-11 15:29:55 +02:00 committed by Marge Bot
parent d6d6bf727f
commit 2815f33458
2 changed files with 32 additions and 0 deletions

View File

@ -183,6 +183,9 @@
@extend .icon-button; @extend .icon-button;
padding: $base_padding; padding: $base_padding;
} }
& .spinner {
padding: $base_padding;
}
&.popup-inactive-menu-item { color: $fg_color; } &.popup-inactive-menu-item { color: $fg_color; }
} }

View File

@ -5,12 +5,15 @@ const Main = imports.ui.main;
const PopupMenu = imports.ui.popupMenu; const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util; const Util = imports.misc.util;
const {Spinner} = imports.ui.animation;
const {QuickToggle, SystemIndicator} = imports.ui.quickSettings; const {QuickToggle, SystemIndicator} = imports.ui.quickSettings;
const {loadInterfaceXML} = imports.misc.dbusUtils; const {loadInterfaceXML} = imports.misc.dbusUtils;
const DBUS_NAME = 'org.freedesktop.background.Monitor'; const DBUS_NAME = 'org.freedesktop.background.Monitor';
const DBUS_OBJECT_PATH = '/org/freedesktop/background/monitor'; const DBUS_OBJECT_PATH = '/org/freedesktop/background/monitor';
const SPINNER_TIMEOUT = 5; // seconds
const BackgroundMonitorIface = loadInterfaceXML('org.freedesktop.background.Monitor'); const BackgroundMonitorIface = loadInterfaceXML('org.freedesktop.background.Monitor');
const BackgroundMonitorProxy = Gio.DBusProxy.makeProxyWrapper(BackgroundMonitorIface); const BackgroundMonitorProxy = Gio.DBusProxy.makeProxyWrapper(BackgroundMonitorIface);
@ -76,6 +79,10 @@ var BackgroundAppMenuItem = GObject.registerClass({
this.set_child_above_sibling(this._ornamentLabel, null); this.set_child_above_sibling(this._ornamentLabel, null);
this._spinner = new Spinner(16, {hideOnStop: true});
this._spinner.add_style_class_name('spinner');
this.add_child(this._spinner);
const closeButton = new St.Button({ const closeButton = new St.Button({
iconName: 'window-close-symbolic', iconName: 'window-close-symbolic',
styleClass: 'close-button', styleClass: 'close-button',
@ -86,12 +93,34 @@ var BackgroundAppMenuItem = GObject.registerClass({
}); });
this.add_child(closeButton); this.add_child(closeButton);
this._spinner.bind_property('visible',
closeButton, 'visible',
GObject.BindingFlags.INVERT_BOOLEAN);
closeButton.connect('clicked', () => this._quitApp().catch(logError)); closeButton.connect('clicked', () => this._quitApp().catch(logError));
this.connect('destroy', () => this._onDestroy());
}
_onDestroy() {
if (this._spinnerTimeoutId)
GLib.source_remove(this._spinnerTimeoutId);
delete this._spinnerTimeoutId;
} }
async _quitApp() { async _quitApp() {
const appId = this.app.get_id().replace(/\.desktop$/, ''); const appId = this.app.get_id().replace(/\.desktop$/, '');
this._spinner.play();
this._spinnerTimeoutId =
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, SPINNER_TIMEOUT,
() => {
// Assume the quit request has failed, stop the spinner
this._spinner.stop();
delete this._spinnerTimeoutId;
return GLib.SOURCE_REMOVE;
});
try { try {
await Gio.DBus.session.call( await Gio.DBus.session.call(
appId, appId,