[SCM] kdeconnect packaging branch, master, updated. upstream/1.0.1-206-gf661872

Maximiliano Curia maxy at moszumanska.debian.org
Thu Jul 13 18:27:01 UTC 2017


Gitweb-URL: http://git.debian.org/?p=pkg-kde/kde-extras/kdeconnect.git;a=commitdiff;h=c122312

The following commit has been merged in the master branch:
commit c122312c65ae4d2350d93e4d403200f9750926c8
Author: Holger Kaelberer <holger.k at elberer.de>
Date:   Sat Aug 27 13:59:25 2016 +0200

    sendnotifications: also sync icon-data from notfication hints
    
    According to the priorities defined in the notifications spec
    version 1.2
    
    REVIEW: 126722
---
 .../sendnotifications/notificationslistener.cpp    | 115 +++++++++++++---
 plugins/sendnotifications/notificationslistener.h  |  12 ++
 tests/testnotificationlistener.cpp                 | 152 ++++++++++++++++++++-
 3 files changed, 254 insertions(+), 25 deletions(-)

diff --git a/plugins/sendnotifications/notificationslistener.cpp b/plugins/sendnotifications/notificationslistener.cpp
index 4da1770..c8608ac 100644
--- a/plugins/sendnotifications/notificationslistener.cpp
+++ b/plugins/sendnotifications/notificationslistener.cpp
@@ -20,9 +20,11 @@
 
 #include <QtDBus/QDBusConnection>
 #include <QtDBus/QDBusInterface>
+#include <QtDBus/QDBusArgument>
 #include <QtDebug>
 #include <QLoggingCategory>
 #include <QStandardPaths>
+#include <QImage>
 #include <KConfig>
 #include <KConfigGroup>
 
@@ -104,6 +106,79 @@ void NotificationsListener::loadApplications()
     //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,
                                    const QString &appIcon,
                                    const QString &summary, const QString &body,
@@ -171,26 +246,26 @@ uint NotificationsListener::Notify(const QString &appName, uint replacesId,
                                           // timeout == 0, for other notifications
                                           // clearability is pointless
 
-    if (!appIcon.isEmpty() && mPlugin->config()->get("generalSynchronizeIcons", true)) {
-        int size = KIconLoader::SizeEnormous;  // use big size to allow for good
-                                               // quality on High-DPI mobile devices
-        QString iconPath = KIconLoader::global()->iconPath(appIcon, -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(appIcon + ".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"))) {
-                //qCDebug(KDECONNECT_PLUGIN_SENDNOTIFICATION) << "Appending icon " << iconPath;
-                QSharedPointer<QIODevice> iconFile(new QFile(iconPath));
-                np.setPayload(iconFile, iconFile->size());
-            }
-        }
+    // sync any icon data?
+    if (mPlugin->config()->get("generalSynchronizeIcons", true)) {
+        QSharedPointer<QIODevice> iconSource;
+        // try different image sources according to priorities in notifications-
+        // spec version 1.2:
+        if (hints.contains("image-data"))
+            iconSource = iconForImageData(hints["image-data"]);
+        else if (hints.contains("image_data"))  // 1.1 backward compatibility
+            iconSource = iconForImageData(hints["image_data"]);
+        else if (hints.contains("image-path"))
+            iconSource = iconForIconName(hints["image-path"].toString());
+        else if (hints.contains("image_path"))  // 1.1 backward compatibility
+            iconSource = iconForIconName(hints["image_path"].toString());
+        else if (!appIcon.isEmpty())
+            iconSource = iconForIconName(appIcon);
+        else if (hints.contains("icon_data"))  // < 1.1 backward compatibility
+            iconSource = iconForImageData(hints["icon_data"]);
+
+        if (iconSource)
+            np.setPayload(iconSource, iconSource->size());
     }
 
     mPlugin->sendPackage(np);
diff --git a/plugins/sendnotifications/notificationslistener.h b/plugins/sendnotifications/notificationslistener.h
index 0612c34..3076d0b 100644
--- a/plugins/sendnotifications/notificationslistener.h
+++ b/plugins/sendnotifications/notificationslistener.h
@@ -19,7 +19,10 @@
  */
 
 #include <QtDBus/QDBusAbstractAdaptor>
+#include <QtDBus/QDBusArgument>
 #include <core/device.h>
+#include <QBuffer>
+#include <QFile>
 
 class KdeConnectPlugin;
 class Notification;
@@ -38,6 +41,15 @@ protected:
     KdeConnectPlugin* mPlugin;
     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:
     Q_SCRIPTABLE uint Notify(const QString&, uint, const QString&,
                              const QString&, const QString&,
diff --git a/tests/testnotificationlistener.cpp b/tests/testnotificationlistener.cpp
index ad36dac..c1c8206 100644
--- a/tests/testnotificationlistener.cpp
+++ b/tests/testnotificationlistener.cpp
@@ -22,8 +22,10 @@
 #include <QApplication>
 #include <QNetworkAccessManager>
 #include <QTest>
-#include <QTemporaryFile>
+#include <QBuffer>
 #include <QStandardPaths>
+#include <QImage>
+#include <QColor>
 
 #include <kiconloader.h>
 
@@ -85,17 +87,23 @@ public:
         return sentPackages;
     }
 
-    const NetworkPackage* getLastPackage() const
+    NetworkPackage* getLastPackage()
     {
         return lastPackage;
     }
 
+    void deleteLastPackage()
+    {
+        delete lastPackage;
+        lastPackage = nullptr;
+    }
+
 public Q_SLOTS:
     bool sendPackage(NetworkPackage& np) override
     {
         ++sentPackages;
         // copy package manually to allow for inspection (can't use copy-constructor)
-        delete lastPackage;
+        deleteLastPackage();
         lastPackage = new NetworkPackage(np.type());
         Q_ASSERT(lastPackage);
         for (QVariantMap::ConstIterator iter = np.body().constBegin();
@@ -128,6 +136,22 @@ public:
         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
@@ -327,24 +351,37 @@ void TestNotificationListener::testNotify()
     QCOMPARE(++proxiedNotifications, d->getSentPackages());
 
     // icon synchronization:
+    QStringList iconPaths;
+    // appIcon
     int count = 0;
     Q_FOREACH (const auto& iconName, KIconLoader::global()->queryIcons(-KIconLoader::SizeEnormous, KIconLoader::Application)) {
         if (!iconName.endsWith(".png"))
             continue;
         if (count++ > 3) // max 3 iterations
             break;
+        iconPaths.append(iconName); // memorize some paths for later
 
         // existing icons are sync-ed if requested
         plugin->config()->set("generalSynchronizeIcons", true);
         QFileInfo fi(iconName);
-        //qDebug() << "XXX" << iconName << fi.baseName() << fi.size();
         retId = listener->Notify(appName, replacesId, fi.baseName(), summary, body, {}, {{}}, 0);
         QCOMPARE(retId, replacesId);
         QCOMPARE(++proxiedNotifications, d->getSentPackages());
         QVERIFY(d->getLastPackage()->hasPayload());
         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);
         retId = listener->Notify(appName, replacesId, fi.baseName(), summary, body, {}, {{}}, 0);
         QCOMPARE(retId, replacesId);
@@ -352,6 +389,111 @@ void TestNotificationListener::testNotify()
         QVERIFY(!d->getLastPackage()->hasPayload());
         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
 }
 
 

-- 
kdeconnect packaging



More information about the pkg-kde-commits mailing list