/* qdbusconnection.cpp * * Copyright (C) 2005 Harald Fernengel * Copyright (C) 2005-2007 Kevin Krammer * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. * */ #include #include "tqdbusconnection.h" #include "tqdbuserror.h" #include "tqdbusmessage.h" #include "tqdbusconnection_p.h" #include "tqdbusmessage_p.h" QT_STATIC_CONST_IMPL char *TQT_DBusConnection::default_connection_name = "qt_dbus_default_connection"; class TQT_DBusConnectionManager { public: TQT_DBusConnectionManager(): default_connection(0) {} ~TQT_DBusConnectionManager(); void bindToApplication(); TQT_DBusConnectionPrivate *connection(const TQString &name) const; void removeConnection(const TQString &name); void setConnection(const TQString &name, TQT_DBusConnectionPrivate *c); static TQT_DBusConnectionManager* instance() { if (managerInstance == 0) managerInstance = new TQT_DBusConnectionManager(); return managerInstance; } private: TQT_DBusConnectionPrivate *default_connection; // FIXME-QT4 TQHash connectionHash; typedef TQMap ConnectionHash; ConnectionHash connectionHash; static TQT_DBusConnectionManager* managerInstance; }; // FIXME-QT4 TQ_GLOBAL_STATIC(TQT_DBusConnectionManager, manager); TQT_DBusConnectionManager* TQT_DBusConnectionManager::managerInstance = 0; TQT_DBusConnectionManager* manager() { return TQT_DBusConnectionManager::instance(); } TQT_DBusConnectionPrivate *TQT_DBusConnectionManager::connection(const TQString &name) const { if (name == TQString::fromLatin1(TQT_DBusConnection::default_connection_name)) return default_connection; ConnectionHash::const_iterator it = connectionHash.find(name); return (it != connectionHash.end() ? it.data() : 0); } void TQT_DBusConnectionManager::removeConnection(const TQString &name) { TQT_DBusConnectionPrivate *d = 0; if (name == TQString::fromLatin1(TQT_DBusConnection::default_connection_name)) { d = default_connection; default_connection = 0; } else { ConnectionHash::iterator it = connectionHash.find(name); if (it == connectionHash.end()) return; d = it.data(); connectionHash.erase(it); } if (!d->ref.deref()) delete d; } TQT_DBusConnectionManager::~TQT_DBusConnectionManager() { if (default_connection) { delete default_connection; default_connection = 0; } /* FIXME-QT4 for (TQHash::const_iterator it = connectionHash.constBegin(); it != connectionHash.constEnd(); ++it) { delete it.value(); }*/ for (ConnectionHash::const_iterator it = connectionHash.constBegin(); it != connectionHash.constEnd(); ++it) { delete it.data(); } connectionHash.clear(); } void TQT_DBusConnectionManager::bindToApplication() { if (default_connection) { default_connection->bindToApplication(); } /* FIXME-QT4 for (TQHash::const_iterator it = connectionHash.constBegin(); it != connectionHash.constEnd(); ++it) { (*it)->bindToApplication(); }*/ for (ConnectionHash::const_iterator it = connectionHash.constBegin(); it != connectionHash.constEnd(); ++it) { it.data()->bindToApplication(); } } void qDBusBindToApplication() { manager()->bindToApplication(); } void TQT_DBusConnectionManager::setConnection(const TQString &name, TQT_DBusConnectionPrivate *c) { if (name == TQString::fromLatin1(TQT_DBusConnection::default_connection_name)) default_connection = c; else connectionHash[name] = c; } TQT_DBusConnection::TQT_DBusConnection() : d(0) { } TQT_DBusConnection::TQT_DBusConnection(const TQString &name) { d = manager()->connection(name); if (d) d->ref.ref(); } TQT_DBusConnection::TQT_DBusConnection(const TQT_DBusConnection &other) { d = other.d; if (d) d->ref.ref(); } TQT_DBusConnection::~TQT_DBusConnection() { if (d && !d->ref.deref()) delete d; } TQT_DBusConnection &TQT_DBusConnection::operator=(const TQT_DBusConnection &other) { if (other.d) other.d->ref.ref(); /* FIXME-QT4 TQT_DBusConnectionPrivate *old = static_cast( q_atomic_set_ptr(&d, other.d));*/ TQT_DBusConnectionPrivate* old = d; d = other.d; if (old && !old->ref.deref()) delete old; return *this; } TQT_DBusConnection TQT_DBusConnection::sessionBus() { return addConnection(TQT_DBusConnection::SessionBus); } TQT_DBusConnection TQT_DBusConnection::systemBus() { return addConnection(TQT_DBusConnection::SystemBus); } TQT_DBusConnection TQT_DBusConnection::addConnection(BusType type, const TQString &name) { // Q_ASSERT_X(TQCoreApplication::instance(), "TQT_DBusConnection::addConnection", // "Cannot create connection without a Q[Core]Application instance"); TQT_DBusConnectionPrivate *d = manager()->connection(name); if (d) return TQT_DBusConnection(name); d = new TQT_DBusConnectionPrivate; DBusConnection *c = 0; switch (type) { case SystemBus: c = dbus_bus_get(DBUS_BUS_SYSTEM, &d->error); break; case SessionBus: c = dbus_bus_get(DBUS_BUS_SESSION, &d->error); break; case ActivationBus: c = dbus_bus_get(DBUS_BUS_STARTER, &d->error); break; } d->setConnection(c); //setConnection does the error handling for us manager()->setConnection(name, d); return TQT_DBusConnection(name); } TQT_DBusConnection TQT_DBusConnection::addConnection(const TQString &address, const TQString &name) { // Q_ASSERT_X(TQCoreApplication::instance(), "TQT_DBusConnection::addConnection", // "Cannot create connection without a Q[Core]Application instance"); TQT_DBusConnectionPrivate *d = manager()->connection(name); if (d) return TQT_DBusConnection(name); d = new TQT_DBusConnectionPrivate; // setConnection does the error handling for us d->setConnection(dbus_connection_open(address.utf8().data(), &d->error)); manager()->setConnection(name, d); return TQT_DBusConnection(name); } void TQT_DBusConnection::closeConnection(const TQString &name) { manager()->removeConnection(name); } void TQT_DBusConnectionPrivate::timerEvent(TQTimerEvent *e) { DBusTimeout *timeout = timeouts[e->timerId()]; dbus_timeout_handle(timeout); } bool TQT_DBusConnection::send(const TQT_DBusMessage &message) const { if (!d || !d->connection) return false; DBusMessage *msg = message.toDBusMessage(); if (!msg) return false; bool isOk = dbus_connection_send(d->connection, msg, 0); dbus_message_unref(msg); return isOk; } int TQT_DBusConnection::sendWithAsyncReply(const TQT_DBusMessage &message, TQObject *receiver, const char *method) const { if (!d || !d->connection) return 0; return d->sendWithReplyAsync(message, receiver, method); } TQT_DBusMessage TQT_DBusConnection::sendWithReply(const TQT_DBusMessage &message, TQT_DBusError *error) const { if (!d || !d->connection) return TQT_DBusMessage::fromDBusMessage(0); DBusMessage *msg = message.toDBusMessage(); if (!msg) return TQT_DBusMessage::fromDBusMessage(0); DBusMessage *reply = dbus_connection_send_with_reply_and_block(d->connection, msg, -1, &d->error); if (d->handleError() && error) *error = d->lastError; dbus_message_unref(msg); TQT_DBusMessage ret = TQT_DBusMessage::fromDBusMessage(reply); // HACK // Reset the error object if no error was reported by DBus // This is needed because TQT_DBusMessage::fromDBusMessage sometimes sets the error object even if DBus did not report a fatal error, // and the dbus_error_is_set() check cannot be moved inside fromDBusMessage() without breaking the API and ABI. if (!dbus_error_is_set(&d->error)) { ret.d->error = TQT_DBusError(); } return ret; } void TQT_DBusConnection::flush() const { if (!d || !d->connection) return; d->flush(); } void TQT_DBusConnection::dispatch() const { if (!d || !d->connection) return; d->dispatch(); } void TQT_DBusConnection::scheduleDispatch() const { if (!d || !d->connection) return; d->scheduleDispatch(); } bool TQT_DBusConnection::connect(TQObject* object, const char* slot) { if (!d || !d->connection || !object || !slot) return false; bool ok = object->connect(d, TQT_SIGNAL(dbusSignal(const TQT_DBusMessage&)), slot); return ok; } bool TQT_DBusConnection::disconnect(TQObject* object, const char* slot) { if (!d || !d->connection || !object || !slot) return false; bool ok = d->disconnect(object, slot); return ok; } bool TQT_DBusConnection::registerObject(const TQString& path, TQT_DBusObjectBase* object) { if (!d || !d->connection || !object || path.isEmpty()) return false; TQT_DBusConnectionPrivate::ObjectMap::const_iterator it = d->registeredObjects.find(path); if (it != d->registeredObjects.end()) return false; d->registeredObjects.insert(path, object); return true; } void TQT_DBusConnection::unregisterObject(const TQString &path) { if (!d || !d->connection || path.isEmpty()) return; TQT_DBusConnectionPrivate::ObjectMap::iterator it = d->registeredObjects.find(path); if (it == d->registeredObjects.end()) return ; d->registeredObjects.erase(it); } bool TQT_DBusConnection::isConnected( ) const { return d && d->connection && dbus_connection_get_is_connected(d->connection); } TQT_DBusError TQT_DBusConnection::lastError() const { return d ? d->lastError : TQT_DBusError(); } TQString TQT_DBusConnection::uniqueName() const { return d && d->connection ? TQString::fromUtf8(dbus_bus_get_unique_name(d->connection)) : TQString(); } bool TQT_DBusConnection::requestName(const TQString &name, int modeFlags) { Q_ASSERT(modeFlags >= 0); if (!d || !d->connection) return false; if (modeFlags < 0) return false; int dbusFlags = 0; if (modeFlags & AllowReplace) dbusFlags |= DBUS_NAME_FLAG_ALLOW_REPLACEMENT; if (modeFlags & ReplaceExisting) dbusFlags |= DBUS_NAME_FLAG_REPLACE_EXISTING; dbus_bus_request_name(d->connection, name.utf8(), dbusFlags, &d->error); return !d->handleError(); } #include "tqdbusconnection.moc"