2006-02-13 John (J5) Palmieri <johnp@redhat.com>
[platform/upstream/dbus.git] / qt / qdbusconnection.cpp
1 /* qdbusconnection.cpp
2  *
3  * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
4  *
5  * Licensed under the Academic Free License version 2.1
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22
23 #include <QtCore/qdebug.h>
24 #include <QtCore/qcoreapplication.h>
25
26 #include "qdbusconnection.h"
27 #include "qdbusconnection_p.h"
28
29 QT_STATIC_CONST_IMPL char *QDBusConnection::default_connection_name = "qt_dbus_default_connection";
30
31 class QDBusConnectionManager
32 {
33 public:
34     QDBusConnectionManager(): default_connection(0) {}
35     ~QDBusConnectionManager();
36     void bindToApplication();
37     QDBusConnectionPrivate *connection(const QString &name) const;
38     void removeConnection(const QString &name);
39     void setConnection(const QString &name, QDBusConnectionPrivate *c);
40
41 private:
42     QDBusConnectionPrivate *default_connection;
43     QHash<QString, QDBusConnectionPrivate *> connectionHash;
44 };
45
46 Q_GLOBAL_STATIC(QDBusConnectionManager, manager);
47
48 QDBusConnectionPrivate *QDBusConnectionManager::connection(const QString &name) const
49 {
50     return name == QLatin1String(QDBusConnection::default_connection_name) ?
51             default_connection : connectionHash.value(name, 0);
52 }
53
54 void QDBusConnectionManager::removeConnection(const QString &name)
55 {
56     QDBusConnectionPrivate *d = 0;
57     if (name == QLatin1String(QDBusConnection::default_connection_name)) {
58         d = default_connection;
59         default_connection = 0;
60     } else {
61         d = connectionHash.take(name);
62     }
63     if (!d->ref.deref())
64         delete d;
65 }
66
67 QDBusConnectionManager::~QDBusConnectionManager()
68 {
69     if (default_connection) {
70         delete default_connection;
71         default_connection = 0;
72     }
73     for (QHash<QString, QDBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin();
74          it != connectionHash.constEnd(); ++it) {
75              delete it.value();
76     }
77     connectionHash.clear();
78 }
79
80 void QDBusConnectionManager::bindToApplication()
81 {
82     if (default_connection) {
83         default_connection->bindToApplication();
84     }
85     for (QHash<QString, QDBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin();
86          it != connectionHash.constEnd(); ++it) {
87              (*it)->bindToApplication();
88     }
89 }
90
91 void qDBusBindToApplication()
92 {
93     manager()->bindToApplication();
94 }
95
96 void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionPrivate *c)
97 {
98     if (name == QLatin1String(QDBusConnection::default_connection_name))
99         default_connection = c;
100     else
101         connectionHash[name] = c;
102 }
103
104
105 QDBusConnection::QDBusConnection(const QString &name)
106 {
107     d = manager()->connection(name);
108     if (d)
109         d->ref.ref();
110 }
111
112 QDBusConnection::QDBusConnection(const QDBusConnection &other)
113 {
114     d = other.d;
115     if (d)
116         d->ref.ref();
117 }
118
119 QDBusConnection::~QDBusConnection()
120 {
121     if (d && !d->ref.deref())
122         delete d;
123 }
124
125 QDBusConnection &QDBusConnection::operator=(const QDBusConnection &other)
126 {
127     if (other.d)
128         other.d->ref.ref();
129     QDBusConnectionPrivate *old = static_cast<QDBusConnectionPrivate *>(
130             q_atomic_set_ptr(&d, other.d));
131     if (old && !old->ref.deref())
132         delete old;
133
134     return *this;
135 }
136
137 QDBusConnection QDBusConnection::addConnection(BusType type, const QString &name)
138 {
139 //    Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection",
140 //               "Cannot create connection without a Q[Core]Application instance");
141
142     QDBusConnectionPrivate *d = manager()->connection(name);
143     if (d)
144         return QDBusConnection(name);
145
146     d = new QDBusConnectionPrivate;
147     DBusConnection *c = 0;
148     switch (type) {
149         case SystemBus:
150             c = dbus_bus_get(DBUS_BUS_SYSTEM, &d->error);
151             break;
152         case SessionBus:
153             c = dbus_bus_get(DBUS_BUS_SESSION, &d->error);
154             break;
155         case ActivationBus:
156             c = dbus_bus_get(DBUS_BUS_STARTER, &d->error);
157             break;
158     }
159     d->setConnection(c); //setConnection does the error handling for us
160
161     manager()->setConnection(name, d);
162
163     return QDBusConnection(name);
164 }
165
166 QDBusConnection QDBusConnection::addConnection(const QString &address,
167                     const QString &name)
168 {
169 //    Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection",
170 //               "Cannot create connection without a Q[Core]Application instance");
171
172     QDBusConnectionPrivate *d = manager()->connection(name);
173     if (d)
174         return QDBusConnection(name);
175
176     d = new QDBusConnectionPrivate;
177     // setConnection does the error handling for us
178     d->setConnection(dbus_connection_open(address.toUtf8().constData(), &d->error));
179
180     manager()->setConnection(name, d);
181
182     return QDBusConnection(name);
183 }
184
185 void QDBusConnection::closeConnection(const QString &name)
186 {
187     manager()->removeConnection(name);
188 }
189
190 void QDBusConnectionPrivate::timerEvent(QTimerEvent *e)
191 {
192     DBusTimeout *timeout = timeouts.value(e->timerId(), 0);
193     dbus_timeout_handle(timeout);
194 }
195
196 bool QDBusConnection::send(const QDBusMessage &message) const
197 {
198     if (!d || !d->connection)
199         return false;
200
201     DBusMessage *msg = message.toDBusMessage();
202     if (!msg)
203         return false;
204
205     bool isOk = dbus_connection_send(d->connection, msg, 0);
206     dbus_message_unref(msg);
207     return isOk;
208 }
209
210 int QDBusConnection::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
211         const char *method) const
212 {
213     if (!d || !d->connection)
214         return 0;
215
216     return d->sendWithReplyAsync(message, receiver, method);
217 }
218
219 QDBusMessage QDBusConnection::sendWithReply(const QDBusMessage &message) const
220 {
221     if (!d || !d->connection)
222         return QDBusMessage::fromDBusMessage(0);
223
224     DBusMessage *msg = message.toDBusMessage();
225     if (!msg)
226         return QDBusMessage::fromDBusMessage(0);
227     DBusMessage *reply = dbus_connection_send_with_reply_and_block(d->connection, msg,
228                                                 -1, &d->error);
229     d->handleError();
230     dbus_message_unref(msg);
231
232     return QDBusMessage::fromDBusMessage(reply);
233 }
234
235 bool QDBusConnection::connect(const QString &path, const QString &interface,
236                               const QString &name, QObject *receiver, const char *slot)
237 {
238     if (!receiver || !slot || !d || !d->connection)
239         return false;
240
241     QDBusConnectionPrivate::SignalHook hook;
242
243     hook.interface = interface;
244     hook.name = name;
245     hook.obj = QPointer<QObject>(receiver);
246     if (!hook.setSlot(slot + 1))
247         return false;
248
249     d->signalHooks.insertMulti(path, hook);
250     d->connect(receiver, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)));
251
252     return true;
253 }
254
255 bool QDBusConnection::registerObject(const QString &path, const QString &interface,
256                                      QObject *object)
257 {
258     if (!d || !d->connection || !object || path.isEmpty() || interface.isEmpty())
259         return false;
260
261     QDBusConnectionPrivate::ObjectHook hook;
262     hook.interface = interface;
263     hook.obj = object;
264
265     QDBusConnectionPrivate::ObjectHookHash::iterator it = d->objectHooks.find(path);
266     while (it != d->objectHooks.end() && it.key() == path) {
267         if (it.value().interface == interface) {
268             d->objectHooks.erase(it);
269             break;
270         }
271         ++it;
272     }
273
274     d->objectHooks.insert(path, hook);
275
276     d->connect(object, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)));
277     qDebug("REGISTERED FOR %s", path.toLocal8Bit().constData());
278
279     return true; // todo - check for slots etc.
280 }
281
282 void QDBusConnection::unregisterObject(const QString &path)
283 {
284     if (!d || !d->connection)
285         return;
286
287     // TODO - check interfaces
288     d->objectHooks.remove(path);
289 }
290
291 bool QDBusConnection::isConnected( ) const
292 {
293     return d && d->connection && dbus_connection_get_is_connected(d->connection);
294 }
295
296 QDBusError QDBusConnection::lastError() const
297 {
298     return d ? d->lastError : QDBusError();
299 }
300
301 QString QDBusConnection::baseService() const
302 {
303     return d && d->connection ?
304             QString::fromUtf8(dbus_bus_get_unique_name(d->connection))
305             : QString();
306 }
307
308 bool QDBusConnection::requestName(const QString &name, NameRequestMode mode)
309 {
310     //FIXME: DBUS_NAME_FLAGS_* are bit fields not enumeration
311     static const int DBusModes[] = { 0, DBUS_NAME_FLAG_ALLOW_REPLACEMENT,
312         DBUS_NAME_FLAG_REPLACE_EXISTING };
313     Q_ASSERT(mode == 0 || mode == AllowReplace ||
314              mode == ReplaceExisting );
315
316     DBusError error;
317     dbus_error_init (&error);
318     dbus_bus_request_name(d->connection, name.toUtf8(), DBusModes[mode], &error);
319     if (dbus_error_is_set (&error)) {
320         qDebug("Error %s\n", error.message);
321         dbus_error_free (&error);
322         return false;
323     }
324     return true;
325 }
326
327 #include "qdbusconnection.moc"