on bionic help sign in
unity8/plugins/Unity/Launcher/dbusinterface.cpp
228 lines 8.7 kB history raw
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 */
20#include "dbusinterface.h"
21#include "launchermodel.h"
22#include "launcheritem.h"
24#include <QDBusArgument>
25#include <QDBusConnection>
26#include <QDBusMessage>
27#include <QDebug>
29DBusInterface::DBusInterface(LauncherModel *parent):
30 UnityDBusVirtualObject(QStringLiteral("/com/canonical/Unity/Launcher"), QStringLiteral("com.canonical.Unity.Launcher"), true, parent),
31 m_launcherModel(parent)
35QString DBusInterface::introspect(const QString &path) const
37 /* This case we should just list the nodes */
38 if (path == QLatin1String("/com/canonical/Unity/Launcher/") || path == QLatin1String("/com/canonical/Unity/Launcher")) {
39 QString nodes;
41 // Add Refresh to introspect
42 // TODO: Confirm this is still used anywhere and remove if not.
43 // It used to be used in an upstart job when desktop fles changed.
44 nodes = QStringLiteral("<interface name=\"com.canonical.Unity.Launcher\">"
45 "<method name=\"Refresh\"/>"
46 "</interface>");
48 // Add dynamic properties for launcher emblems
49 for (int i = 0; i < m_launcherModel->rowCount(); i++) {
50 nodes.append("<node name=\"");
51 nodes.append(encodeAppId(m_launcherModel->get(i)->appId()));
52 nodes.append("\"/>\n");
53 }
54 return nodes;
55 }
57 /* Should not happen, but let's handle it */
58 if (!path.startsWith(QLatin1String("/com/canonical/Unity/Launcher"))) {
59 return QLatin1String("");
60 }
62 /* Now we should be looking at a node */
63 QString nodeiface =
64 QStringLiteral("<interface name=\"com.canonical.Unity.Launcher.Item\">"
65 "<property name=\"count\" type=\"i\" access=\"readwrite\" />"
66 "<property name=\"countVisible\" type=\"b\" access=\"readwrite\" />"
67 "<property name=\"progress\" type=\"i\" access=\"readwrite\" />"
68 "<method name=\"Alert\" />"
69 "</interface>");
70 return nodeiface;
74QString DBusInterface::decodeAppId(const QString& path)
76 QByteArray bytes = path.toUtf8();
77 QByteArray decoded;
79 for (int i = 0; i < bytes.size(); ++i) {
80 char chr = bytes.at(i);
82 if (chr == '_') {
83 QString number;
84 number.append(bytes.at(i+1));
85 number.append(bytes.at(i+2));
87 bool okay;
88 char newchar = number.toUInt(&okay, 16);
89 if (okay)
90 decoded.append(newchar);
92 i += 2;
93 } else {
94 decoded.append(chr);
95 }
96 }
98 return QString::fromUtf8(decoded);
101QString DBusInterface::encodeAppId(const QString& appId)
103 QByteArray bytes = appId.toUtf8();
104 QString encoded;
106 for (int i = 0; i < bytes.size(); ++i) {
107 uchar chr = bytes.at(i);
109 if ((chr >= 'a' && chr <= 'z') ||
110 (chr >= 'A' && chr <= 'Z') ||
111 (chr >= '0' && chr <= '9'&& i != 0)) {
112 encoded.append(chr);
113 } else {
114 QString hexval = QStringLiteral("_%1").arg(chr, 2, 16, QChar('0'));
115 encoded.append(hexval.toUpper());
116 }
117 }
119 return encoded;
122bool DBusInterface::handleMessage(const QDBusMessage& message, const QDBusConnection& connection)
124 /* Check to make sure we're getting properties on our interface */
125 if (message.type() != QDBusMessage::MessageType::MethodCallMessage) {
126 return false;
127 }
129 /* Break down the path to just the app id */
130 bool validpath = true;
131 QString pathtemp = message.path();
132 if (!pathtemp.startsWith(QLatin1String("/com/canonical/Unity/Launcher/"))) {
133 validpath = false;
134 }
135 pathtemp.remove(QStringLiteral("/com/canonical/Unity/Launcher/"));
136 if (pathtemp.indexOf('/') >= 0) {
137 validpath = false;
138 }
140 /* Find ourselves an appid */
141 QString appid = decodeAppId(pathtemp);
143 // First handle methods of the Launcher interface
144 if (message.interface() == QLatin1String("com.canonical.Unity.Launcher")) {
145 if (message.member() == QLatin1String("Refresh")) {
146 QDBusMessage reply = message.createReply();
147 Q_EMIT refreshCalled();
148 return connection.send(reply);
149 }
150 } else if (message.interface() == QLatin1String("com.canonical.Unity.Launcher.Item")) {
151 // Handle methods of the Launcher-Item interface
152 if (message.member() == QLatin1String("Alert") && validpath) {
153 QDBusMessage reply = message.createReply();
154 Q_EMIT alertCalled(appid);
155 return connection.send(reply);
156 }
157 }
159 // Now handle dynamic properties (for launcher emblems)
160 if (message.interface() != QLatin1String("org.freedesktop.DBus.Properties")) {
161 return false;
162 }
164 const QList<QVariant> messageArguments = message.arguments();
165 if (message.member() == QLatin1String("Get") && (messageArguments.count() != 2 || messageArguments[0].toString() != QLatin1String("com.canonical.Unity.Launcher.Item"))) {
166 return false;
167 }
169 if (message.member() == QLatin1String("Set") && (messageArguments.count() != 3 || messageArguments[0].toString() != QLatin1String("com.canonical.Unity.Launcher.Item"))) {
170 return false;
171 }
173 if (!validpath) {
174 return false;
175 }
177 int index = m_launcherModel->findApplication(appid);
178 LauncherItem *item = static_cast<LauncherItem*>(m_launcherModel->get(index));
180 QVariantList retval;
181 if (message.member() == QLatin1String("Get")) {
182 QString cachedString = messageArguments[1].toString();
183 if (!item) {
184 return false;
185 }
186 if (cachedString == QLatin1String("count")) {
187 retval.append(QVariant::fromValue(QDBusVariant(item->count())));
188 } else if (cachedString == QLatin1String("countVisible")) {
189 retval.append(QVariant::fromValue(QDBusVariant(item->countVisible())));
190 } else if (cachedString == QLatin1String("progress")) {
191 retval.append(QVariant::fromValue(QDBusVariant(item->progress())));
192 }
193 } else if (message.member() == QLatin1String("Set")) {
194 QString cachedString = messageArguments[1].toString();
195 if (cachedString == QLatin1String("count")) {
196 int newCount = messageArguments[2].value<QDBusVariant>().variant().toInt();
197 if (!item || newCount != item->count()) {
198 Q_EMIT countChanged(appid, newCount);
199 notifyPropertyChanged(QStringLiteral("com.canonical.Unity.Launcher.Item"), encodeAppId(appid), QStringLiteral("count"), QVariant(newCount));
200 }
201 } else if (cachedString == QLatin1String("countVisible")) {
202 bool newVisible = messageArguments[2].value<QDBusVariant>().variant().toBool();
203 if (!item || newVisible != item->countVisible()) {
204 Q_EMIT countVisibleChanged(appid, newVisible);
205 notifyPropertyChanged(QStringLiteral("com.canonical.Unity.Launcher.Item"), encodeAppId(appid), QStringLiteral("countVisible"), newVisible);
206 }
207 } else if (cachedString == QLatin1String("progress")) {
208 int newProgress = messageArguments[2].value<QDBusVariant>().variant().toInt();
209 if (!item || newProgress != item->progress()) {
210 Q_EMIT progressChanged(appid, newProgress);
211 notifyPropertyChanged(QStringLiteral("com.canonical.Unity.Launcher.Item"), encodeAppId(appid), QStringLiteral("progress"), QVariant(newProgress));
212 }
213 }
214 } else if (message.member() == QLatin1String("GetAll")) {
215 if (item) {
216 QVariantMap all;
217 all.insert(QStringLiteral("count"), item->count());
218 all.insert(QStringLiteral("countVisible"), item->countVisible());
219 all.insert(QStringLiteral("progress"), item->progress());
220 retval.append(all);
221 }
222 } else {
223 return false;
224 }
226 QDBusMessage reply = message.createReply(retval);
227 return connection.send(reply);