612e04165e
We want to replace gjs' custom (and now legacy) imports system with standard EcmaScript modules: JS developers are already familiar with them, they have better tooling support and using standard features over non-standard ones is generally the right thing to do. Our D-Bus services are separate from the main process, and thus can be ported separately (except for the few imports that are shared with the main process' code base). Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2786>
161 lines
4.9 KiB
JavaScript
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';
|
|
|
|
const {loadInterfaceXML} = imports.misc.dbusUtils;
|
|
|
|
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;
|
|
}
|
|
};
|