Lomiri
Loading...
Searching...
No Matches
dbusinterface.cpp
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Michael Zanetti <michael.zanetti@canonical.com>
18 */
19
20#include "dbusinterface.h"
21#include "launchermodel.h"
22#include "launcheritem.h"
23
24#include <QDBusArgument>
25#include <QDBusConnection>
26#include <QDBusMessage>
27#include <QDebug>
28
29DBusInterface::DBusInterface(LauncherModel *parent):
30 LomiriDBusVirtualObject(QStringLiteral("/com/lomiri/Shell/Launcher"), QStringLiteral("com.lomiri.Shell.Launcher"), true, parent),
31 m_launcherModel(parent)
32{
33}
34
35QString DBusInterface::introspect(const QString &path) const
36{
37 /* This case we should just list the nodes */
38 if (path == QLatin1String("/com/lomiri/Shell/Launcher/") || path == QLatin1String("/com/lomiri/Shell/Launcher")) {
39 QString nodes;
40
41 // Add Refresh to introspect
42 nodes = QStringLiteral("<interface name=\"com.lomiri.Shell.Launcher\">"
43 "<method name=\"Refresh\"/>"
44 "</interface>");
45
46 // Add dynamic properties for launcher emblems
47 for (int i = 0; i < m_launcherModel->rowCount(); i++) {
48 nodes.append("<node name=\"");
49 nodes.append(encodeAppId(m_launcherModel->get(i)->appId()));
50 nodes.append("\"/>\n");
51 }
52 return nodes;
53 }
54
55 /* Should not happen, but let's handle it */
56 if (!path.startsWith(QLatin1String("/com/lomiri/Shell/Launcher"))) {
57 return QLatin1String("");
58 }
59
60 /* Now we should be looking at a node */
61 QString nodeiface =
62 QStringLiteral("<interface name=\"com.lomiri.Shell.Launcher.Item\">"
63 "<property name=\"count\" type=\"i\" access=\"readwrite\" />"
64 "<property name=\"countVisible\" type=\"b\" access=\"readwrite\" />"
65 "<property name=\"progress\" type=\"i\" access=\"readwrite\" />"
66 "<method name=\"Alert\" />"
67 "</interface>");
68 return nodeiface;
69}
70
71
72QString DBusInterface::decodeAppId(const QString& path)
73{
74 QByteArray bytes = path.toUtf8();
75 QByteArray decoded;
76
77 for (int i = 0; i < bytes.size(); ++i) {
78 char chr = bytes.at(i);
79
80 if (chr == '_') {
81 QString number;
82 number.append(bytes.at(i+1));
83 number.append(bytes.at(i+2));
84
85 bool okay;
86 char newchar = number.toUInt(&okay, 16);
87 if (okay)
88 decoded.append(newchar);
89
90 i += 2;
91 } else {
92 decoded.append(chr);
93 }
94 }
95
96 return QString::fromUtf8(decoded);
97}
98
99QString DBusInterface::encodeAppId(const QString& appId)
100{
101 QByteArray bytes = appId.toUtf8();
102 QString encoded;
103
104 for (int i = 0; i < bytes.size(); ++i) {
105 uchar chr = bytes.at(i);
106
107 if ((chr >= 'a' && chr <= 'z') ||
108 (chr >= 'A' && chr <= 'Z') ||
109 (chr >= '0' && chr <= '9'&& i != 0)) {
110 encoded.append(chr);
111 } else {
112 QString hexval = QStringLiteral("_%1").arg(chr, 2, 16, QChar('0'));
113 encoded.append(hexval.toUpper());
114 }
115 }
116
117 return encoded;
118}
119
120bool DBusInterface::handleMessage(const QDBusMessage& message, const QDBusConnection& connection)
121{
122 /* Check to make sure we're getting properties on our interface */
123 if (message.type() != QDBusMessage::MessageType::MethodCallMessage) {
124 return false;
125 }
126
127 /* Break down the path to just the app id */
128 bool validpath = true;
129 QString pathtemp = message.path();
130 if (!pathtemp.startsWith(QLatin1String("/com/lomiri/Shell/Launcher/"))) {
131 validpath = false;
132 }
133 pathtemp.remove(QStringLiteral("/com/lomiri/Shell/Launcher/"));
134 if (pathtemp.indexOf('/') >= 0) {
135 validpath = false;
136 }
137
138 /* Find ourselves an appid */
139 QString appid = decodeAppId(pathtemp);
140
141 // First handle methods of the Launcher interface
142 if (message.interface() == QLatin1String("com.lomiri.Shell.Launcher")) {
143 if (message.member() == QLatin1String("Refresh")) {
144 QDBusMessage reply = message.createReply();
145 Q_EMIT refreshCalled();
146 return connection.send(reply);
147 }
148 } else if (message.interface() == QLatin1String("com.lomiri.Shell.Launcher.Item")) {
149 // Handle methods of the Launcher-Item interface
150 if (message.member() == QLatin1String("Alert") && validpath) {
151 QDBusMessage reply = message.createReply();
152 Q_EMIT alertCalled(appid);
153 return connection.send(reply);
154 }
155 }
156
157 // Now handle dynamic properties (for launcher emblems)
158 if (message.interface() != QLatin1String("org.freedesktop.DBus.Properties")) {
159 return false;
160 }
161
162 const QList<QVariant> messageArguments = message.arguments();
163 if (message.member() == QLatin1String("Get") && (messageArguments.count() != 2 || messageArguments[0].toString() != QLatin1String("com.lomiri.Shell.Launcher.Item"))) {
164 return false;
165 }
166
167 if (message.member() == QLatin1String("Set") && (messageArguments.count() != 3 || messageArguments[0].toString() != QLatin1String("com.lomiri.Shell.Launcher.Item"))) {
168 return false;
169 }
170
171 if (!validpath) {
172 return false;
173 }
174
175 int index = m_launcherModel->findApplication(appid);
176 LauncherItem *item = static_cast<LauncherItem*>(m_launcherModel->get(index));
177
178 QVariantList retval;
179 if (message.member() == QLatin1String("Get")) {
180 QString cachedString = messageArguments[1].toString();
181 if (!item) {
182 return false;
183 }
184 if (cachedString == QLatin1String("count")) {
185 retval.append(QVariant::fromValue(QDBusVariant(item->count())));
186 } else if (cachedString == QLatin1String("countVisible")) {
187 retval.append(QVariant::fromValue(QDBusVariant(item->countVisible())));
188 } else if (cachedString == QLatin1String("progress")) {
189 retval.append(QVariant::fromValue(QDBusVariant(item->progress())));
190 }
191 } else if (message.member() == QLatin1String("Set")) {
192 QString cachedString = messageArguments[1].toString();
193 if (cachedString == QLatin1String("count")) {
194 int newCount = messageArguments[2].value<QDBusVariant>().variant().toInt();
195 if (!item || newCount != item->count()) {
196 Q_EMIT countChanged(appid, newCount);
197 notifyPropertyChanged(QStringLiteral("com.lomiri.Shell.Launcher.Item"), encodeAppId(appid), QStringLiteral("count"), QVariant(newCount));
198 }
199 } else if (cachedString == QLatin1String("countVisible")) {
200 bool newVisible = messageArguments[2].value<QDBusVariant>().variant().toBool();
201 if (!item || newVisible != item->countVisible()) {
202 Q_EMIT countVisibleChanged(appid, newVisible);
203 notifyPropertyChanged(QStringLiteral("com.lomiri.Shell.Launcher.Item"), encodeAppId(appid), QStringLiteral("countVisible"), newVisible);
204 }
205 } else if (cachedString == QLatin1String("progress")) {
206 int newProgress = messageArguments[2].value<QDBusVariant>().variant().toInt();
207 if (!item || newProgress != item->progress()) {
208 Q_EMIT progressChanged(appid, newProgress);
209 notifyPropertyChanged(QStringLiteral("com.lomiri.Shell.Launcher.Item"), encodeAppId(appid), QStringLiteral("progress"), QVariant(newProgress));
210 }
211 }
212 } else if (message.member() == QLatin1String("GetAll")) {
213 if (item) {
214 QVariantMap all;
215 all.insert(QStringLiteral("count"), item->count());
216 all.insert(QStringLiteral("countVisible"), item->countVisible());
217 all.insert(QStringLiteral("progress"), item->progress());
218 retval.append(all);
219 }
220 } else {
221 return false;
222 }
223
224 QDBusMessage reply = message.createReply(retval);
225 return connection.send(reply);
226}