sendnotifications: also sync icon-data from notfication hints
According to the priorities defined in the notifications spec version 1.2 REVIEW: 126722
This commit is contained in:
parent
8f4d39424a
commit
c122312c65
3 changed files with 254 additions and 25 deletions
|
@ -20,9 +20,11 @@
|
||||||
|
|
||||||
#include <QtDBus/QDBusConnection>
|
#include <QtDBus/QDBusConnection>
|
||||||
#include <QtDBus/QDBusInterface>
|
#include <QtDBus/QDBusInterface>
|
||||||
|
#include <QtDBus/QDBusArgument>
|
||||||
#include <QtDebug>
|
#include <QtDebug>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
#include <QImage>
|
||||||
#include <KConfig>
|
#include <KConfig>
|
||||||
#include <KConfigGroup>
|
#include <KConfigGroup>
|
||||||
|
|
||||||
|
@ -104,6 +106,79 @@ void NotificationsListener::loadApplications()
|
||||||
//qCDebug(KDECONNECT_PLUGIN_SENDNOTIFICATION) << "Loaded" << applications.size() << " applications";
|
//qCDebug(KDECONNECT_PLUGIN_SENDNOTIFICATION) << "Loaded" << applications.size() << " applications";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NotificationsListener::parseImageDataArgument(const QVariant& argument,
|
||||||
|
int& width, int& height,
|
||||||
|
int& rowStride, int& bitsPerSample,
|
||||||
|
int& channels, bool& hasAlpha,
|
||||||
|
QByteArray& imageData) const
|
||||||
|
{
|
||||||
|
if (!argument.canConvert<QDBusArgument>())
|
||||||
|
return false;
|
||||||
|
const QDBusArgument dbusArg = argument.value<QDBusArgument>();
|
||||||
|
dbusArg.beginStructure();
|
||||||
|
dbusArg >> width >> height >> rowStride >> hasAlpha >> bitsPerSample
|
||||||
|
>> channels >> imageData;
|
||||||
|
dbusArg.endStructure();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<QIODevice> NotificationsListener::iconForImageData(const QVariant& argument) const
|
||||||
|
{
|
||||||
|
int width, height, rowStride, bitsPerSample, channels;
|
||||||
|
bool hasAlpha;
|
||||||
|
QByteArray imageData;
|
||||||
|
|
||||||
|
if (!parseImageDataArgument(argument, width, height, rowStride, bitsPerSample,
|
||||||
|
channels, hasAlpha, imageData))
|
||||||
|
return QSharedPointer<QIODevice>();
|
||||||
|
|
||||||
|
if (bitsPerSample != 8) {
|
||||||
|
qCWarning(KDECONNECT_PLUGIN_SENDNOTIFICATION) << "Unsupported image format:"
|
||||||
|
<< "width=" << width
|
||||||
|
<< "height=" << height
|
||||||
|
<< "rowStride=" << rowStride
|
||||||
|
<< "bitsPerSample=" << bitsPerSample
|
||||||
|
<< "channels=" << channels
|
||||||
|
<< "hasAlpha=" << hasAlpha;
|
||||||
|
return QSharedPointer<QIODevice>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage image(reinterpret_cast<uchar*>(imageData.data()), width, height, rowStride,
|
||||||
|
hasAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32);
|
||||||
|
if (hasAlpha)
|
||||||
|
image = image.rgbSwapped(); // RGBA --> ARGB
|
||||||
|
|
||||||
|
QSharedPointer<QBuffer> buffer = QSharedPointer<QBuffer>(new QBuffer);
|
||||||
|
if (!buffer || !buffer->open(QIODevice::WriteOnly) ||
|
||||||
|
!image.save(buffer.data(), "PNG")) {
|
||||||
|
qCWarning(KDECONNECT_PLUGIN_SENDNOTIFICATION) << "Could not initialize image buffer";
|
||||||
|
return QSharedPointer<QIODevice>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<QIODevice> NotificationsListener::iconForIconName(const QString &iconName) const
|
||||||
|
{
|
||||||
|
int size = KIconLoader::SizeEnormous; // use big size to allow for good
|
||||||
|
// quality on high-DPI mobile devices
|
||||||
|
QString iconPath = KIconLoader::global()->iconPath(iconName, -size, true);
|
||||||
|
if (!iconPath.isEmpty()) {
|
||||||
|
if (!iconPath.endsWith(QLatin1String(".png")) &&
|
||||||
|
KIconLoader::global()->theme()->name() != QLatin1String("hicolor")) {
|
||||||
|
// try falling back to hicolor theme:
|
||||||
|
KIconTheme hicolor(QStringLiteral("hicolor"));
|
||||||
|
if (hicolor.isValid()) {
|
||||||
|
iconPath = hicolor.iconPath(iconName + ".png", size, KIconLoader::MatchBest);
|
||||||
|
//qCDebug(KDECONNECT_PLUGIN_SENDNOTIFICATION) << "Found non-png icon in default theme trying fallback to hicolor:" << iconPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iconPath.endsWith(QLatin1String(".png")))
|
||||||
|
return QSharedPointer<QIODevice>(new QFile(iconPath));
|
||||||
|
return QSharedPointer<QIODevice>();
|
||||||
|
}
|
||||||
uint NotificationsListener::Notify(const QString &appName, uint replacesId,
|
uint NotificationsListener::Notify(const QString &appName, uint replacesId,
|
||||||
const QString &appIcon,
|
const QString &appIcon,
|
||||||
const QString &summary, const QString &body,
|
const QString &summary, const QString &body,
|
||||||
|
@ -171,26 +246,26 @@ uint NotificationsListener::Notify(const QString &appName, uint replacesId,
|
||||||
// timeout == 0, for other notifications
|
// timeout == 0, for other notifications
|
||||||
// clearability is pointless
|
// clearability is pointless
|
||||||
|
|
||||||
if (!appIcon.isEmpty() && mPlugin->config()->get("generalSynchronizeIcons", true)) {
|
// sync any icon data?
|
||||||
int size = KIconLoader::SizeEnormous; // use big size to allow for good
|
if (mPlugin->config()->get("generalSynchronizeIcons", true)) {
|
||||||
// quality on High-DPI mobile devices
|
QSharedPointer<QIODevice> iconSource;
|
||||||
QString iconPath = KIconLoader::global()->iconPath(appIcon, -size, true);
|
// try different image sources according to priorities in notifications-
|
||||||
if (!iconPath.isEmpty()) {
|
// spec version 1.2:
|
||||||
if (!iconPath.endsWith(QLatin1String(".png")) &&
|
if (hints.contains("image-data"))
|
||||||
KIconLoader::global()->theme()->name() != QLatin1String("hicolor")) {
|
iconSource = iconForImageData(hints["image-data"]);
|
||||||
// try falling back to hicolor theme:
|
else if (hints.contains("image_data")) // 1.1 backward compatibility
|
||||||
KIconTheme hicolor(QStringLiteral("hicolor"));
|
iconSource = iconForImageData(hints["image_data"]);
|
||||||
if (hicolor.isValid()) {
|
else if (hints.contains("image-path"))
|
||||||
iconPath = hicolor.iconPath(appIcon + ".png", size, KIconLoader::MatchBest);
|
iconSource = iconForIconName(hints["image-path"].toString());
|
||||||
//qCDebug(KDECONNECT_PLUGIN_SENDNOTIFICATION) << "Found non-png icon in default theme trying fallback to hicolor:" << iconPath;
|
else if (hints.contains("image_path")) // 1.1 backward compatibility
|
||||||
}
|
iconSource = iconForIconName(hints["image_path"].toString());
|
||||||
}
|
else if (!appIcon.isEmpty())
|
||||||
if (iconPath.endsWith(QLatin1String(".png"))) {
|
iconSource = iconForIconName(appIcon);
|
||||||
//qCDebug(KDECONNECT_PLUGIN_SENDNOTIFICATION) << "Appending icon " << iconPath;
|
else if (hints.contains("icon_data")) // < 1.1 backward compatibility
|
||||||
QSharedPointer<QIODevice> iconFile(new QFile(iconPath));
|
iconSource = iconForImageData(hints["icon_data"]);
|
||||||
np.setPayload(iconFile, iconFile->size());
|
|
||||||
}
|
if (iconSource)
|
||||||
}
|
np.setPayload(iconSource, iconSource->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
mPlugin->sendPackage(np);
|
mPlugin->sendPackage(np);
|
||||||
|
|
|
@ -19,7 +19,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QtDBus/QDBusAbstractAdaptor>
|
#include <QtDBus/QDBusAbstractAdaptor>
|
||||||
|
#include <QtDBus/QDBusArgument>
|
||||||
#include <core/device.h>
|
#include <core/device.h>
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
class KdeConnectPlugin;
|
class KdeConnectPlugin;
|
||||||
class Notification;
|
class Notification;
|
||||||
|
@ -38,6 +41,15 @@ protected:
|
||||||
KdeConnectPlugin* mPlugin;
|
KdeConnectPlugin* mPlugin;
|
||||||
QHash<QString, NotifyingApplication> applications;
|
QHash<QString, NotifyingApplication> applications;
|
||||||
|
|
||||||
|
// virtual helper function to make testing possible (QDBusArgument can not
|
||||||
|
// be injected without making a DBUS-call):
|
||||||
|
virtual bool parseImageDataArgument(const QVariant& argument, int& width,
|
||||||
|
int& height, int& rowStride, int& bitsPerSample,
|
||||||
|
int& channels, bool& hasAlpha,
|
||||||
|
QByteArray& imageData) const;
|
||||||
|
QSharedPointer<QIODevice> iconForImageData(const QVariant& argument) const;
|
||||||
|
QSharedPointer<QIODevice> iconForIconName(const QString& iconName) const;
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
Q_SCRIPTABLE uint Notify(const QString&, uint, const QString&,
|
Q_SCRIPTABLE uint Notify(const QString&, uint, const QString&,
|
||||||
const QString&, const QString&,
|
const QString&, const QString&,
|
||||||
|
|
|
@ -22,8 +22,10 @@
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QTest>
|
#include <QTest>
|
||||||
#include <QTemporaryFile>
|
#include <QBuffer>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QColor>
|
||||||
|
|
||||||
#include <kiconloader.h>
|
#include <kiconloader.h>
|
||||||
|
|
||||||
|
@ -85,17 +87,23 @@ public:
|
||||||
return sentPackages;
|
return sentPackages;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NetworkPackage* getLastPackage() const
|
NetworkPackage* getLastPackage()
|
||||||
{
|
{
|
||||||
return lastPackage;
|
return lastPackage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void deleteLastPackage()
|
||||||
|
{
|
||||||
|
delete lastPackage;
|
||||||
|
lastPackage = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
bool sendPackage(NetworkPackage& np) override
|
bool sendPackage(NetworkPackage& np) override
|
||||||
{
|
{
|
||||||
++sentPackages;
|
++sentPackages;
|
||||||
// copy package manually to allow for inspection (can't use copy-constructor)
|
// copy package manually to allow for inspection (can't use copy-constructor)
|
||||||
delete lastPackage;
|
deleteLastPackage();
|
||||||
lastPackage = new NetworkPackage(np.type());
|
lastPackage = new NetworkPackage(np.type());
|
||||||
Q_ASSERT(lastPackage);
|
Q_ASSERT(lastPackage);
|
||||||
for (QVariantMap::ConstIterator iter = np.body().constBegin();
|
for (QVariantMap::ConstIterator iter = np.body().constBegin();
|
||||||
|
@ -128,6 +136,22 @@ public:
|
||||||
applications = value;
|
applications = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool parseImageDataArgument(const QVariant& argument, int& width,
|
||||||
|
int& height, int& rowStride, int& bitsPerSample,
|
||||||
|
int& channels, bool& hasAlpha,
|
||||||
|
QByteArray& imageData) const override
|
||||||
|
{
|
||||||
|
width = argument.toMap().value("width").toInt();
|
||||||
|
height = argument.toMap().value("height").toInt();
|
||||||
|
rowStride = argument.toMap().value("rowStride").toInt();
|
||||||
|
bitsPerSample = argument.toMap().value("bitsPerSample").toInt();
|
||||||
|
channels = argument.toMap().value("channels").toInt();
|
||||||
|
hasAlpha = argument.toMap().value("hasAlpha").toBool();
|
||||||
|
imageData = argument.toMap().value("imageData").toByteArray();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class TestNotificationListener : public QObject
|
class TestNotificationListener : public QObject
|
||||||
|
@ -327,24 +351,37 @@ void TestNotificationListener::testNotify()
|
||||||
QCOMPARE(++proxiedNotifications, d->getSentPackages());
|
QCOMPARE(++proxiedNotifications, d->getSentPackages());
|
||||||
|
|
||||||
// icon synchronization:
|
// icon synchronization:
|
||||||
|
QStringList iconPaths;
|
||||||
|
// appIcon
|
||||||
int count = 0;
|
int count = 0;
|
||||||
Q_FOREACH (const auto& iconName, KIconLoader::global()->queryIcons(-KIconLoader::SizeEnormous, KIconLoader::Application)) {
|
Q_FOREACH (const auto& iconName, KIconLoader::global()->queryIcons(-KIconLoader::SizeEnormous, KIconLoader::Application)) {
|
||||||
if (!iconName.endsWith(".png"))
|
if (!iconName.endsWith(".png"))
|
||||||
continue;
|
continue;
|
||||||
if (count++ > 3) // max 3 iterations
|
if (count++ > 3) // max 3 iterations
|
||||||
break;
|
break;
|
||||||
|
iconPaths.append(iconName); // memorize some paths for later
|
||||||
|
|
||||||
// existing icons are sync-ed if requested
|
// existing icons are sync-ed if requested
|
||||||
plugin->config()->set("generalSynchronizeIcons", true);
|
plugin->config()->set("generalSynchronizeIcons", true);
|
||||||
QFileInfo fi(iconName);
|
QFileInfo fi(iconName);
|
||||||
//qDebug() << "XXX" << iconName << fi.baseName() << fi.size();
|
|
||||||
retId = listener->Notify(appName, replacesId, fi.baseName(), summary, body, {}, {{}}, 0);
|
retId = listener->Notify(appName, replacesId, fi.baseName(), summary, body, {}, {{}}, 0);
|
||||||
QCOMPARE(retId, replacesId);
|
QCOMPARE(retId, replacesId);
|
||||||
QCOMPARE(++proxiedNotifications, d->getSentPackages());
|
QCOMPARE(++proxiedNotifications, d->getSentPackages());
|
||||||
QVERIFY(d->getLastPackage()->hasPayload());
|
QVERIFY(d->getLastPackage()->hasPayload());
|
||||||
QCOMPARE(d->getLastPackage()->payloadSize(), fi.size());
|
QCOMPARE(d->getLastPackage()->payloadSize(), fi.size());
|
||||||
|
// works also with abolute paths
|
||||||
|
retId = listener->Notify(appName, replacesId, iconName, summary, body, {}, {{}}, 0);
|
||||||
|
QCOMPARE(retId, replacesId);
|
||||||
|
QCOMPARE(++proxiedNotifications, d->getSentPackages());
|
||||||
|
QVERIFY(d->getLastPackage()->hasPayload());
|
||||||
|
QCOMPARE(d->getLastPackage()->payloadSize(), fi.size());
|
||||||
|
// extensions other than png are not accepted:
|
||||||
|
retId = listener->Notify(appName, replacesId, iconName + ".svg", summary, body, {}, {{}}, 0);
|
||||||
|
QCOMPARE(retId, replacesId);
|
||||||
|
QCOMPARE(++proxiedNotifications, d->getSentPackages());
|
||||||
|
QVERIFY(!d->getLastPackage()->hasPayload());
|
||||||
|
|
||||||
// otherwise no payload:
|
// if sync not requested no payload:
|
||||||
plugin->config()->set("generalSynchronizeIcons", false);
|
plugin->config()->set("generalSynchronizeIcons", false);
|
||||||
retId = listener->Notify(appName, replacesId, fi.baseName(), summary, body, {}, {{}}, 0);
|
retId = listener->Notify(appName, replacesId, fi.baseName(), summary, body, {}, {{}}, 0);
|
||||||
QCOMPARE(retId, replacesId);
|
QCOMPARE(retId, replacesId);
|
||||||
|
@ -352,6 +389,111 @@ void TestNotificationListener::testNotify()
|
||||||
QVERIFY(!d->getLastPackage()->hasPayload());
|
QVERIFY(!d->getLastPackage()->hasPayload());
|
||||||
QCOMPARE(d->getLastPackage()->payloadSize(), 0);
|
QCOMPARE(d->getLastPackage()->payloadSize(), 0);
|
||||||
}
|
}
|
||||||
|
plugin->config()->set("generalSynchronizeIcons", true);
|
||||||
|
|
||||||
|
// image-path in hints
|
||||||
|
if (iconPaths.size() > 0) {
|
||||||
|
retId = listener->Notify(appName, replacesId, iconPaths.size() > 1 ? iconPaths[1] : icon, summary, body, {}, {{"image-path", iconPaths[0]}}, 0);
|
||||||
|
QCOMPARE(retId, replacesId);
|
||||||
|
QCOMPARE(++proxiedNotifications, d->getSentPackages());
|
||||||
|
QVERIFY(d->getLastPackage()->hasPayload());
|
||||||
|
QFileInfo hintsFi(iconPaths[0]);
|
||||||
|
// image-path has priority over appIcon parameter:
|
||||||
|
QCOMPARE(d->getLastPackage()->payloadSize(), hintsFi.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// image_path in hints
|
||||||
|
if (iconPaths.size() > 0) {
|
||||||
|
retId = listener->Notify(appName, replacesId, iconPaths.size() > 1 ? iconPaths[1] : icon, summary, body, {}, {{"image_path", iconPaths[0]}}, 0);
|
||||||
|
QCOMPARE(retId, replacesId);
|
||||||
|
QCOMPARE(++proxiedNotifications, d->getSentPackages());
|
||||||
|
QVERIFY(d->getLastPackage()->hasPayload());
|
||||||
|
QFileInfo hintsFi(iconPaths[0]);
|
||||||
|
// image_path has priority over appIcon parameter:
|
||||||
|
QCOMPARE(d->getLastPackage()->payloadSize(), hintsFi.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// image-data in hints
|
||||||
|
// set up:
|
||||||
|
QBuffer *buffer;
|
||||||
|
QImage image;
|
||||||
|
int width = 2, height = 2, rowStride = 4*width, bitsPerSample = 8,
|
||||||
|
channels = 4;
|
||||||
|
bool hasAlpha = 1;
|
||||||
|
char rawData[] = { 0x01, 0x02, 0x03, 0x04, // raw rgba data
|
||||||
|
0x11, 0x12, 0x13, 0x14,
|
||||||
|
0x21, 0x22, 0x23, 0x24,
|
||||||
|
0x31, 0x32, 0x33, 0x34 };
|
||||||
|
QByteArray byteData(rawData, rowStride*height);
|
||||||
|
QVariantMap imageData = {{"width", width}, {"height", height}, {"rowStride", rowStride},
|
||||||
|
{"bitsPerSample", bitsPerSample}, {"channels", channels},
|
||||||
|
{"hasAlpha", hasAlpha}, {"imageData", rawData}};
|
||||||
|
QVariantMap hints;
|
||||||
|
#define COMPARE_PIXEL(x, y) \
|
||||||
|
QCOMPARE(qRed(image.pixel(x,y)), (int)rawData[x*4 + y*rowStride + 0]); \
|
||||||
|
QCOMPARE(qGreen(image.pixel(x,y)), (int)rawData[x*4 + y*rowStride + 1]); \
|
||||||
|
QCOMPARE(qBlue(image.pixel(x,y)), (int)rawData[x*4 + y*rowStride + 2]); \
|
||||||
|
QCOMPARE(qAlpha(image.pixel(x,y)), (int)rawData[x*4 + y*rowStride + 3]);
|
||||||
|
|
||||||
|
hints.insert("image-data", imageData);
|
||||||
|
if (iconPaths.size() > 0)
|
||||||
|
hints.insert("image-path", iconPaths[0]);
|
||||||
|
retId = listener->Notify(appName, replacesId, icon, summary, body, {}, hints, 0);
|
||||||
|
QCOMPARE(retId, replacesId);
|
||||||
|
QCOMPARE(++proxiedNotifications, d->getSentPackages());
|
||||||
|
QVERIFY(d->getLastPackage()->hasPayload());
|
||||||
|
buffer = dynamic_cast<QBuffer*>(d->getLastPackage()->payload().data());
|
||||||
|
QCOMPARE(d->getLastPackage()->payloadSize(), buffer->size());
|
||||||
|
// image-data is attached as png data
|
||||||
|
QVERIFY(image.loadFromData(reinterpret_cast<const uchar*>(buffer->data().constData()), buffer->size(), "PNG"));
|
||||||
|
// image-data has priority over image-path:
|
||||||
|
QCOMPARE(image.byteCount(), rowStride*height);
|
||||||
|
// rgba -> argb conversion was done correctly:
|
||||||
|
COMPARE_PIXEL(0,0);
|
||||||
|
COMPARE_PIXEL(1,0);
|
||||||
|
COMPARE_PIXEL(0,1);
|
||||||
|
COMPARE_PIXEL(1,1);
|
||||||
|
|
||||||
|
// same for image_data in hints
|
||||||
|
hints.clear();
|
||||||
|
hints.insert("image-data", imageData);
|
||||||
|
if (iconPaths.size() > 0)
|
||||||
|
hints.insert("image_path", iconPaths[0]);
|
||||||
|
retId = listener->Notify(appName, replacesId, icon, summary, body, {}, hints, 0);
|
||||||
|
QCOMPARE(retId, replacesId);
|
||||||
|
QCOMPARE(++proxiedNotifications, d->getSentPackages());
|
||||||
|
QVERIFY(d->getLastPackage()->hasPayload());
|
||||||
|
buffer = dynamic_cast<QBuffer*>(d->getLastPackage()->payload().data());
|
||||||
|
QCOMPARE(d->getLastPackage()->payloadSize(), buffer->size());
|
||||||
|
// image-data is attached as png data
|
||||||
|
QVERIFY(image.loadFromData(reinterpret_cast<const uchar*>(buffer->data().constData()), buffer->size(), "PNG"));
|
||||||
|
// image_data has priority over image_path/image-path:
|
||||||
|
QCOMPARE(image.byteCount(), rowStride*height);
|
||||||
|
// rgba -> argb conversion was done correctly:
|
||||||
|
COMPARE_PIXEL(0,0);
|
||||||
|
COMPARE_PIXEL(1,0);
|
||||||
|
COMPARE_PIXEL(0,1);
|
||||||
|
COMPARE_PIXEL(1,1);
|
||||||
|
|
||||||
|
// same for icon_data, which has lowest priority
|
||||||
|
hints.clear();
|
||||||
|
hints.insert("icon_data", imageData);
|
||||||
|
retId = listener->Notify(appName, replacesId, "", summary, body, {}, hints, 0);
|
||||||
|
QCOMPARE(retId, replacesId);
|
||||||
|
QCOMPARE(++proxiedNotifications, d->getSentPackages());
|
||||||
|
QVERIFY(d->getLastPackage());
|
||||||
|
QVERIFY(d->getLastPackage()->hasPayload());
|
||||||
|
buffer = dynamic_cast<QBuffer*>(d->getLastPackage()->payload().data());
|
||||||
|
// image-data is attached as png data
|
||||||
|
QVERIFY(image.loadFromData(reinterpret_cast<const uchar*>(buffer->data().constData()), buffer->size(), "PNG"));
|
||||||
|
QCOMPARE(image.byteCount(), rowStride*height);
|
||||||
|
// rgba -> argb conversion was done correctly:
|
||||||
|
COMPARE_PIXEL(0,0);
|
||||||
|
COMPARE_PIXEL(1,0);
|
||||||
|
COMPARE_PIXEL(0,1);
|
||||||
|
COMPARE_PIXEL(1,1);
|
||||||
|
|
||||||
|
#undef COMPARE_PIXEL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue