gnome-shell/js/dbusServices/notifications/notificationDaemon.js
Florian Müllner 477011a364 js: Port dbusUtils to ESM
The module is shared between the various D-Bus services and the
main gnome-shell process, so it was originally left out to allow
porting different bits at their own speed.

Now that everything has been ported to ESM, there is no reason
to not move that particular module as well.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2868>
2023-08-07 19:05:50 +00:00

161 lines
4.9 KiB
JavaScript

// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import {ServiceImplementation} from './dbusService.js';
import {loadInterfaceXML} from './misc/dbusUtils.js';
const NotificationsIface = loadInterfaceXML('org.freedesktop.Notifications');
const NotificationsProxy = Gio.DBusProxy.makeProxyWrapper(NotificationsIface);
Gio._promisify(Gio.DBusConnection.prototype, 'call');
export const NotificationDaemon = class extends ServiceImplementation {
constructor() {
super(NotificationsIface, '/org/freedesktop/Notifications');
this._autoShutdown = false;
this._activeNotifications = new Map();
this._proxy = new NotificationsProxy(Gio.DBus.session,
'org.gnome.Shell',
'/org/freedesktop/Notifications',
(proxy, error) => {
if (error)
log(error.message);
});
this._proxy.connectSignal('ActionInvoked',
(proxy, sender, params) => {
const [id] = params;
this._emitSignal(
this._activeNotifications.get(id),
'ActionInvoked',
new GLib.Variant('(us)', params));
});
this._proxy.connectSignal('NotificationClosed',
(proxy, sender, params) => {
const [id] = params;
this._emitSignal(
this._activeNotifications.get(id),
'NotificationClosed',
new GLib.Variant('(uu)', params));
this._activeNotifications.delete(id);
});
}
_emitSignal(sender, signalName, params) {
if (!sender)
return;
this._dbusImpl.get_connection()?.emit_signal(
sender,
this._dbusImpl.get_object_path(),
'org.freedesktop.Notifications',
signalName,
params);
}
_untrackSender(sender) {
super._untrackSender(sender);
this._activeNotifications.forEach((value, key) => {
if (value === sender)
this._activeNotifications.delete(key);
});
}
_checkNotificationId(invocation, id) {
if (id === 0)
return true;
if (!this._activeNotifications.has(id))
return true;
if (this._activeNotifications.get(id) === invocation.get_sender())
return true;
const error = new GLib.Error(Gio.DBusError,
Gio.DBusError.INVALID_ARGS, 'Invalid notification ID');
this._handleError(invocation, error);
return false;
}
register() {
Gio.DBus.session.own_name(
'org.freedesktop.Notifications',
Gio.BusNameOwnerFlags.REPLACE,
null, null);
}
async NotifyAsync(params, invocation) {
const sender = invocation.get_sender();
const pid = await this._getSenderPid(sender);
const replaceId = params[1];
const hints = params[6];
if (!this._checkNotificationId(invocation, replaceId))
return;
params[6] = {
...hints,
'sender-pid': new GLib.Variant('u', pid),
};
try {
const [id] = await this._proxy.NotifyAsync(...params);
this._activeNotifications.set(id, sender);
invocation.return_value(new GLib.Variant('(u)', [id]));
} catch (error) {
this._handleError(invocation, error);
}
}
async CloseNotificationAsync(params, invocation) {
const [id] = params;
if (!this._checkNotificationId(invocation, id))
return;
try {
await this._proxy.CloseNotificationAsync(...params);
invocation.return_value(null);
} catch (error) {
this._handleError(invocation, error);
}
}
async GetCapabilitiesAsync(params, invocation) {
try {
const res = await this._proxy.GetCapabilitiesAsync(...params);
invocation.return_value(new GLib.Variant('(as)', res));
} catch (error) {
this._handleError(invocation, error);
}
}
async GetServerInformationAsync(params, invocation) {
try {
const res = await this._proxy.GetServerInformationAsync(...params);
invocation.return_value(new GLib.Variant('(ssss)', res));
} catch (error) {
this._handleError(invocation, error);
}
}
async _getSenderPid(sender) {
const res = await Gio.DBus.session.call(
'org.freedesktop.DBus',
'/',
'org.freedesktop.DBus',
'GetConnectionUnixProcessID',
new GLib.Variant('(s)', [sender]),
new GLib.VariantType('(u)'),
Gio.DBusCallFlags.NONE,
-1,
null);
const [pid] = res.deepUnpack();
return pid;
}
};