summaryrefslogtreecommitdiffstats
path: root/tqdbusintegrator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tqdbusintegrator.cpp')
-rw-r--r--tqdbusintegrator.cpp626
1 files changed, 626 insertions, 0 deletions
diff --git a/tqdbusintegrator.cpp b/tqdbusintegrator.cpp
new file mode 100644
index 0000000..c61801f
--- /dev/null
+++ b/tqdbusintegrator.cpp
@@ -0,0 +1,626 @@
+/* qdbusintegrator.cpp TQT_DBusConnection private implementation
+ *
+ * Copyright (C) 2005 Harald Fernengel <harry@kdevelop.org>
+ * Copyright (C) 2005 Kevin Krammer <kevin.krammer@gmx.at>
+ *
+ * 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 <tqapplication.h>
+#include <tqevent.h>
+#include <tqmetaobject.h>
+#include <tqsocketnotifier.h>
+#include <tqtimer.h>
+
+#include "tqdbusconnection_p.h"
+#include "tqdbusmessage.h"
+
+Atomic::Atomic(int value) : m_value(value)
+{
+}
+
+void Atomic::ref()
+{
+ m_value++;
+}
+
+bool Atomic::deref()
+{
+ m_value--;
+ return m_value > 0;
+}
+
+int TQT_DBusConnectionPrivate::messageMetaType = 0;
+
+static dbus_bool_t qDBusAddTimeout(DBusTimeout *timeout, void *data)
+{
+ Q_ASSERT(timeout);
+ Q_ASSERT(data);
+
+ // qDebug("addTimeout %d", dbus_timeout_get_interval(timeout));
+
+ TQT_DBusConnectionPrivate *d = static_cast<TQT_DBusConnectionPrivate *>(data);
+
+ if (!dbus_timeout_get_enabled(timeout))
+ return true;
+
+ if (!tqApp) {
+ d->pendingTimeouts.append(timeout);
+ return true;
+ }
+ int timerId = d->startTimer(dbus_timeout_get_interval(timeout));
+ if (!timerId)
+ return false;
+
+ d->timeouts[timerId] = timeout;
+ return true;
+}
+
+static void qDBusRemoveTimeout(DBusTimeout *timeout, void *data)
+{
+ Q_ASSERT(timeout);
+ Q_ASSERT(data);
+
+ // qDebug("removeTimeout");
+
+ TQT_DBusConnectionPrivate *d = static_cast<TQT_DBusConnectionPrivate *>(data);
+ for (TQValueList<DBusTimeout*>::iterator it = d->pendingTimeouts.begin();
+ it != d->pendingTimeouts.end();) {
+ if ((*it) == timeout) {
+ it = d->pendingTimeouts.erase(it);
+ }
+ else
+ ++it;
+ }
+
+ TQT_DBusConnectionPrivate::TimeoutHash::iterator it = d->timeouts.begin();
+ while (it != d->timeouts.end()) {
+ if (it.data() == timeout) {
+ d->killTimer(it.key());
+ TQT_DBusConnectionPrivate::TimeoutHash::iterator copyIt = it;
+ ++it;
+ d->timeouts.erase(copyIt);
+ } else {
+ ++it;
+ }
+ }
+}
+
+static void qDBusToggleTimeout(DBusTimeout *timeout, void *data)
+{
+ Q_ASSERT(timeout);
+ Q_ASSERT(data);
+
+ //qDebug("ToggleTimeout");
+
+ qDBusRemoveTimeout(timeout, data);
+ qDBusAddTimeout(timeout, data);
+}
+
+static dbus_bool_t qDBusAddWatch(DBusWatch *watch, void *data)
+{
+ Q_ASSERT(watch);
+ Q_ASSERT(data);
+
+ TQT_DBusConnectionPrivate *d = static_cast<TQT_DBusConnectionPrivate *>(data);
+
+ int flags = dbus_watch_get_flags(watch);
+ int fd = dbus_watch_get_unix_fd(watch);
+
+ TQT_DBusConnectionPrivate::Watcher watcher;
+ if (flags & DBUS_WATCH_READABLE) {
+ bool enabled = dbus_watch_get_enabled(watch);
+ //qDebug("addReadWatch %d %s", fd, (enabled ? "enabled" : "disabled"));
+ watcher.watch = watch;
+ if (tqApp) {
+ watcher.read = new TQSocketNotifier(fd, TQSocketNotifier::Read, d);
+ if (!enabled) watcher.read->setEnabled(false);
+ d->connect(watcher.read, TQT_SIGNAL(activated(int)), TQT_SLOT(socketRead(int)));
+ }
+ }
+ if (flags & DBUS_WATCH_WRITABLE) {
+ bool enabled = dbus_watch_get_enabled(watch);
+ //qDebug("addWriteWatch %d %s", fd, (enabled ? "enabled" : "disabled"));
+ watcher.watch = watch;
+ if (tqApp) {
+ watcher.write = new TQSocketNotifier(fd, TQSocketNotifier::Write, d);
+ if (!enabled) watcher.write->setEnabled(false);
+ d->connect(watcher.write, TQT_SIGNAL(activated(int)), TQT_SLOT(socketWrite(int)));
+ }
+ }
+ // FIXME-QT4 d->watchers.insertMulti(fd, watcher);
+ TQT_DBusConnectionPrivate::WatcherHash::iterator it = d->watchers.tqfind(fd);
+ if (it == d->watchers.end())
+ {
+ it = d->watchers.insert(fd, TQT_DBusConnectionPrivate::WatcherList());
+ }
+ it.data().append(watcher);
+
+ return true;
+}
+
+static void qDBusRemoveWatch(DBusWatch *watch, void *data)
+{
+ Q_ASSERT(watch);
+ Q_ASSERT(data);
+
+ //qDebug("remove watch");
+
+ TQT_DBusConnectionPrivate *d = static_cast<TQT_DBusConnectionPrivate *>(data);
+ int fd = dbus_watch_get_unix_fd(watch);
+
+ TQT_DBusConnectionPrivate::WatcherHash::iterator it = d->watchers.tqfind(fd);
+ if (it != d->watchers.end())
+ {
+ TQT_DBusConnectionPrivate::WatcherList& list = *it;
+ for (TQT_DBusConnectionPrivate::WatcherList::iterator wit = list.begin();
+ wit != list.end(); ++wit)
+ {
+ if ((*wit).watch == watch)
+ {
+ // migth be called from a function triggered by a socket listener
+ // so just disconnect them and schedule their delayed deletion.
+
+ d->removedWatches.append(*wit);
+ if ((*wit).read)
+ {
+ (*wit).read->disconnect(d);
+ (*wit).read = 0;
+ }
+ if ((*wit).write)
+ {
+ (*wit).write->disconnect(d);
+ (*wit).write = 0;
+ }
+ (*wit).watch = 0;
+ }
+ }
+ }
+
+ if (d->removedWatches.count() > 0)
+ TQTimer::singleShot(0, d, TQT_SLOT(purgeRemovedWatches()));
+}
+
+static void qDBusToggleWatch(DBusWatch *watch, void *data)
+{
+ Q_ASSERT(watch);
+ Q_ASSERT(data);
+
+ //qDebug("toggle watch");
+
+ TQT_DBusConnectionPrivate *d = static_cast<TQT_DBusConnectionPrivate *>(data);
+ int fd = dbus_watch_get_unix_fd(watch);
+
+ TQT_DBusConnectionPrivate::WatcherHash::iterator it = d->watchers.tqfind(fd);
+ if (it != d->watchers.end()) {
+ TQT_DBusConnectionPrivate::WatcherList& list = *it;
+ for (TQT_DBusConnectionPrivate::WatcherList::iterator wit = list.begin(); wit != list.end();
+ ++wit)
+ {
+ if ((*wit).watch == watch) {
+ bool enabled = dbus_watch_get_enabled(watch);
+ int flags = dbus_watch_get_flags(watch);
+
+// qDebug("toggle watch %d to %d (write: %d, read: %d)",
+// dbus_watch_get_unix_fd(watch), enabled,
+// flags & DBUS_WATCH_WRITABLE, flags & DBUS_WATCH_READABLE);
+
+ if (flags & DBUS_WATCH_READABLE && (*wit).read)
+ (*wit).read->setEnabled(enabled);
+ if (flags & DBUS_WATCH_WRITABLE && (*wit).write)
+ (*wit).write->setEnabled(enabled);
+ return;
+ }
+ }
+ }
+}
+
+static void qDBusNewConnection(DBusServer *server, DBusConnection *c, void *data)
+{
+ Q_ASSERT(data); Q_ASSERT(server); Q_ASSERT(c);
+
+ qDebug("SERVER: GOT A NEW CONNECTION"); // TODO
+}
+
+static DBusHandlerResult qDBusSignalFilter(DBusConnection *connection,
+ DBusMessage *message, void *data)
+{
+ Q_ASSERT(data);
+ Q_UNUSED(connection);
+
+ TQT_DBusConnectionPrivate *d = static_cast<TQT_DBusConnectionPrivate *>(data);
+ if (d->mode == TQT_DBusConnectionPrivate::InvalidMode)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ int msgType = dbus_message_get_type(message);
+ bool handled = false;
+
+ //TQT_DBusMessage amsg = TQT_DBusMessage::fromDBusMessage(message);
+ //qDebug() << "got message: " << dbus_message_get_type(message) << amsg;
+
+ if (msgType == DBUS_MESSAGE_TYPE_SIGNAL) {
+ handled = d->handleSignal(message);
+ } else if (msgType == DBUS_MESSAGE_TYPE_METHOD_CALL) {
+ handled = d->handleObjectCall(message);
+ }
+
+ return handled ? DBUS_HANDLER_RESULT_HANDLED :
+ DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+int TQT_DBusConnectionPrivate::registerMessageMetaType()
+{
+ // FIXME-QT4 int tp = messageMetaType = qRegisterMetaType<TQT_DBusMessage>("TQT_DBusMessage");
+ int tp = 0;
+ return tp;
+}
+
+TQT_DBusConnectionPrivate::TQT_DBusConnectionPrivate(TQObject *tqparent)
+ : TQObject(tqparent), ref(1), mode(InvalidMode), connection(0), server(0),
+ dispatcher(0)
+{
+ static const int msgType = registerMessageMetaType();
+ Q_UNUSED(msgType);
+
+ dbus_error_init(&error);
+
+ dispatcher = new TQTimer(this);
+ TQObject::connect(dispatcher, TQT_SIGNAL(timeout()), this, TQT_SLOT(dispatch()));
+}
+
+TQT_DBusConnectionPrivate::~TQT_DBusConnectionPrivate()
+{
+ if (dbus_error_is_set(&error))
+ dbus_error_free(&error);
+
+ closeConnection();
+}
+
+void TQT_DBusConnectionPrivate::closeConnection()
+{
+ ConnectionMode oldMode = mode;
+ mode = InvalidMode; // prevent reentrancy
+ if (oldMode == ServerMode) {
+ if (server) {
+ dbus_server_disconnect(server);
+ dbus_server_unref(server);
+ server = 0;
+ }
+ } else if (oldMode == ClientMode) {
+ if (connection) {
+ // closing shared connections is forbidden
+#if 0
+ dbus_connection_close(connection);
+ // send the "close" message
+ while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS);
+#endif
+ dbus_connection_unref(connection);
+ connection = 0;
+ }
+ }
+}
+
+bool TQT_DBusConnectionPrivate::handleError()
+{
+ lastError = TQT_DBusError(&error);
+ if (dbus_error_is_set(&error))
+ dbus_error_free(&error);
+ return lastError.isValid();
+}
+
+void TQT_DBusConnectionPrivate::emitPendingCallReply(const TQT_DBusMessage& message)
+{
+ emit dbusPendingCallReply(message);
+}
+
+void TQT_DBusConnectionPrivate::bindToApplication()
+{
+ // Yay, now that we have an application we are in business
+ // Re-add all watchers
+ WatcherHash oldWatchers = watchers;
+ watchers.clear();
+ // FIXME-QT4 TQHashIterator<int, TQT_DBusConnectionPrivate::Watcher> it(oldWatchers);
+ for (WatcherHash::const_iterator it = oldWatchers.begin(); it != oldWatchers.end(); ++it)
+ {
+ const WatcherList& list = *it;
+ for (WatcherList::const_iterator wit = list.begin(); wit != list.end(); ++wit)
+ {
+ if (!(*wit).read && !(*wit).write) {
+ qDBusAddWatch((*wit).watch, this);
+ }
+ }
+ }
+
+ // Re-add all timeouts
+ while (!pendingTimeouts.isEmpty()) {
+ qDBusAddTimeout(pendingTimeouts.first(), this);
+ pendingTimeouts.pop_front();
+ }
+}
+
+void TQT_DBusConnectionPrivate::socketRead(int fd)
+{
+ // FIXME-QT4 TQHashIterator<int, TQT_DBusConnectionPrivate::Watcher> it(watchers);
+ WatcherHash::const_iterator it = watchers.tqfind(fd);
+ if (it != watchers.end()) {
+ const WatcherList& list = *it;
+ for (WatcherList::const_iterator wit = list.begin(); wit != list.end(); ++wit) {
+ if ((*wit).read && (*wit).read->isEnabled()) {
+ if (!dbus_watch_handle((*wit).watch, DBUS_WATCH_READABLE))
+ qDebug("OUT OF MEM");
+ }
+ }
+ }
+ if (mode == ClientMode)
+ scheduleDispatch();
+}
+
+void TQT_DBusConnectionPrivate::socketWrite(int fd)
+{
+ // FIXME-QT4 TQHashIterator<int, TQT_DBusConnectionPrivate::Watcher> it(watchers);
+ WatcherHash::const_iterator it = watchers.tqfind(fd);
+ if (it != watchers.end()) {
+ const WatcherList& list = *it;
+ for (WatcherList::const_iterator wit = list.begin(); wit != list.end(); ++wit) {
+ if ((*wit).write && (*wit).write->isEnabled()) {
+ if (!dbus_watch_handle((*wit).watch, DBUS_WATCH_WRITABLE))
+ qDebug("OUT OF MEM");
+ }
+ }
+ }
+}
+
+void TQT_DBusConnectionPrivate::objectDestroyed(TQObject* object)
+{
+ //qDebug("Object destroyed");
+ for (PendingCallMap::iterator it = pendingCalls.begin(); it != pendingCalls.end();)
+ {
+ TQObject* receiver = (TQObject*) it.data()->receiver;
+ if (receiver == object || receiver == 0)
+ {
+ PendingCallMap::iterator copyIt = it;
+ ++it;
+
+ dbus_pending_call_cancel(copyIt.key());
+ dbus_pending_call_unref(copyIt.key());
+ delete copyIt.data();
+ pendingCalls.erase(copyIt);
+ }
+ else
+ ++it;
+ }
+}
+
+void TQT_DBusConnectionPrivate::purgeRemovedWatches()
+{
+ if (removedWatches.isEmpty()) return;
+
+ WatcherList::iterator listIt = removedWatches.begin();
+ for (; listIt != removedWatches.end(); ++listIt)
+ {
+ delete (*listIt).read;
+ delete (*listIt).write;
+ }
+ removedWatches.clear();
+
+ uint count = 0;
+ WatcherHash::iterator it = watchers.begin();
+ while (it != watchers.end())
+ {
+ WatcherList& list = *it;
+ listIt = list.begin();
+ while (listIt != list.end())
+ {
+ if (!((*listIt).read) && !((*listIt).write))
+ {
+ listIt = list.erase(listIt);
+ ++count;
+ }
+ }
+
+ if (list.isEmpty())
+ {
+ WatcherHash::iterator copyIt = it;
+ ++it;
+ watchers.erase(copyIt);
+ }
+ else
+ ++it;
+ }
+}
+
+void TQT_DBusConnectionPrivate::scheduleDispatch()
+{
+ dispatcher->start(0);
+}
+
+void TQT_DBusConnectionPrivate::dispatch()
+{
+ if (mode == ClientMode)
+ {
+ if (dbus_connection_dispatch(connection) != DBUS_DISPATCH_DATA_REMAINS)
+ {
+ // stop dispatch timer
+ dispatcher->stop();
+ }
+ }
+}
+
+bool TQT_DBusConnectionPrivate::handleObjectCall(DBusMessage *message)
+{
+ TQT_DBusMessage msg = TQT_DBusMessage::fromDBusMessage(message);
+
+ ObjectMap::iterator it = registeredObjects.tqfind(msg.path());
+ if (it == registeredObjects.end())
+ return false;
+
+ return it.data()->handleMethodCall(msg);
+}
+
+bool TQT_DBusConnectionPrivate::handleSignal(DBusMessage *message)
+{
+ TQT_DBusMessage msg = TQT_DBusMessage::fromDBusMessage(message);
+
+ // yes, it is a single "|" below...
+ // FIXME-QT4
+ //return handleSignal(TQString(), msg) | handleSignal(msg.path(), msg);
+
+ dbusSignal(msg);
+ return true;
+}
+
+static dbus_int32_t server_slot = -1;
+
+void TQT_DBusConnectionPrivate::setServer(DBusServer *s)
+{
+ if (!server) {
+ handleError();
+ return;
+ }
+
+ server = s;
+ mode = ServerMode;
+
+ dbus_server_allocate_data_slot(&server_slot);
+ if (server_slot < 0)
+ return;
+
+ dbus_server_set_watch_functions(server, qDBusAddWatch, qDBusRemoveWatch,
+ qDBusToggleWatch, this, 0); // ### check return type?
+ dbus_server_set_timeout_functions(server, qDBusAddTimeout, qDBusRemoveTimeout,
+ qDBusToggleTimeout, this, 0);
+ dbus_server_set_new_connection_function(server, qDBusNewConnection, this, 0);
+
+ dbus_server_set_data(server, server_slot, this, 0);
+}
+
+void TQT_DBusConnectionPrivate::setConnection(DBusConnection *dbc)
+{
+ if (!dbc) {
+ handleError();
+ return;
+ }
+
+ connection = dbc;
+ mode = ClientMode;
+
+ dbus_connection_set_exit_on_disconnect(connection, false);
+ dbus_connection_set_watch_functions(connection, qDBusAddWatch, qDBusRemoveWatch,
+ qDBusToggleWatch, this, 0);
+ dbus_connection_set_timeout_functions(connection, qDBusAddTimeout, qDBusRemoveTimeout,
+ qDBusToggleTimeout, this, 0);
+// dbus_bus_add_match(connection, "type='signal',interface='com.trolltech.dbus.Signal'", &error);
+// dbus_bus_add_match(connection, "type='signal'", &error);
+
+ dbus_bus_add_match(connection, "type='signal'", &error);
+ if (handleError()) {
+ closeConnection();
+ return;
+ }
+
+ const char *service = dbus_bus_get_unique_name(connection);
+ if (service) {
+ TQCString filter;
+ filter += "destination='";
+ filter += service;
+ filter += "\'";
+
+ dbus_bus_add_match(connection, filter.data(), &error);
+ if (handleError()) {
+ closeConnection();
+ return;
+ }
+ } else {
+ qWarning("TQT_DBusConnectionPrivate::SetConnection: Unable to get unique name");
+ }
+
+ dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0);
+
+ //qDebug("unique name: %s", service);
+}
+
+static void qDBusResultReceived(DBusPendingCall *pending, void *user_data)
+{
+ //qDebug("Pending Call Result received");
+ TQT_DBusConnectionPrivate* d = reinterpret_cast<TQT_DBusConnectionPrivate*>(user_data);
+ TQT_DBusConnectionPrivate::PendingCallMap::iterator it = d->pendingCalls.tqfind(pending);
+
+ DBusMessage *dbusReply = dbus_pending_call_steal_reply(pending);
+
+ dbus_set_error_from_message(&d->error, dbusReply);
+ d->handleError();
+
+ if (it != d->pendingCalls.end())
+ {
+ TQT_DBusMessage reply = TQT_DBusMessage::fromDBusMessage(dbusReply);
+
+ TQObject::connect(d, TQT_SIGNAL(dbusPendingCallReply(const TQT_DBusMessage&)),
+ it.data()->receiver, it.data()->method.data());
+
+ d->emitPendingCallReply(reply);
+
+ TQObject::disconnect(d, TQT_SIGNAL(dbusPendingCallReply(const TQT_DBusMessage&)),
+ it.data()->receiver, it.data()->method.data());
+ }
+
+ dbus_message_unref(dbusReply);
+ dbus_pending_call_unref(pending);
+ delete it.data();
+
+ d->pendingCalls.erase(it);
+}
+
+int TQT_DBusConnectionPrivate::sendWithReplyAsync(const TQT_DBusMessage &message, TQObject *receiver,
+ const char *method)
+{
+ if (!receiver || !method)
+ return 0;
+
+ if (!TQObject::connect(receiver, TQT_SIGNAL(destroyed(TQObject*)),
+ this, TQT_SLOT(objectDestroyed(TQObject*))))
+ return false;
+
+ DBusMessage *msg = message.toDBusMessage();
+ if (!msg)
+ return 0;
+
+ DBusPendingCall *pending = 0;
+ if (dbus_connection_send_with_reply(connection, msg, &pending, message.timeout())) {
+ TQT_DBusPendingCall *pcall = new TQT_DBusPendingCall;
+ pcall->receiver = receiver;
+ pcall->method = method;
+ pcall->pending = dbus_pending_call_ref(pending);
+ pendingCalls.insert(pcall->pending, pcall);
+
+ dbus_pending_call_set_notify(pending, qDBusResultReceived, this, 0);
+
+ return dbus_message_get_serial(msg);
+ }
+
+ return 0;
+}
+
+void TQT_DBusConnectionPrivate::flush()
+{
+ if (!connection) return;
+
+ dbus_connection_flush(connection);
+}
+
+#include "tqdbusconnection_p.moc"