on xenial help sign in
Provide a dbus interface for setting the count and countVisible properties. Fixes: 1301400
commit4eba3436539ccb499c0c64da5d7a2ebcc7494286 authorTed Gould <ted@gould.cx> dateMon 5 May 2014, 12:08 (12 years ago) parent5c25f78e0a1f8a
4 files changed+488−23
plugins/Unity/Launcher/backend/launcherbackend.cpp+266−16 plugins/Unity/Launcher/backend/launcherbackend.h+52−4 tests/plugins/Unity/Launcher/CMakeLists.txt+3−3 tests/plugins/Unity/Launcher/launcherbackendtest.cpp+167
plugins/Unity/Launcher/backend/launcherbackend.cpp+266−16
@@ -34,10 +34,12 @@ public:
3434 QString desktopFile;
3535 QString displayName;
3636 QString icon;
37+ int count;
38+ bool countVisible;
3739};
3840
3941LauncherBackend::LauncherBackend(QObject *parent):
40− QObject(parent),
42+ QDBusVirtualObject(parent),
4143 m_accounts(nullptr)
4244{
4345#ifndef LAUNCHER_TESTING
@@ -45,10 +47,25 @@ LauncherBackend::LauncherBackend(QObject *parent):
4547#endif
4648 m_user = qgetenv("USER");
4749 syncFromAccounts();
50+
51+ /* Set up ourselves on DBus */
52+ QDBusConnection con = QDBusConnection::sessionBus();
53+ if (!con.registerService("com.canonical.Unity.Launcher")) {
54+ qDebug() << "Unable to register launcher name";
55+ }
56+ if (!con.registerVirtualObject("/com/canonical/Unity/Launcher", this, QDBusConnection::VirtualObjectRegisterOption::SubPath)) {
57+ qDebug() << "Unable to register launcher object";
58+ }
4859}
4960
5061LauncherBackend::~LauncherBackend()
5162{
63+ /* Remove oursevles from DBus */
64+ QDBusConnection con = QDBusConnection::sessionBus();
65+ con.unregisterService("com.canonical.Unity.Launcher");
66+ con.unregisterObject("/com/canonical/Unity/Launcher");
67+
68+ /* Clear data */
5269 m_storedApps.clear();
5370
5471 Q_FOREACH(LauncherBackendItem *item, m_itemCache) {
@@ -90,7 +107,7 @@ void LauncherBackend::setStoredApplications(const QStringList &appIds)
90107
91108QString LauncherBackend::desktopFile(const QString &appId) const
92109{
93− LauncherBackendItem *item = m_itemCache.value(appId);
110+ LauncherBackendItem *item = m_itemCache.value(appId, nullptr);
94111 if (item) {
95112 return item->desktopFile;
96113 }
@@ -100,7 +117,7 @@ QString LauncherBackend::desktopFile(const QString &appId) const
100117
101118QString LauncherBackend::displayName(const QString &appId) const
102119{
103− LauncherBackendItem *item = m_itemCache.value(appId);
120+ LauncherBackendItem *item = m_itemCache.value(appId, nullptr);
104121 if (item) {
105122 return item->displayName;
106123 }
@@ -118,16 +135,9 @@ QString LauncherBackend::displayName(const QString &appId) const
118135QString LauncherBackend::icon(const QString &appId) const
119136{
120137 QString iconName;
121− LauncherBackendItem *item = m_itemCache.value(appId);
138+ LauncherBackendItem *item = getItem(appId);
122139 if (item) {
123140 iconName = item->icon;
124− } else {
125− QString df = findDesktopFile(appId);
126− if (!df.isEmpty()) {
127− LauncherBackendItem *item = parseDesktopFile(df);
128− m_itemCache.insert(appId, item);
129− iconName = item->icon;
130− }
131141 }
132142
133143 return iconName;
@@ -153,10 +163,70 @@ int LauncherBackend::progress(const QString &appId) const
153163
154164int LauncherBackend::count(const QString &appId) const
155165{
156− // TODO: Return value for count emblem.
157− // TODO: emit countChanged() when this value changes.
158− Q_UNUSED(appId)
159− return 0;
166+ int count = -1;
167+ LauncherBackendItem *item = getItem(appId);
168+
169+ if (item) {
170+ if (item->countVisible) {
171+ count = item->count;
172+ }
173+ }
174+
175+ return count;
176+}
177+
178+void LauncherBackend::setCount(const QString &appId, int count) const
179+{
180+ LauncherBackendItem *item = getItem(appId);
181+
182+ bool emitchange = false;
183+ if (item) {
184+ emitchange = (item->count != count);
185+ item->count = count;
186+ }
187+
188+ if (emitchange) {
189+ /* TODO: This needs to use the accessor to handle the visibility
190+ correctly, but when we have the two properties we can just use
191+ the local value */
192+ Q_EMIT countChanged(appId, this->count(appId));
193+ QVariant vcount(item->count);
194+ emitPropChangedDbus(appId, "count", vcount);
195+ }
196+}
197+
198+bool LauncherBackend::countVisible(const QString &appId) const
199+{
200+ bool visible = false;
201+ LauncherBackendItem *item = getItem(appId);
202+
203+ if (item) {
204+ visible = item->countVisible;
205+ }
206+
207+ return visible;
208+}
209+
210+void LauncherBackend::setCountVisible(const QString &appId, bool visible) const
211+{
212+ LauncherBackendItem *item = getItem(appId);
213+
214+ bool emitchange = false;
215+ if (item) {
216+ emitchange = (item->countVisible != visible);
217+ item->countVisible = visible;
218+ } else {
219+ qDebug() << "Unable to find:" << appId;
220+ }
221+
222+ if (emitchange) {
223+ /* TODO: Because we're using visible in determining the
224+ count we need to emit a count changed as well */
225+ Q_EMIT countChanged(appId, this->count(appId));
226+ Q_EMIT countVisibleChanged(appId, item->countVisible);
227+ QVariant vCountVisible(item->countVisible);
228+ emitPropChangedDbus(appId, "countVisible", vCountVisible);
229+ }
160230}
161231
162232void LauncherBackend::setUser(const QString &username)
@@ -275,6 +345,35 @@ LauncherBackendItem* LauncherBackend::parseDesktopFile(const QString &desktopFil
275345 } else {
276346 item->icon = "image://theme/" + iconString;
277347 }
348+
349+ /* TODO: These should be looked up in a cache somewhere */
350+ item->count = 0;
351+ item->countVisible = false;
352+
353+ return item;
354+}
355+
356+/* Gets an item, and tries to create a new one if we need it to */
357+LauncherBackendItem* LauncherBackend::getItem(const QString &appId) const
358+{
359+ LauncherBackendItem *item = m_itemCache.value(appId, nullptr);
360+ if (!item) {
361+ QString df = findDesktopFile(appId);
362+ if (!df.isEmpty()) {
363+ item = parseDesktopFile(df);
364+ if (item) {
365+ m_itemCache[appId] = item;
366+ } else {
367+ qWarning() << "Unable to parse desktop file for" << appId << "path" << df;
368+ }
369+ } else {
370+ qDebug() << "Unable to find desktop file for:" << appId;
371+ }
372+ }
373+
374+ if (!item)
375+ qWarning() << "Unable to find item for: " << appId;
376+
278377 return item;
279378}
280379
@@ -285,7 +384,7 @@ void LauncherBackend::loadFromVariant(const QVariantMap &details)
285384 }
286385 QString appId = details.value("id").toString();
287386
288− LauncherBackendItem *item = m_itemCache.value(appId);
387+ LauncherBackendItem *item = m_itemCache.value(appId, nullptr);
289388 if (item) {
290389 delete item;
291390 }
@@ -295,6 +394,8 @@ void LauncherBackend::loadFromVariant(const QVariantMap &details)
295394 item->desktopFile = details.value("desktopFile").toString();
296395 item->displayName = details.value("name").toString();
297396 item->icon = details.value("icon").toString();
397+ item->count = details.value("count").toInt();
398+ item->countVisible = details.value("countVisible").toBool();
298399
299400 m_itemCache.insert(appId, item);
300401 m_storedApps.append(appId);
@@ -308,6 +409,8 @@ QVariantMap LauncherBackend::itemToVariant(const QString &appId) const
308409 details.insert("name", item->displayName);
309410 details.insert("icon", item->icon);
310411 details.insert("desktopFile", item->desktopFile);
412+ details.insert("count", item->count);
413+ details.insert("countVisible", item->countVisible);
311414 return details;
312415}
313416
@@ -318,3 +421,150 @@ bool LauncherBackend::isDefaultsItem(const QList<QVariantMap> &apps) const
318421 // list of one item with the 'defaults' field set to true.
319422 return (apps.size() == 1 && apps[0].value("defaults").toBool());
320423}
424+
425+bool LauncherBackend::handleMessage(const QDBusMessage& message, const QDBusConnection& connection)
426+{
427+ /* Check to make sure we're getting properties on our interface */
428+ if (message.type() != QDBusMessage::MessageType::MethodCallMessage) {
429+ return false;
430+ }
431+ if (message.interface() != "org.freedesktop.DBus.Properties") {
432+ return false;
433+ }
434+ if (message.arguments()[0].toString() != "com.canonical.Unity.Launcher.Item") {
435+ return false;
436+ }
437+
438+ /* Break down the path to just the app id */
439+ QString pathtemp = message.path();
440+ if (!pathtemp.startsWith("/com/canonical/Unity/Launcher/")) {
441+ return false;
442+ }
443+ pathtemp.remove("/com/canonical/Unity/Launcher/");
444+ if (pathtemp.indexOf('/') >= 0) {
445+ return false;
446+ }
447+
448+ /* Find ourselves an appid */
449+ QString appid = decodeAppId(pathtemp);
450+ QVariantList retval;
451+
452+ if (message.member() == "Get") {
453+ if (message.arguments()[1].toString() == "count") {
454+ retval.append(QVariant::fromValue(QDBusVariant(this->count(appid))));
455+ } else if (message.arguments()[1].toString() == "countVisible") {
456+ retval.append(QVariant::fromValue(QDBusVariant(this->countVisible(appid))));
457+ }
458+ } else if (message.member() == "Set") {
459+ if (message.arguments()[1].toString() == "count") {
460+ this->setCount(appid, message.arguments()[2].value<QDBusVariant>().variant().toInt());
461+ } else if (message.arguments()[1].toString() == "countVisible") {
462+ this->setCountVisible(appid, message.arguments()[2].value<QDBusVariant>().variant().toBool());
463+ }
464+ } else if (message.member() == "GetAll") {
465+ retval.append(this->itemToVariant(appid));
466+ } else {
467+ return false;
468+ }
469+
470+ QDBusMessage reply = message.createReply(retval);
471+ return connection.send(reply);
472+}
473+
474+QString LauncherBackend::introspect(const QString &path) const
475+{
476+ /* This case we should just list the nodes */
477+ if (path == "/com/canonical/Unity/Launcher/" || path == "/com/canonical/Unity/Launcher") {
478+ QString nodes;
479+
480+ Q_FOREACH(const QString &appId, m_itemCache.keys()) {
481+ nodes.append("<node name=\"");
482+ nodes.append(encodeAppId(appId));
483+ nodes.append("\"/>\n");
484+ }
485+
486+ return nodes;
487+ }
488+
489+ /* Should not happen, but let's handle it */
490+ if (!path.startsWith("/com/canonical/Unity/Launcher")) {
491+ return "";
492+ }
493+
494+ /* Now we should be looking at a node */
495+ QString nodeiface =
496+ "<interface name=\"com.canonical.Unity.Launcher.Item\">"
497+ "<property name=\"count\" type=\"i\" access=\"readwrite\" />"
498+ "<property name=\"countVisible\" type=\"b\" access=\"readwrite\" />"
499+ "</interface>";
500+ return nodeiface;
501+}
502+
503+QString LauncherBackend::decodeAppId(const QString& path)
504+{
505+ QByteArray bytes = path.toUtf8();
506+ QByteArray decoded;
507+
508+ for (int i = 0; i < bytes.size(); ++i) {
509+ char chr = bytes.at(i);
510+
511+ if (chr == '_') {
512+ QString number;
513+ number.append(bytes.at(i+1));
514+ number.append(bytes.at(i+2));
515+
516+ bool okay;
517+ char newchar = number.toUInt(&okay, 16);
518+ if (okay)
519+ decoded.append(newchar);
520+
521+ i += 2;
522+ } else {
523+ decoded.append(chr);
524+ }
525+ }
526+
527+ return QString::fromUtf8(decoded);
528+}
529+
530+QString LauncherBackend::encodeAppId(const QString& appId)
531+{
532+ QByteArray bytes = appId.toUtf8();
533+ QString encoded;
534+
535+ for (int i = 0; i < bytes.size(); ++i) {
536+ uchar chr = bytes.at(i);
537+
538+ if ((chr >= 'a' && chr <= 'z') ||
539+ (chr >= 'A' && chr <= 'Z') ||
540+ (chr >= '0' && chr <= '9'&& i != 0)) {
541+ encoded.append(chr);
542+ } else {
543+ QString hexval = QString("_%1").arg(chr, 2, 16, QChar('0'));
544+ encoded.append(hexval.toUpper());
545+ }
546+ }
547+
548+ return encoded;
549+}
550+
551+void LauncherBackend::emitPropChangedDbus(const QString& appId, const QString& property, QVariant &value) const
552+{
553+ QString path("/com/canonical/Unity/Launcher/");
554+ path.append(encodeAppId(appId));
555+
556+ QDBusMessage message = QDBusMessage::createSignal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged");
557+
558+ QList<QVariant> arguments;
559+ QVariantHash changedprops;
560+ changedprops[property] = QVariant::fromValue(QDBusVariant(value));
561+ QVariantList deletedprops;
562+
563+ arguments.append(changedprops);
564+ arguments.append(deletedprops);
565+
566+ message.setArguments(arguments);
567+
568+ QDBusConnection con = QDBusConnection::sessionBus();
569+ con.send(message);
570+}
plugins/Unity/Launcher/backend/launcherbackend.h+52−4
@@ -24,6 +24,7 @@
2424#include <QObject>
2525#include <QSettings>
2626#include <QStringList>
27+#include <QDBusVirtualObject>
2728
2829class AccountsServiceDBusAdaptor;
2930
@@ -32,11 +33,13 @@ class AccountsServiceDBusAdaptor;
3233 */
3334
3435class LauncherBackendItem;
36+class LauncherBackendTest;
3537
36−class LauncherBackend : public QObject
38+class LauncherBackend : public QDBusVirtualObject
3739{
3840 Q_OBJECT
3941
42+ friend LauncherBackendTest;
4043
4144public:
4245 LauncherBackend(QObject *parent = 0);
@@ -116,16 +119,53 @@ public:
116119 */
117120 int count(const QString &appId) const;
118121
122+ /**
123+ * @brief Set the count on an item
124+ * @param appId The ID of the application
125+ * @param count Count to show on the application
126+ */
127+ void setCount(const QString &appId, int count) const;
128+
129+ /**
130+ * @brief Get whether the count should be visible
131+ * @param appId The ID of the application.
132+ * @returns Whether to show a count on the launcher
133+ */
134+ bool countVisible(const QString &appId) const;
135+
136+ /**
137+ * @brief Set the visibility of the count item
138+ * @param appId The ID of the application
139+ * @param visible Whether the count should be visible
140+ */
141+ void setCountVisible(const QString &appId, bool visible) const;
142+
119143 /**
120144 * @brief Sets the username for which to look up launcher items.
121145 * @param username The username to use.
122146 */
123147 void setUser(const QString &username);
124148
149+ /**
150+ * @brief Handle a message to an application node
151+ * @param message DBus message to handle
152+ * @param connection DBus connection that we're using
153+ * @returns whether the message was handled
154+ */
155+ virtual bool handleMessage(const QDBusMessage& message, const QDBusConnection& connection);
156+
157+ /**
158+ * @brief Get introspection information on the objects we're exporting
159+ * @param path the dbus path containing the appid
160+ * @returns Introspection information for that node in the tree
161+ */
162+ virtual QString introspect (const QString &path) const;
163+
125164Q_SIGNALS:
126− void quickListChanged(const QString &appId, const QList<QuickListEntry> &quickList);
127− void progressChanged(const QString &appId, int progress);
128− void countChanged(const QString &appId, int count);
165+ void quickListChanged(const QString &appId, const QList<QuickListEntry> &quickList) const;
166+ void progressChanged(const QString &appId, int progress) const;
167+ void countChanged(const QString &appId, int count) const;
168+ void countVisibleChanged(const QString &appId, bool visible) const;
129169
130170private:
131171 QString findDesktopFile(const QString &appId) const;
@@ -143,6 +183,14 @@ private:
143183
144184 AccountsServiceDBusAdaptor *m_accounts;
145185 QString m_user;
186+
187+ void emitPropChangedDbus(const QString& appId, const QString& property, QVariant &value) const;
188+
189+protected: /* Protected to allow testing */
190+ LauncherBackendItem* getItem(const QString& appId) const;
191+
192+ static QString decodeAppId(const QString& path);
193+ static QString encodeAppId(const QString& appId);
146194};
147195
148196#endif // LAUNCHERBACKEND_H
tests/plugins/Unity/Launcher/CMakeLists.txt+3−3
@@ -15,9 +15,9 @@ add_definitions(-DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
1515add_definitions(-DLAUNCHER_TESTING)
1616
1717### LauncherBackendTest
18−set(testBackendCommand ${CMAKE_CURRENT_BINARY_DIR}/launcherbackendtestExec
19− -o ${CMAKE_BINARY_DIR}/launcherbackendtest.xml,xunitxml
20− -o -,txt)
18+set(testBackendCommand dbus-test-runner --task ${CMAKE_CURRENT_BINARY_DIR}/launcherbackendtestExec
19+ --parameter -o --parameter ${CMAKE_BINARY_DIR}/launcherbackendtest.xml,xunitxml
20+ --parameter -o --parameter -,txt)
2121add_test(NAME launcherbackendtest COMMAND ${testBackendCommand})
2222add_custom_target(launcherbackendtest ${testBackendCommand})
2323add_executable(launcherbackendtestExec
tests/plugins/Unity/Launcher/launcherbackendtest.cpp+167
@@ -20,6 +20,10 @@
2020#include "launcherbackend.h"
2121
2222#include <QtTest>
23+#include <QDBusConnection>
24+#include <QDBusMessage>
25+#include <QDBusVariant>
26+
2327
2428class LauncherBackendTest : public QObject
2529{
@@ -66,6 +70,169 @@ private Q_SLOTS:
6670
6771 QCOMPARE(backend.icon(appId), expectedIcon);
6872 }
73+
74+ void testGetItem_data() {
75+ QTest::addColumn<QString>("appId");
76+ QTest::addColumn<bool>("exists");
77+
78+ QTest::newRow("Exists") << "rel-icon" << true;
79+ QTest::newRow("Doesn't Exist") << "does-not-exist" << false;
80+ }
81+
82+ void testGetItem() {
83+ QFETCH(QString, appId);
84+ QFETCH(bool, exists);
85+
86+ LauncherBackend backend;
87+ auto item = backend.getItem(appId);
88+
89+ if (exists) {
90+ QVERIFY(item != nullptr);
91+ } else {
92+ QVERIFY(item == nullptr);
93+ }
94+ }
95+
96+ void testCount_data() {
97+ QTest::addColumn<QString>("appId");
98+ QTest::addColumn<bool>("setCount");
99+ QTest::addColumn<int>("inCount");
100+ QTest::addColumn<bool>("countVisible");
101+ QTest::addColumn<int>("expectedCount");
102+
103+ /* Get baseline data on things working */
104+ QTest::newRow("Baseline") << "rel-icon" << false << 0 << false << -1;
105+
106+ /* Valid count, but not visible */
107+ QTest::newRow("Not visible") << "rel-icon" << true << 42 << false << -1;
108+
109+ /* Turn it on */
110+ QTest::newRow("Visible Count") << "rel-icon" << true << 42 << true << 42;
111+
112+ /* Invalide app to load */
113+ QTest::newRow("Invalid App ID") << "this-app-doesnt-exist" << true << 42 << true << -1;
114+ }
115+
116+ void testCount() {
117+ QFETCH(QString, appId);
118+ QFETCH(bool, setCount);
119+ QFETCH(int, inCount);
120+ QFETCH(bool, countVisible);
121+ QFETCH(int, expectedCount);
122+
123+ LauncherBackend backend;
124+
125+ if (setCount)
126+ backend.setCount(appId, inCount);
127+ backend.setCountVisible(appId, countVisible);
128+
129+ QCOMPARE(backend.count(appId), expectedCount);
130+ }
131+
132+ void testDbusName_data() {
133+ QTest::addColumn<QString>("decoded");
134+ QTest::addColumn<QString>("encoded");
135+
136+ /* Passthrough test */
137+ QTest::newRow("Passthrough") << "fine" << "fine";
138+
139+ /* Number as first characeter */
140+ QTest::newRow("Number first") << "31337" << "_331337";
141+
142+ /* Underscore test */
143+ QTest::newRow("Underscore test") << "this_is_c_style_namespacing" << "this_5Fis_5Fc_5Fstyle_5Fnamespacing";
144+
145+ /* Hyphen test */
146+ QTest::newRow("Hyphen test") << "typical-application" << "typical_2Dapplication";
147+
148+ /* Japanese test */
149+ QTest::newRow("日本語 test") << "日本語" << "_E6_97_A5_E6_9C_AC_E8_AA_9E";
150+ }
151+
152+ void testDbusName() {
153+ QFETCH(QString, decoded);
154+ QFETCH(QString, encoded);
155+
156+ QString encodeOut = LauncherBackend::encodeAppId(decoded);
157+ QCOMPARE(encoded, encodeOut);
158+
159+ QString decodeOut = LauncherBackend::decodeAppId(encoded);
160+ QCOMPARE(decoded, decodeOut);
161+ }
162+
163+ void testDbusIface_data() {
164+ QTest::addColumn<QString>("appId");
165+ QTest::addColumn<bool>("setCount");
166+ QTest::addColumn<int>("inCount");
167+ QTest::addColumn<bool>("countVisible");
168+ QTest::addColumn<int>("expectedCount");
169+
170+ /* Get baseline data on things working */
171+ QTest::newRow("Baseline") << "rel-icon" << false << 0 << false << -1;
172+
173+ /* Turn it on */
174+ QTest::newRow("Visible Count") << "rel-icon" << true << 42 << true << 42;
175+
176+ /* Invalide app to load */
177+ QTest::newRow("Invalid App ID") << "this-app-doesnt-exist" << true << 42 << true << -1;
178+ }
179+
180+ void testDbusIface() {
181+ QFETCH(QString, appId);
182+ QFETCH(bool, setCount);
183+ QFETCH(int, inCount);
184+ QFETCH(bool, countVisible);
185+ QFETCH(int, expectedCount);
186+
187+ QDBusConnection con = QDBusConnection::sessionBus();
188+ QDBusMessage message;
189+ QDBusMessage reply;
190+
191+ LauncherBackend backend;
192+
193+ if (setCount) {
194+ message = QDBusMessage::createMethodCall("com.canonical.Unity.Launcher",
195+ "/com/canonical/Unity/Launcher/" + LauncherBackend::encodeAppId(appId),
196+ "org.freedesktop.DBus.Properties",
197+ "Set");
198+ QVariantList cargs;
199+ cargs.append(QString("com.canonical.Unity.Launcher.Item"));
200+ cargs.append(QString("count"));
201+ cargs.append(QVariant::fromValue(QDBusVariant(inCount)));
202+
203+ message.setArguments(cargs);
204+ reply = con.call(message);
205+ QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
206+ }
207+
208+ /* Set countVisible */
209+ message = QDBusMessage::createMethodCall("com.canonical.Unity.Launcher",
210+ "/com/canonical/Unity/Launcher/" + LauncherBackend::encodeAppId(appId),
211+ "org.freedesktop.DBus.Properties",
212+ "Set");
213+ QVariantList cvargs;
214+ cvargs.append(QString("com.canonical.Unity.Launcher.Item"));
215+ cvargs.append(QString("countVisible"));
216+ cvargs.append(QVariant::fromValue(QDBusVariant(countVisible)));
217+
218+ message.setArguments(cvargs);
219+ reply = con.call(message);
220+ QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
221+
222+ /* Get value */
223+ message = QDBusMessage::createMethodCall("com.canonical.Unity.Launcher",
224+ "/com/canonical/Unity/Launcher/" + LauncherBackend::encodeAppId(appId),
225+ "org.freedesktop.DBus.Properties",
226+ "Get");
227+ QVariantList getargs;
228+ getargs.append(QString("com.canonical.Unity.Launcher.Item"));
229+ getargs.append(QString("count"));
230+
231+ message.setArguments(getargs);
232+ reply = con.call(message);
233+ QCOMPARE(reply.type(), QDBusMessage::ReplyMessage);
234+ QCOMPARE(reply.arguments()[0].value<QDBusVariant>().variant().toInt(), expectedCount);
235+ }
69236};
70237
71238QTEST_GUILESS_MAIN(LauncherBackendTest)