messageTray: Expose Source icon as GObject property

As the notification redesign affects the API anyway, we can just
as well use the opportunity to modernize the code.

Turning the icon into a GObject property means we no longer need
a custom signal for change notifications, and the icon becomes
usable in bindings.

Since setting an `GThemedIcon` is common this also adds a convenience
property to set the icon name directly.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3103>
This commit is contained in:
Julian Sparber 2024-01-24 12:25:21 +01:00 committed by Marge Bot
parent 1b49cc643c
commit 00a375ce9b
9 changed files with 52 additions and 90 deletions

View File

@ -226,6 +226,10 @@ $_gdm_dialog_width: 23em;
}
}
.unlock-dialog-notification-icon {
icon-size: $large_icon_size;
}
.unlock-dialog-notification-label {
padding-left: $base_padding * 2;
padding-right: 0;

View File

@ -19,8 +19,6 @@ import {loadInterfaceXML} from '../misc/fileUtils.js';
const SHOW_WEEKDATE_KEY = 'show-weekdate';
const MESSAGE_ICON_SIZE = -1; // pick up from CSS
const NC_ = (context, str) => `${context}\u0004${str}`;
function sameYear(dateA, dateB) {
@ -795,7 +793,6 @@ class NotificationMessage extends MessageList.Message {
if (this.notification.gicon) {
return new St.Icon({
gicon: this.notification.gicon,
icon_size: MESSAGE_ICON_SIZE,
});
} else {
return null;

View File

@ -272,7 +272,7 @@ class AutorunSource extends MessageTray.Source {
this.showNotification(this._notification);
}
getIcon() {
get icon() {
return this.mount.get_icon();
}

View File

@ -383,7 +383,7 @@ class ChatSource extends MessageTray.Source {
this._notification.appendAliasChange(oldAlias, newAlias);
}
getIcon() {
get icon() {
let file = this._contact.get_avatar_file();
if (file)
return new Gio.FileIcon({file});
@ -392,12 +392,12 @@ class ChatSource extends MessageTray.Source {
}
_updateAvatarIcon() {
this.iconUpdated();
this.notify('icon');
if (this._notification) {
this._notification.update(
this._notification.title,
this._notification.bannerBodyText,
{gicon: this.getIcon()});
{gicon: this.icon});
}
}

View File

@ -833,7 +833,7 @@ class ExtensionUpdateSource extends MessageTray.Source {
super._init(this._app.get_name());
}
getIcon() {
get icon() {
return this._app.app_info.get_icon();
}

View File

@ -580,46 +580,6 @@ export const NotificationBanner = GObject.registerClass({
}
});
export const SourceActor = GObject.registerClass(
class SourceActor extends St.Widget {
_init(source, size) {
super._init();
this._source = source;
this._size = size;
this.connect('destroy',
() => (this._actorDestroyed = true));
this._actorDestroyed = false;
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._iconBin = new St.Bin({
x_expand: true,
height: size * scaleFactor,
width: size * scaleFactor,
});
this.add_child(this._iconBin);
this._source.connectObject('icon-updated',
this._updateIcon.bind(this), this);
this._updateIcon();
}
setIcon(icon) {
this._iconBin.child = icon;
this._iconSet = true;
}
_updateIcon() {
if (this._actorDestroyed)
return;
if (!this._iconSet)
this._iconBin.child = this._source.createIcon(this._size);
}
});
export const Source = GObject.registerClass({
Properties: {
'count': GObject.ParamSpec.int(
@ -634,10 +594,17 @@ export const Source = GObject.registerClass({
'title', 'title', 'title',
GObject.ParamFlags.READWRITE,
null),
'icon': GObject.ParamSpec.object(
'icon', 'icon', 'icon',
GObject.ParamFlags.READWRITE,
Gio.Icon),
'icon-name': GObject.ParamSpec.string(
'icon-name', 'icon-name', 'icon-name',
GObject.ParamFlags.READWRITE,
null),
},
Signals: {
'destroy': {param_types: [GObject.TYPE_UINT]},
'icon-updated': {},
'notification-added': {param_types: [Notification.$gtype]},
'notification-show': {param_types: [Notification.$gtype]},
},
@ -645,7 +612,7 @@ export const Source = GObject.registerClass({
_init(title, iconName) {
super._init({title});
this.iconName = iconName;
this.icon = new Gio.ThemedIcon({name: iconName});
this.notifications = [];
@ -700,18 +667,15 @@ export const Source = GObject.registerClass({
return new NotificationBanner(notification);
}
// Called to create a new icon actor.
// Provides a sane default implementation, override if you need
// something more fancy.
createIcon(size) {
return new St.Icon({
gicon: this.getIcon(),
icon_size: size,
});
get iconName() {
if (this.gicon instanceof Gio.ThemedIcon)
return this.gicon.iconName;
else
return null;
}
getIcon() {
return new Gio.ThemedIcon({name: this.iconName});
set iconName(iconName) {
this.icon = new Gio.ThemedIcon({name: iconName});
}
_onNotificationDestroy(notification) {
@ -765,10 +729,6 @@ export const Source = GObject.registerClass({
this.run_dispose();
}
iconUpdated() {
this.emit('icon-updated');
}
// To be overridden by subclasses
open() {
}

View File

@ -5,7 +5,6 @@ import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Shell from 'gi://Shell';
import St from 'gi://St';
import * as Config from '../misc/config.js';
import * as Main from './main.js';
@ -347,10 +346,11 @@ class FdoNotificationDaemonSource extends MessageTray.Source {
this.destroy();
}
processNotification(notification, gicon) {
if (gicon)
this._gicon = gicon;
this.iconUpdated();
processNotification(notification, appIcon) {
if (!this.app && appIcon) {
this._appIcon = appIcon;
this.notify('icon');
}
let tracker = Shell.WindowTracker.get_default();
if (notification.resident && this.app && tracker.focus_app === this.app)
@ -409,17 +409,13 @@ class FdoNotificationDaemonSource extends MessageTray.Source {
super.destroy();
}
createIcon(size) {
if (this.app) {
return this.app.create_icon_texture(size);
} else if (this._gicon) {
return new St.Icon({
gicon: this._gicon,
icon_size: size,
});
} else {
get icon() {
if (this.app)
return this.app.get_icon();
else if (this._appIcon)
return this._appIcon;
else
return null;
}
}
});
@ -542,8 +538,8 @@ class GtkNotificationDaemonAppSource extends MessageTray.Source {
this._notificationPending = false;
}
createIcon(size) {
return this._app.create_icon_texture(size);
get icon() {
return this._app.get_icon();
}
_createPolicy() {

View File

@ -32,8 +32,6 @@ const FADE_OUT_SCALE = 0.3;
const BLUR_BRIGHTNESS = 0.65;
const BLUR_RADIUS = 90;
const SUMMARY_ICON_SIZE = 32;
const NotificationsBox = GObject.registerClass({
Signals: {'wake-up-screen': {}},
}, class NotificationsBox extends St.BoxLayout {
@ -83,8 +81,12 @@ const NotificationsBox = GObject.registerClass({
}
_makeNotificationSource(source, box) {
let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE);
box.add_child(sourceActor);
let iconActor = new St.Icon({
style_class: 'unlock-dialog-notification-icon',
fallback_icon_name: 'application-x-executable',
});
source.bind_property('icon', iconActor, 'gicon', GObject.BindingFlags.SYNC_CREATE);
box.add_child(iconActor);
let textBox = new St.BoxLayout({
x_expand: true,
@ -114,9 +116,12 @@ const NotificationsBox = GObject.registerClass({
}
_makeNotificationDetailedSource(source, box) {
let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE);
let sourceBin = new St.Bin({child: sourceActor});
box.add_child(sourceBin);
let iconActor = new St.Icon({
style_class: 'unlock-dialog-notification-icon',
fallback_icon_name: 'application-x-executable',
});
source.bind_property('icon', iconActor, 'gicon', GObject.BindingFlags.SYNC_CREATE);
box.add_child(iconActor);
let textBox = new St.BoxLayout({vertical: true});
box.add_child(textBox);

View File

@ -84,8 +84,8 @@ class WindowAttentionSource extends MessageTray.Source {
}
}
createIcon(size) {
return this._app.create_icon_texture(size);
get icon() {
return this._app.get_icon();
}
destroy(params) {