diff --git a/libnotificationmanager/jobsmodel_p.cpp b/libnotificationmanager/jobsmodel_p.cpp --- a/libnotificationmanager/jobsmodel_p.cpp +++ b/libnotificationmanager/jobsmodel_p.cpp @@ -265,10 +265,16 @@ const QString serviceName = message().service(); if (job->applicationName().isEmpty()) { qCInfo(NOTIFICATIONMANAGER) << "JobView request from" << serviceName << "didn't contain any identification information, this is an application bug!"; - const QString processName = Utils::processNameFromDBusService(connection(), serviceName); - if (!processName.isEmpty()) { - qCDebug(NOTIFICATIONMANAGER) << "Resolved JobView request to be from" << processName; - job->setApplicationName(processName); + + QDBusReply pidReply = connection().interface()->servicePid(serviceName); + if (pidReply.isValid()) { + const auto pid = pidReply.value(); + + const QString processName = Utils::processNameFromPid(pid); + if (!processName.isEmpty()) { + qCDebug(NOTIFICATIONMANAGER) << "Resolved JobView request to be from" << processName; + job->setApplicationName(processName); + } } } diff --git a/libnotificationmanager/notification.h b/libnotificationmanager/notification.h --- a/libnotificationmanager/notification.h +++ b/libnotificationmanager/notification.h @@ -71,6 +71,7 @@ void setImage(const QImage &image); QString desktopEntry() const; + void setDesktopEntry(const QString &desktopEntry); QString notifyRcName() const; QString eventId() const; diff --git a/libnotificationmanager/notification.cpp b/libnotificationmanager/notification.cpp --- a/libnotificationmanager/notification.cpp +++ b/libnotificationmanager/notification.cpp @@ -271,7 +271,13 @@ KService::Ptr Notification::Private::serviceForDesktopEntry(const QString &desktopEntry) { - KService::Ptr service = KService::serviceByDesktopName(desktopEntry); + KService::Ptr service; + + if (desktopEntry.startsWith(QLatin1Char('/'))) { + service = KService::serviceByDesktopPath(desktopEntry); + } else { + service = KService::serviceByDesktopName(desktopEntry); + } if (!service) { const QString lowerDesktopEntry = desktopEntry.toLower(); @@ -299,25 +305,20 @@ return service; } -void Notification::Private::processHints(const QVariantMap &hints) +void Notification::Private::setDesktopEntry(const QString &desktopEntry) { - auto end = hints.end(); - - desktopEntry = hints.value(QStringLiteral("desktop-entry")).toString(); - QString serviceName; configurableService = false; KService::Ptr service = serviceForDesktopEntry(desktopEntry); if (service) { - desktopEntry = service->desktopEntryName(); + this->desktopEntry = service->desktopEntryName(); serviceName = service->name(); applicationIconName = service->icon(); configurableService = !service->noDisplay(); } - notifyRcName = hints.value(QStringLiteral("x-kde-appname")).toString(); const bool isDefaultEvent = (notifyRcName == defaultComponentName()); configurableNotifyRc = false; if (!notifyRcName.isEmpty()) { @@ -344,6 +345,15 @@ const QRegularExpression regexp(QStringLiteral("^Event/([^/]*)$")); configurableNotifyRc = !config.groupList().filter(regexp).isEmpty(); } +} + +void Notification::Private::processHints(const QVariantMap &hints) +{ + auto end = hints.end(); + + notifyRcName = hints.value(QStringLiteral("x-kde-appname")).toString(); + + setDesktopEntry(hints.value(QStringLiteral("desktop-entry")).toString()); // Special override for KDE Connect since the notification is sent by kdeconnectd // but actually comes from a different app on the phone @@ -523,6 +533,11 @@ return d->desktopEntry; } +void Notification::setDesktopEntry(const QString &desktopEntry) +{ + d->setDesktopEntry(desktopEntry); +} + QString Notification::notifyRcName() const { return d->notifyRcName; diff --git a/libnotificationmanager/notification_p.h b/libnotificationmanager/notification_p.h --- a/libnotificationmanager/notification_p.h +++ b/libnotificationmanager/notification_p.h @@ -52,6 +52,7 @@ static KService::Ptr serviceForDesktopEntry(const QString &desktopEntry); + void setDesktopEntry(const QString &desktopEntry); void processHints(const QVariantMap &hints); void setUrgency(Notifications::Urgency urgency); @@ -69,6 +70,7 @@ QString applicationName; QString desktopEntry; bool configurableService = false; + QString serviceName; // "Name" field in KService from desktopEntry QString applicationIconName; QString originName; diff --git a/libnotificationmanager/server_p.cpp b/libnotificationmanager/server_p.cpp --- a/libnotificationmanager/server_p.cpp +++ b/libnotificationmanager/server_p.cpp @@ -138,13 +138,30 @@ notification.setIcon(app_icon); } - // No application name? Try to figure out the process name using the sender's PID - if (notification.applicationName().isEmpty()) { + uint pid = 0; + if (notification.desktopEntry().isEmpty() || notification.applicationName().isEmpty()) { qCInfo(NOTIFICATIONMANAGER) << "Notification from service" << message().service() << "didn't contain any identification information, this is an application bug!"; - const QString processName = Utils::processNameFromDBusService(connection(), message().service()); + QDBusReply pidReply = connection().interface()->servicePid(message().service()); + if (pidReply.isValid()) { + pid = pidReply.value(); + } + } + + // No desktop entry? Try to read the BAMF_DESKTOP_FILE_HINT in the environment of snaps + if (notification.desktopEntry().isEmpty() && pid > 0) { + const QString desktopEntry = Utils::desktopEntryFromPid(pid); + if (!desktopEntry.isEmpty()) { + qCDebug(NOTIFICATIONMANAGER) << "Resolved notification to be from desktop entry" << desktopEntry; + notification.setDesktopEntry(desktopEntry); + } + } + + // No application name? Try to figure out the process name using the sender's PID + if (notification.applicationName().isEmpty() && pid > 0) { + const QString processName = Utils::processNameFromPid(pid); if (!processName.isEmpty()) { - qCDebug(NOTIFICATIONMANAGER) << "Resolved notification to be from" << processName; + qCDebug(NOTIFICATIONMANAGER) << "Resolved notification to be from process name" << processName; notification.setApplicationName(processName); } } diff --git a/libnotificationmanager/utils.cpp b/libnotificationmanager/utils.cpp --- a/libnotificationmanager/utils.cpp +++ b/libnotificationmanager/utils.cpp @@ -24,25 +24,18 @@ #include #include #include +#include +#include #include -#include - #include #include using namespace NotificationManager; -QString Utils::processNameFromDBusService(const QDBusConnection &connection, const QString &serviceName) +QString Utils::processNameFromPid(uint pid) { - QDBusReply pidReply = connection.interface()->servicePid(serviceName); - if (!pidReply.isValid()) { - return QString(); - } - - const auto pid = pidReply.value(); - KSysGuard::Processes procs; procs.updateOrAddProcess(pid); @@ -55,6 +48,32 @@ return proc->name(); } +QString Utils::desktopEntryFromPid(uint pid) +{ + QFile environFile(QStringLiteral("/proc/%1/environ").arg(QString::number(pid))); + if (!environFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + return QString(); + } + + const QByteArray bamfDesktopFileHint = QByteArrayLiteral("BAMF_DESKTOP_FILE_HINT"); + + const auto lines = environFile.readAll().split('\0'); + for (const QByteArray &line : lines) { + const int equalsIdx = line.indexOf('='); + if (equalsIdx <= 0) { + continue; + } + + const QByteArray key = line.left(equalsIdx); + const QByteArray value = line.mid(equalsIdx + 1); + if (key == bamfDesktopFileHint) { + return value; + } + } + + return QString(); +} + QModelIndex Utils::mapToModel(const QModelIndex &idx, const QAbstractItemModel *sourceModel) { // KModelIndexProxyMapper can only map diferent indices to a single source diff --git a/libnotificationmanager/utils_p.h b/libnotificationmanager/utils_p.h --- a/libnotificationmanager/utils_p.h +++ b/libnotificationmanager/utils_p.h @@ -32,8 +32,9 @@ namespace Utils { -QString processNameFromDBusService(const QDBusConnection &connection, - const QString &serviceName); +QString processNameFromPid(uint pid); + +QString desktopEntryFromPid(uint pid); QModelIndex mapToModel(const QModelIndex &idx, const QAbstractItemModel *sourceModel);