qdbusconnection.cpp

00001 /* qdbusconnection.cpp
00002  *
00003  * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
00004  *
00005  * Licensed under the Academic Free License version 2.1
00006  *
00007  * This program is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  *
00021  */
00022 
00023 #include <QtCore/qdebug.h>
00024 #include <QtCore/qcoreapplication.h>
00025 
00026 #include "qdbusconnection.h"
00027 #include "qdbusconnection_p.h"
00028 
00029 QT_STATIC_CONST_IMPL char *QDBusConnection::default_connection_name = "qt_dbus_default_connection";
00030 
00031 class QDBusConnectionManager
00032 {
00033 public:
00034     QDBusConnectionManager(): default_connection(0) {}
00035     ~QDBusConnectionManager();
00036     void bindToApplication();
00037     QDBusConnectionPrivate *connection(const QString &name) const;
00038     void removeConnection(const QString &name);
00039     void setConnection(const QString &name, QDBusConnectionPrivate *c);
00040 
00041 private:
00042     QDBusConnectionPrivate *default_connection;
00043     QHash<QString, QDBusConnectionPrivate *> connectionHash;
00044 };
00045 
00046 Q_GLOBAL_STATIC(QDBusConnectionManager, manager);
00047 
00048 QDBusConnectionPrivate *QDBusConnectionManager::connection(const QString &name) const
00049 {
00050     return name == QLatin1String(QDBusConnection::default_connection_name) ?
00051             default_connection : connectionHash.value(name, 0);
00052 }
00053 
00054 void QDBusConnectionManager::removeConnection(const QString &name)
00055 {
00056     QDBusConnectionPrivate *d = 0;
00057     if (name == QLatin1String(QDBusConnection::default_connection_name)) {
00058         d = default_connection;
00059         default_connection = 0;
00060     } else {
00061         d = connectionHash.take(name);
00062     }
00063     if (!d->ref.deref())
00064         delete d;
00065 }
00066 
00067 QDBusConnectionManager::~QDBusConnectionManager()
00068 {
00069     if (default_connection) {
00070         delete default_connection;
00071         default_connection = 0;
00072     }
00073     for (QHash<QString, QDBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin();
00074          it != connectionHash.constEnd(); ++it) {
00075              delete it.value();
00076     }
00077     connectionHash.clear();
00078 }
00079 
00080 void QDBusConnectionManager::bindToApplication()
00081 {
00082     if (default_connection) {
00083         default_connection->bindToApplication();
00084     }
00085     for (QHash<QString, QDBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin();
00086          it != connectionHash.constEnd(); ++it) {
00087              (*it)->bindToApplication();
00088     }
00089 }
00090 
00091 void qDBusBindToApplication()
00092 {
00093     manager()->bindToApplication();
00094 }
00095 
00096 void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionPrivate *c)
00097 {
00098     if (name == QLatin1String(QDBusConnection::default_connection_name))
00099         default_connection = c;
00100     else
00101         connectionHash[name] = c;
00102 }
00103 
00104 
00105 QDBusConnection::QDBusConnection(const QString &name)
00106 {
00107     d = manager()->connection(name);
00108     if (d)
00109         d->ref.ref();
00110 }
00111 
00112 QDBusConnection::QDBusConnection(const QDBusConnection &other)
00113 {
00114     d = other.d;
00115     if (d)
00116         d->ref.ref();
00117 }
00118 
00119 QDBusConnection::~QDBusConnection()
00120 {
00121     if (d && !d->ref.deref())
00122         delete d;
00123 }
00124 
00125 QDBusConnection &QDBusConnection::operator=(const QDBusConnection &other)
00126 {
00127     if (other.d)
00128         other.d->ref.ref();
00129     QDBusConnectionPrivate *old = static_cast<QDBusConnectionPrivate *>(
00130             q_atomic_set_ptr(&d, other.d));
00131     if (old && !old->ref.deref())
00132         delete old;
00133 
00134     return *this;
00135 }
00136 
00137 QDBusConnection QDBusConnection::addConnection(BusType type, const QString &name)
00138 {
00139 //    Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection",
00140 //               "Cannot create connection without a Q[Core]Application instance");
00141 
00142     QDBusConnectionPrivate *d = manager()->connection(name);
00143     if (d)
00144         return QDBusConnection(name);
00145 
00146     d = new QDBusConnectionPrivate;
00147     DBusConnection *c = 0;
00148     switch (type) {
00149         case SystemBus:
00150             c = dbus_bus_get(DBUS_BUS_SYSTEM, &d->error);
00151             break;
00152         case SessionBus:
00153             c = dbus_bus_get(DBUS_BUS_SESSION, &d->error);
00154             break;
00155         case ActivationBus:
00156             c = dbus_bus_get(DBUS_BUS_STARTER, &d->error);
00157             break;
00158     }
00159     d->setConnection(c); //setConnection does the error handling for us
00160 
00161     manager()->setConnection(name, d);
00162 
00163     return QDBusConnection(name);
00164 }
00165 
00166 QDBusConnection QDBusConnection::addConnection(const QString &address,
00167                     const QString &name)
00168 {
00169 //    Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection",
00170 //               "Cannot create connection without a Q[Core]Application instance");
00171 
00172     QDBusConnectionPrivate *d = manager()->connection(name);
00173     if (d)
00174         return QDBusConnection(name);
00175 
00176     d = new QDBusConnectionPrivate;
00177     // setConnection does the error handling for us
00178     d->setConnection(dbus_connection_open(address.toUtf8().constData(), &d->error));
00179 
00180     manager()->setConnection(name, d);
00181 
00182     return QDBusConnection(name);
00183 }
00184 
00185 void QDBusConnection::closeConnection(const QString &name)
00186 {
00187     manager()->removeConnection(name);
00188 }
00189 
00190 void QDBusConnectionPrivate::timerEvent(QTimerEvent *e)
00191 {
00192     DBusTimeout *timeout = timeouts.value(e->timerId(), 0);
00193     dbus_timeout_handle(timeout);
00194 }
00195 
00196 bool QDBusConnection::send(const QDBusMessage &message) const
00197 {
00198     if (!d || !d->connection)
00199         return false;
00200 
00201     DBusMessage *msg = message.toDBusMessage();
00202     if (!msg)
00203         return false;
00204 
00205     bool isOk = dbus_connection_send(d->connection, msg, 0);
00206     dbus_message_unref(msg);
00207     return isOk;
00208 }
00209 
00210 int QDBusConnection::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
00211         const char *method) const
00212 {
00213     if (!d || !d->connection)
00214         return 0;
00215 
00216     return d->sendWithReplyAsync(message, receiver, method);
00217 }
00218 
00219 QDBusMessage QDBusConnection::sendWithReply(const QDBusMessage &message) const
00220 {
00221     if (!d || !d->connection)
00222         return QDBusMessage::fromDBusMessage(0);
00223 
00224     DBusMessage *msg = message.toDBusMessage();
00225     if (!msg)
00226         return QDBusMessage::fromDBusMessage(0);
00227     DBusMessage *reply = dbus_connection_send_with_reply_and_block(d->connection, msg,
00228                                                 -1, &d->error);
00229     d->handleError();
00230     dbus_message_unref(msg);
00231 
00232     return QDBusMessage::fromDBusMessage(reply);
00233 }
00234 
00235 bool QDBusConnection::connect(const QString &path, const QString &interface,
00236                               const QString &name, QObject *receiver, const char *slot)
00237 {
00238     if (!receiver || !slot || !d || !d->connection)
00239         return false;
00240 
00241     QDBusConnectionPrivate::SignalHook hook;
00242 
00243     hook.interface = interface;
00244     hook.name = name;
00245     hook.obj = QPointer<QObject>(receiver);
00246     if (!hook.setSlot(slot + 1))
00247         return false;
00248 
00249     d->signalHooks.insertMulti(path, hook);
00250     d->connect(receiver, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)));
00251 
00252     return true;
00253 }
00254 
00255 bool QDBusConnection::registerObject(const QString &path, const QString &interface,
00256                                      QObject *object)
00257 {
00258     if (!d || !d->connection || !object || path.isEmpty() || interface.isEmpty())
00259         return false;
00260 
00261     QDBusConnectionPrivate::ObjectHook hook;
00262     hook.interface = interface;
00263     hook.obj = object;
00264 
00265     QDBusConnectionPrivate::ObjectHookHash::iterator it = d->objectHooks.find(path);
00266     while (it != d->objectHooks.end() && it.key() == path) {
00267         if (it.value().interface == interface) {
00268             d->objectHooks.erase(it);
00269             break;
00270         }
00271         ++it;
00272     }
00273 
00274     d->objectHooks.insert(path, hook);
00275 
00276     d->connect(object, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)));
00277     qDebug("REGISTERED FOR %s", path.toLocal8Bit().constData());
00278 
00279     return true; // todo - check for slots etc.
00280 }
00281 
00282 void QDBusConnection::unregisterObject(const QString &path)
00283 {
00284     if (!d || !d->connection)
00285         return;
00286 
00287     // TODO - check interfaces
00288     d->objectHooks.remove(path);
00289 }
00290 
00291 bool QDBusConnection::isConnected( ) const
00292 {
00293     return d && d->connection && dbus_connection_get_is_connected(d->connection);
00294 }
00295 
00296 QDBusError QDBusConnection::lastError() const
00297 {
00298     return d ? d->lastError : QDBusError();
00299 }
00300 
00301 QString QDBusConnection::baseService() const
00302 {
00303     return d && d->connection ?
00304             QString::fromUtf8(dbus_bus_get_unique_name(d->connection))
00305             : QString();
00306 }
00307 
00308 bool QDBusConnection::requestName(const QString &name, NameRequestMode mode)
00309 {
00310     //FIXME: DBUS_NAME_FLAGS_* are bit fields not enumeration
00311     static const int DBusModes[] = { 0, DBUS_NAME_FLAG_ALLOW_REPLACEMENT,
00312         DBUS_NAME_FLAG_REPLACE_EXISTING };
00313     Q_ASSERT(mode == 0 || mode == AllowReplace ||
00314              mode == ReplaceExisting );
00315 
00316     DBusError error;
00317     dbus_error_init (&error);
00318     dbus_bus_request_name(d->connection, name.toUtf8(), DBusModes[mode], &error);
00319     if (dbus_error_is_set (&error)) {
00320         qDebug("Error %s\n", error.message);
00321         dbus_error_free (&error);
00322         return false;
00323     }
00324     return true;
00325 }
00326 
00327 #include "qdbusconnection.moc"

Generated on Wed Feb 27 10:13:38 2008 for D-BUS by  doxygen 1.4.6