dbus/qt Makefile.am, 1.9, 1.10 connection.cpp, 1.10,
NONE connection.h, 1.10, NONE dbus-qt.h, 1.4,
NONE dbus-qthread.cpp, 1.4, NONE integrator.cpp, 1.5,
NONE integrator.h, 1.5, NONE message.cpp, 1.12, NONE message.h,
1.8, NONE qdbus.h, NONE, 1.1 qdbusconnection.cpp, NONE,
1.1 qdbusconnection.h, NONE, 1.1 qdbusconnection_p.h, NONE,
1.1 qdbuserror.cpp, NONE, 1.1 qdbuserror.h, NONE,
1.1 qdbusintegrator.cpp, NONE, 1.1 qdbusmacros.h, NONE,
1.1 qdbusmarshall.cpp, NONE, 1.1 qdbusmarshall.h, NONE,
1.1 qdbusmessage.cpp, NONE, 1.1 qdbusmessage.h, NONE,
1.1 qdbusmessage_p.h, NONE, 1.1 qdbusserver.cpp, NONE,
1.1 qdbusserver.h, NONE, 1.1 qdbusvariant.h, NONE,
1.1 server.cpp, 1.3, NONE server.h, 1.3, NONE
Harald Fernengel
harry at freedesktop.org
Fri Sep 23 06:08:28 PDT 2005
Update of /cvs/dbus/dbus/qt
In directory gabe:/tmp/cvs-serv20433/qt
Modified Files:
Makefile.am
Added Files:
qdbus.h qdbusconnection.cpp qdbusconnection.h
qdbusconnection_p.h qdbuserror.cpp qdbuserror.h
qdbusintegrator.cpp qdbusmacros.h qdbusmarshall.cpp
qdbusmarshall.h qdbusmessage.cpp qdbusmessage.h
qdbusmessage_p.h qdbusserver.cpp qdbusserver.h qdbusvariant.h
Removed Files:
connection.cpp connection.h dbus-qt.h dbus-qthread.cpp
integrator.cpp integrator.h message.cpp message.h server.cpp
server.h
Log Message:
With the permission of the original authors, removing the non-working and hopelessly unmaintained old Qt D-BUS bindings and adding the ones from KDE's SVN.
Index: Makefile.am
===================================================================
RCS file: /cvs/dbus/dbus/qt/Makefile.am,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- Makefile.am 6 Sep 2005 22:38:54 -0000 1.9
+++ Makefile.am 23 Sep 2005 13:08:26 -0000 1.10
@@ -1,37 +1,50 @@
if HAVE_QT
-INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_QT_CXXFLAGS)
+INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_QT_CFLAGS)
dbusincludedir=$(includedir)/dbus-1.0/dbus
lib_LTLIBRARIES=libdbus-qt-1.la
-dbusinclude_HEADERS= \
- dbus-qt.h message.h connection.h \
- server.h
+dbusinclude_HEADERS= \
+ qdbuserror.h \
+ qdbusmacros.h \
+ qdbusmessage.h \
+ qdbusserver.h \
+ qdbus.h \
+ qdbusmarshall.h \
+ qdbusvariant.h
libdbus_qt_1_la_SOURCES = \
- dbus-qthread.cpp \
- $(top_srcdir)/qt/message.cpp \
- $(top_srcdir)/qt/connection.cpp \
- $(top_srcdir)/qt/integrator.cpp \
- $(top_srcdir)/qt/server.cpp \
- $(top_srcdir)/qt/connection.h \
- $(top_srcdir)/qt/integrator.h \
- $(top_srcdir)/qt/server.h
+ $(top_srcdir)/qt/qdbusconnection.cpp \
+ $(top_srcdir)/qt/qdbuserror.cpp \
+ $(top_srcdir)/qt/qdbusintegrator.cpp \
+ $(top_srcdir)/qt/qdbusmarshall.cpp \
+ $(top_srcdir)/qt/qdbusmessage.cpp \
+ $(top_srcdir)/qt/qdbusserver.cpp \
+ $(top_srcdir)/qt/qdbusconnection.h \
+ $(top_srcdir)/qt/qdbuserror.h \
+ $(top_srcdir)/qt/qdbusmacros.h \
+ $(top_srcdir)/qt/qdbusmessage.h \
+ $(top_srcdir)/qt/qdbusserver.h \
+ $(top_srcdir)/qt/qdbusconnection_p.h \
+ $(top_srcdir)/qt/qdbus.h \
+ $(top_srcdir)/qt/qdbusmarshall.h \
+ $(top_srcdir)/qt/qdbusmessage_p.h \
+ $(top_srcdir)/qt/qdbusvariant.h
-$(top_srcdir)/qt/connection.cpp: connection.moc
-$(top_srcdir)/qt/integrator.cpp: integrator.moc
-$(top_srcdir)/qt/server.cpp: server.moc
-$(top_srcdir)/qt/connection.h: connection.moc
-$(top_srcdir)/qt/integrator.h: integrator.moc
-$(top_srcdir)/qt/server.h: server.moc
+$(top_srcdir)/qt/qdbusserver.cpp: qdbusserver.moc
+$(top_srcdir)/qt/qdbusconnection.cpp: qdbusconnection.moc
-CLEANFILES=connection.moc integrator.moc server.moc
+CLEANFILES=qdbusserver.moc qdbusconnection.moc
libdbus_qt_1_la_LIBADD= $(DBUS_QT_LIBS) $(top_builddir)/dbus/libdbus-1.la
libdbus_qt_1_la_LDFLAGS= -version-info 1:0 -no-undefined
+# _p.h files are a exception
+qdbusconnection.moc: qdbusconnection_p.h
+ $(QT_MOC) -o qdbusconnection.moc $(top_srcdir)/qt/qdbusconnection_p.h
+
%.moc: %.h
$(QT_MOC) $< > $@
endif
--- connection.cpp DELETED ---
--- connection.h DELETED ---
--- dbus-qt.h DELETED ---
--- dbus-qthread.cpp DELETED ---
--- integrator.cpp DELETED ---
--- integrator.h DELETED ---
--- message.cpp DELETED ---
--- message.h DELETED ---
--- NEW FILE: qdbus.h ---
/* qdbus.h precompiled header
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef QDBUS_H
#define QDBUS_H
#include <QtDBUS/qdbusconnection.h>
#include <QtDBUS/qdbuserror.h>
#include <QtDBUS/qdbusmessage.h>
#include <QtDBUS/qdbusserver.h>
#endif
--- NEW FILE: qdbusconnection.cpp ---
/* qdbusconnection.cpp
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <QtCore/qdebug.h>
#include <QtCore/qcoreapplication.h>
#include "qdbusconnection.h"
#include "qdbuserror.h"
#include "qdbusmessage.h"
#include "qdbusconnection_p.h"
QT_STATIC_CONST_IMPL char *QDBusConnection::default_connection_name = "qt_dbus_default_connection";
class QDBusConnectionManager
{
public:
QDBusConnectionManager(): default_connection(0) {}
~QDBusConnectionManager();
void bindToApplication();
QDBusConnectionPrivate *connection(const QString &name) const;
void removeConnection(const QString &name);
void setConnection(const QString &name, QDBusConnectionPrivate *c);
private:
QDBusConnectionPrivate *default_connection;
QHash<QString, QDBusConnectionPrivate *> connectionHash;
};
Q_GLOBAL_STATIC(QDBusConnectionManager, manager);
QDBusConnectionPrivate *QDBusConnectionManager::connection(const QString &name) const
{
return name == QLatin1String(QDBusConnection::default_connection_name) ?
default_connection : connectionHash.value(name, 0);
}
void QDBusConnectionManager::removeConnection(const QString &name)
{
QDBusConnectionPrivate *d = 0;
if (name == QLatin1String(QDBusConnection::default_connection_name)) {
d = default_connection;
default_connection = 0;
} else {
d = connectionHash.take(name);
}
if (!d->ref.deref())
delete d;
}
QDBusConnectionManager::~QDBusConnectionManager()
{
if (default_connection) {
delete default_connection;
default_connection = 0;
}
for (QHash<QString, QDBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin();
it != connectionHash.constEnd(); ++it) {
delete it.value();
}
connectionHash.clear();
}
void QDBusConnectionManager::bindToApplication()
{
if (default_connection) {
default_connection->bindToApplication();
}
for (QHash<QString, QDBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin();
it != connectionHash.constEnd(); ++it) {
(*it)->bindToApplication();
}
}
void qDBusBindToApplication()
{
manager()->bindToApplication();
}
void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionPrivate *c)
{
if (name == QLatin1String(QDBusConnection::default_connection_name))
default_connection = c;
else
connectionHash[name] = c;
}
QDBusConnection::QDBusConnection(const QString &name)
{
d = manager()->connection(name);
if (d)
d->ref.ref();
}
QDBusConnection::QDBusConnection(const QDBusConnection &other)
{
d = other.d;
if (d)
d->ref.ref();
}
QDBusConnection::~QDBusConnection()
{
if (d && !d->ref.deref())
delete d;
}
QDBusConnection &QDBusConnection::operator=(const QDBusConnection &other)
{
if (other.d)
other.d->ref.ref();
QDBusConnectionPrivate *old = static_cast<QDBusConnectionPrivate *>(
q_atomic_set_ptr(&d, other.d));
if (old && !old->ref.deref())
delete old;
return *this;
}
QDBusConnection QDBusConnection::addConnection(BusType type, const QString &name)
{
// Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection",
// "Cannot create connection without a Q[Core]Application instance");
QDBusConnectionPrivate *d = manager()->connection(name);
if (d)
return QDBusConnection(name);
d = new QDBusConnectionPrivate;
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 QDBusConnection(name);
}
QDBusConnection QDBusConnection::addConnection(const QString &address,
const QString &name)
{
// Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection",
// "Cannot create connection without a Q[Core]Application instance");
QDBusConnectionPrivate *d = manager()->connection(name);
if (d)
return QDBusConnection(name);
d = new QDBusConnectionPrivate;
// setConnection does the error handling for us
d->setConnection(dbus_connection_open(address.toUtf8().constData(), &d->error));
manager()->setConnection(name, d);
return QDBusConnection(name);
}
void QDBusConnection::closeConnection(const QString &name)
{
manager()->removeConnection(name);
}
void QDBusConnectionPrivate::timerEvent(QTimerEvent *e)
{
DBusTimeout *timeout = timeouts.value(e->timerId(), 0);
dbus_timeout_handle(timeout);
}
bool QDBusConnection::send(const QDBusMessage &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 QDBusConnection::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
const char *method) const
{
if (!d || !d->connection)
return 0;
return d->sendWithReplyAsync(message, receiver, method);
}
QDBusMessage QDBusConnection::sendWithReply(const QDBusMessage &message) const
{
if (!d || !d->connection)
return QDBusMessage::fromDBusMessage(0);
DBusMessage *msg = message.toDBusMessage();
if (!msg)
return QDBusMessage::fromDBusMessage(0);
DBusMessage *reply = dbus_connection_send_with_reply_and_block(d->connection, msg,
-1, &d->error);
d->handleError();
dbus_message_unref(msg);
return QDBusMessage::fromDBusMessage(reply);
}
bool QDBusConnection::connect(const QString &path, const QString &interface,
const QString &name, QObject *receiver, const char *slot)
{
if (!receiver || !slot || !d || !d->connection)
return false;
QDBusConnectionPrivate::SignalHook hook;
hook.interface = interface;
hook.name = name;
hook.obj = QPointer<QObject>(receiver);
if (!hook.setSlot(slot + 1))
return false;
d->signalHooks.insertMulti(path, hook);
d->connect(receiver, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)));
return true;
}
bool QDBusConnection::registerObject(const QString &path, const QString &interface,
QObject *object)
{
if (!d || !d->connection || !object || path.isEmpty() || interface.isEmpty())
return false;
QDBusConnectionPrivate::ObjectHook hook;
hook.interface = interface;
hook.obj = object;
QDBusConnectionPrivate::ObjectHookHash::iterator it = d->objectHooks.find(path);
while (it != d->objectHooks.end() && it.key() == path) {
if (it.value().interface == interface) {
d->objectHooks.erase(it);
break;
}
++it;
}
d->objectHooks.insert(path, hook);
d->connect(object, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)));
qDebug("REGISTERED FOR %s", path.toLocal8Bit().constData());
return true; // todo - check for slots etc.
}
void QDBusConnection::unregisterObject(const QString &path)
{
if (!d || !d->connection)
return;
// TODO - check interfaces
d->objectHooks.remove(path);
}
bool QDBusConnection::isConnected( ) const
{
return d && d->connection && dbus_connection_get_is_connected(d->connection);
}
QDBusError QDBusConnection::lastError() const
{
return d ? d->lastError : QDBusError();
}
QString QDBusConnection::baseService() const
{
return d && d->connection ?
QString::fromUtf8(dbus_bus_get_unique_name(d->connection))
: QString();
}
bool QDBusConnection::requestName(const QString &name, NameRequestMode mode)
{
static const int DBusModes[] = { 0, DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT,
DBUS_NAME_FLAG_REPLACE_EXISTING };
Q_ASSERT(mode == 0 || mode == DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT ||
mode == DBUS_NAME_FLAG_REPLACE_EXISTING);
DBusError error;
dbus_error_init (&error);
dbus_bus_request_name(d->connection, name.toUtf8(), DBusModes[mode], &error);
if (dbus_error_is_set (&error)) {
qDebug("Error %s\n", error.message);
dbus_error_free (&error);
return false;
}
return true;
}
#include "qdbusconnection.moc"
--- NEW FILE: qdbusconnection.h ---
/* qdbusconnection.h QDBusConnection object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef QDBUSCONNECTION_H
#define QDBUSCONNECTION_H
#include "qdbusmacros.h"
#include <QtCore/qstring.h>
class QDBusConnectionPrivate;
class QDBusError;
class QDBusMessage;
class QByteArray;
class QObject;
class QDBUS_EXPORT QDBusConnection
{
public:
enum BusType { SessionBus, SystemBus, ActivationBus };
QDBusConnection(const QString &name = QLatin1String(default_connection_name));
QDBusConnection(const QDBusConnection &other);
~QDBusConnection();
QDBusConnection &operator=(const QDBusConnection &other);
bool isConnected() const;
QDBusError lastError() const;
enum NameRequestMode { NoReplace = 0, ProhibitReplace = 1, ReplaceExisting = 2 };
bool requestName(const QString &name, NameRequestMode mode = NoReplace);
QString baseService() const;
bool send(const QDBusMessage &message) const;
QDBusMessage sendWithReply(const QDBusMessage &message) const;
int sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
const char *slot) const;
bool connect(const QString &path, const QString &interface,
const QString &name, QObject *receiver, const char *slot);
bool registerObject(const QString &path, const QString &interface,
QObject *object);
void unregisterObject(const QString &path);
static QDBusConnection addConnection(BusType type,
const QString &name = QLatin1String(default_connection_name));
static QDBusConnection addConnection(const QString &address,
const QString &name = QLatin1String(default_connection_name));
static void closeConnection(const QString &name = QLatin1String(default_connection_name));
QT_STATIC_CONST char *default_connection_name;
private:
QDBusConnectionPrivate *d;
};
#endif
--- NEW FILE: qdbusconnection_p.h ---
/* qdbusconnection_p.h QDBusConnection private object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
//
// W A R N I N G
// -------------
//
// This file is not part of the public API. This header file may
// change from version to version without notice, or even be
// removed.
//
// We mean it.
//
//
#include <QtCore/qatomic.h>
#include <QtCore/qhash.h>
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
#include <QtCore/qvarlengtharray.h>
#include <dbus/dbus.h>
#include "qdbuserror.h"
class QDBusMessage;
class QSocketNotifier;
class QTimerEvent;
typedef struct DBusConnection;
typedef struct DBusServer;
class QDBusConnectionPrivate: public QObject
{
Q_OBJECT
public:
QDBusConnectionPrivate(QObject *parent = 0);
~QDBusConnectionPrivate();
void bindToApplication();
void setConnection(DBusConnection *connection);
void setServer(DBusServer *server);
void closeConnection();
void timerEvent(QTimerEvent *e);
bool handleSignal(DBusMessage *msg) const;
bool handleObjectCall(DBusMessage *message) const;
bool handleError();
public slots:
void socketRead(int);
void socketWrite(int);
void objectDestroyed(QObject *o);
public:
DBusError error;
QDBusError lastError;
enum ConnectionMode { InvalidMode, ServerMode, ClientMode };
QAtomic ref;
ConnectionMode mode;
DBusConnection *connection;
DBusServer *server;
static int messageMetaType;
static int registerMessageMetaType();
bool handleSignal(const QString &path, const QDBusMessage &msg) const;
int sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
const char *method) const;
struct Watcher
{
Watcher(): watch(0), read(0), write(0) {}
DBusWatch *watch;
QSocketNotifier *read;
QSocketNotifier *write;
};
typedef QMultiHash<int, Watcher> WatcherHash;
WatcherHash watchers;
typedef QHash<int, DBusTimeout *> TimeoutHash;
TimeoutHash timeouts;
struct SignalHook
{
QString interface, name;
QPointer<QObject> obj;
int midx;
QVarLengthArray<int, 10> params;
bool setSlot(const char *slotName);
};
typedef QMultiHash<QString, SignalHook> SignalHookHash;
SignalHookHash signalHooks;
struct ObjectHook
{
QString interface;
QPointer<QObject> obj;
};
typedef QMultiHash<QString, ObjectHook> ObjectHookHash;
ObjectHookHash objectHooks;
QList<DBusTimeout *> pendingTimeouts;
};
--- NEW FILE: qdbuserror.cpp ---
/* qdbuserror.h QDBusError object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "qdbuserror.h"
#include <QtCore/qdebug.h>
#include <dbus/dbus.h>
QDBusError::QDBusError(const DBusError *error)
{
if (!error || !dbus_error_is_set(error))
return;
nm = QString::fromUtf8(error->name);
msg = QString::fromUtf8(error->message);
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const QDBusError &msg)
{
dbg.nospace() << "QDBusError(" << msg.name() << ", " << msg.message() << ")";
return dbg.space();
}
#endif
--- NEW FILE: qdbuserror.h ---
/* qdbuserror.h QDBusError object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef QDBUSERROR_H
#define QDBUSERROR_H
#include "qdbusmacros.h"
#include <QtCore/qstring.h>
struct DBusError;
class QDBUS_EXPORT QDBusError
{
public:
QDBusError(const DBusError *error = 0);
inline QString name() const { return nm; }
inline QString message() const { return msg; }
inline bool isValid() const { return !nm.isNull() && !msg.isNull(); }
private:
QString nm, msg;
};
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug, const QDBusError &);
#endif
#endif
--- NEW FILE: qdbusintegrator.cpp ---
/* qdbusintegrator.cpp QDBusConnection private implementation
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <QtCore/qcoreapplication.h>
#include <QtCore/qcoreevent.h>
#include <QtCore/qdebug.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qsocketnotifier.h>
#include "qdbusconnection_p.h"
#include "qdbusmessage.h"
int QDBusConnectionPrivate::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));
QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
if (!dbus_timeout_get_enabled(timeout))
return true;
if (!QCoreApplication::instance()) {
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");
QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
d->pendingTimeouts.removeAll(timeout);
QDBusConnectionPrivate::TimeoutHash::iterator it = d->timeouts.begin();
while (it != d->timeouts.end()) {
if (it.value() == timeout) {
d->killTimer(it.key());
it = d->timeouts.erase(it);
} 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);
QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
int flags = dbus_watch_get_flags(watch);
int fd = dbus_watch_get_fd(watch);
QDBusConnectionPrivate::Watcher watcher;
if (flags & DBUS_WATCH_READABLE) {
qDebug("addReadWatch %d", fd);
watcher.watch = watch;
if (QCoreApplication::instance()) {
watcher.read = new QSocketNotifier(fd, QSocketNotifier::Read, d);
d->connect(watcher.read, SIGNAL(activated(int)), SLOT(socketRead(int)));
}
}
if (flags & DBUS_WATCH_WRITABLE) {
qDebug("addWriteWatch %d", fd);
watcher.watch = watch;
if (QCoreApplication::instance()) {
watcher.write = new QSocketNotifier(fd, QSocketNotifier::Write, d);
d->connect(watcher.write, SIGNAL(activated(int)), SLOT(socketWrite(int)));
}
}
d->watchers.insertMulti(fd, watcher);
return true;
}
static void qDBusRemoveWatch(DBusWatch *watch, void *data)
{
Q_ASSERT(watch);
Q_ASSERT(data);
qDebug("remove watch");
QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
int fd = dbus_watch_get_fd(watch);
QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd);
while (i != d->watchers.end() && i.key() == fd) {
if (i.value().watch == watch) {
delete i.value().read;
delete i.value().write;
d->watchers.erase(i);
return;
}
++i;
}
}
static void qDBusToggleWatch(DBusWatch *watch, void *data)
{
Q_ASSERT(watch);
Q_ASSERT(data);
QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
int fd = dbus_watch_get_fd(watch);
QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd);
while (i != d->watchers.end() && i.key() == fd) {
if (i.value().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_fd(watch), enabled, flags & DBUS_WATCH_WRITABLE, flags & DBUS_WATCH_READABLE);
if (flags & DBUS_WATCH_READABLE && i.value().read)
i.value().read->setEnabled(enabled);
if (flags & DBUS_WATCH_WRITABLE && i.value().write)
i.value().write->setEnabled(enabled);
return;
}
++i;
}
}
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);
QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
if (d->mode == QDBusConnectionPrivate::InvalidMode)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
int msgType = dbus_message_get_type(message);
bool handled = false;
QDBusMessage amsg = QDBusMessage::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;
}
static bool qInvokeDBusSlot(const QDBusConnectionPrivate::SignalHook& hook, const QDBusMessage &msg)
{
int count = msg.count();
if (!(count == hook.params.count()
|| (count + 1 == hook.params.count()
&& hook.params[count] == QDBusConnectionPrivate::messageMetaType)))
return false;
QVarLengthArray<void *, 16> params;
params.append(0); // return value
for (int i = 0; i < msg.count(); ++i) {
const QVariant &v = msg.at(i);
if (int(v.type()) != hook.params[i]) {
return false;
}
params.append(const_cast<void *>(v.constData()));
}
if (count + 1 == hook.params.count())
params.append(const_cast<QDBusMessage *>(&msg));
return hook.obj->qt_metacall(QMetaObject::InvokeMetaMethod, hook.midx, params.data()) < 0;
}
static bool qInvokeDBusSlot(QObject *object, int idx, const QDBusMessage &msg)
{
Q_ASSERT(object);
const QMetaMethod method = object->metaObject()->method(idx);
if (!method.signature())
return false;
QVarLengthArray<void *> params;
params.append(0); // ### return type
QList<QByteArray> parameterTypes = method.parameterTypes();
// check parameters, the slot should have <= parameters than the message
// also allow the QDBusMessage itself as last parameter slot
if ((parameterTypes.count() > msg.count())
|| (parameterTypes.count() + 1 != msg.count())
&& parameterTypes.last() != "QDBusMessage") {
qWarning("Cannot deliver asynchronous reply to object named '%s' because of parameter "
"mismatch. Please check your sendWithReplyAsync() statements.",
object->objectName().toLocal8Bit().constData());
return false;
}
int i;
for (i = 0; i < parameterTypes.count(); ++i) {
const QByteArray param = parameterTypes.at(i);
if (param == msg.at(i).typeName()) {
params.append(const_cast<void *>(msg.at(i).constData()));
} else if (i == parameterTypes.count() - 1 && param == "QDBusMessage") {
params.append(const_cast<void *>(static_cast<const void *>(&msg)));
} else {
qWarning("Parameter mismatch while delivering message, expected '%s', got '%s'",
msg.at(i).typeName(), param.constData());
return false;
}
}
return object->qt_metacall(QMetaObject::InvokeMetaMethod, idx, params.data()) < 0;
}
static bool qInvokeDBusSlot(QObject *object, QDBusMessage *msg)
{
Q_ASSERT(object);
Q_ASSERT(msg);
const QMetaObject *mo = object->metaObject();
QVarLengthArray<void *> params;
params.append(0); // ### return type
/* Try to find a slot with all args and the QDBusMessage */
QByteArray slotName = msg->name().toUtf8(); // QVarLengthArray?
slotName.append("(");
for (int i = 0; i < msg->count(); ++i) {
slotName.append(msg->at(i).typeName()).append(",");
params.append(const_cast<void *>(msg->at(i).constData()));
}
slotName.append("QDBusMessage)");
int idx = mo->indexOfSlot(slotName.constData());
if (idx >= 0) {
params.append(msg);
return object->qt_metacall(QMetaObject::InvokeMetaMethod, idx, params.data()) < 0;
}
/* Try to find only args, without the QDBusMessage */
slotName.chop(13);
slotName[slotName.count() - 1] = ')';
idx = mo->indexOfSlot(slotName.constData());
if (idx >= 0 && (mo->method(idx).attributes() & QMetaMethod::Scriptable))
return object->qt_metacall(QMetaObject::InvokeMetaMethod, idx, params.data()) < 0;
/* Try to find a slot with only QDBusMessage */
slotName = msg->name().toUtf8();
slotName.append("(QDBusMessage)");
idx = mo->indexOfSlot(slotName.constData());
if (idx >= 0)
return QMetaObject::invokeMethod(object, msg->name().toUtf8().constData(),
Q_ARG(QDBusMessage, *msg));
return false;
}
int QDBusConnectionPrivate::registerMessageMetaType()
{
int tp = messageMetaType = qRegisterMetaType<QDBusMessage>("QDBusMessage");
return tp;
}
bool QDBusConnectionPrivate::SignalHook::setSlot(const char *slotName)
{
Q_ASSERT(static_cast<QObject *>(obj)); Q_ASSERT(slotName);
QByteArray normalizedName = QMetaObject::normalizedSignature(slotName);
const QMetaObject *mo = obj->metaObject();
midx = mo->indexOfMethod(normalizedName.constData());
if (midx < 0)
return false;
const QList<QByteArray> ptypes = mo->method(midx).parameterTypes();
for (int i = 0; i < ptypes.count(); ++i) {
int t = QVariant::nameToType(ptypes.at(i).constData());
if (t == QVariant::UserType)
t = QMetaType::type(ptypes.at(i).constData());
if (t == QVariant::Invalid)
return false;
params.append(t);
}
return true;
}
QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *parent)
: QObject(parent), ref(1), mode(InvalidMode), connection(0), server(0)
{
static const int msgType = registerMessageMetaType();
Q_UNUSED(msgType);
dbus_error_init(&error);
}
QDBusConnectionPrivate::~QDBusConnectionPrivate()
{
if (dbus_error_is_set(&error))
dbus_error_free(&error);
closeConnection();
}
void QDBusConnectionPrivate::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) {
dbus_connection_close(connection);
// send the "close" message
while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS)
;
dbus_connection_unref(connection);
connection = 0;
}
}
}
bool QDBusConnectionPrivate::handleError()
{
lastError = QDBusError(&error);
if (dbus_error_is_set(&error))
dbus_error_free(&error);
return lastError.isValid();
}
void QDBusConnectionPrivate::bindToApplication()
{
// Yay, now that we have an application we are in business
// Re-add all watchers
WatcherHash oldWatchers = watchers;
watchers.clear();
QHashIterator<int, QDBusConnectionPrivate::Watcher> it(oldWatchers);
while (it.hasNext()) {
it.next();
if (!it.value().read && !it.value().write) {
qDBusAddWatch(it.value().watch, this);
}
}
// Re-add all timeouts
while (!pendingTimeouts.isEmpty())
qDBusAddTimeout(pendingTimeouts.takeFirst(), this);
}
void QDBusConnectionPrivate::socketRead(int fd)
{
QHashIterator<int, QDBusConnectionPrivate::Watcher> it(watchers);
while (it.hasNext()) {
it.next();
if (it.key() == fd && it.value().read && it.value().read->isEnabled()) {
if (!dbus_watch_handle(it.value().watch, DBUS_WATCH_READABLE))
qDebug("OUT OF MEM");
}
}
if (mode == ClientMode)
while (dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS);
// ### break out of loop?
}
void QDBusConnectionPrivate::socketWrite(int fd)
{
QHashIterator<int, QDBusConnectionPrivate::Watcher> it(watchers);
while (it.hasNext()) {
it.next();
if (it.key() == fd && it.value().write && it.value().write->isEnabled()) {
if (!dbus_watch_handle(it.value().watch, DBUS_WATCH_WRITABLE))
qDebug("OUT OF MEM");
}
}
}
void QDBusConnectionPrivate::objectDestroyed(QObject *obj)
{
ObjectHookHash::iterator it = objectHooks.begin();
while (it != objectHooks.end()) {
if (static_cast<QObject *>(it.value().obj) == obj)
it = objectHooks.erase(it);
else
++it;
}
SignalHookHash::iterator sit = signalHooks.begin();
while (sit != signalHooks.end()) {
if (static_cast<QObject *>(sit.value().obj) == obj)
sit = signalHooks.erase(sit);
else
++sit;
}
obj->disconnect(this);
}
bool QDBusConnectionPrivate::handleObjectCall(DBusMessage *message) const
{
QDBusMessage msg = QDBusMessage::fromDBusMessage(message);
ObjectHook hook;
ObjectHookHash::ConstIterator it = objectHooks.find(msg.path());
while (it != objectHooks.constEnd() && it.key() == msg.path()) {
if (it.value().interface == msg.interface()) {
hook = it.value();
break;
} else if (it.value().interface.isEmpty()) {
hook = it.value();
}
++it;
}
if (!hook.obj) {
qDebug("NO OBJECT for %s", msg.path().toLocal8Bit().constData());
return false;
}
if (!qInvokeDBusSlot(hook.obj, &msg)) {
qDebug("NO SUCH SLOT: %s(QDBusMessage)", msg.name().toLocal8Bit().constData());
return false;
}
return true;
}
bool QDBusConnectionPrivate::handleSignal(const QString &path, const QDBusMessage &msg) const
{
SignalHookHash::const_iterator it = signalHooks.find(path);
qDebug("looking for: %s", path.toLocal8Bit().constData());
qDebug() << signalHooks.keys();
while (it != signalHooks.constEnd() && it.key() == path) {
const SignalHook &hook = it.value();
if ((hook.name.isEmpty() || hook.name == msg.name())
&& (hook.interface.isEmpty() || hook.interface == msg.interface()))
qInvokeDBusSlot(hook, msg);
++it;
}
return true;
}
bool QDBusConnectionPrivate::handleSignal(DBusMessage *message) const
{
QDBusMessage msg = QDBusMessage::fromDBusMessage(message);
// yes, it is a single "|" below...
return handleSignal(QString(), msg) | handleSignal(msg.path(), msg);
}
static dbus_int32_t server_slot = -1;
void QDBusConnectionPrivate::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 QDBusConnectionPrivate::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) {
QVarLengthArray<char, 56> filter;
filter.append("destination='", 13);
filter.append(service, qstrlen(service));
filter.append("\'\0", 2);
dbus_bus_add_match(connection, filter.constData(), &error);
if (handleError()) {
closeConnection();
return;
}
} else {
qWarning("QDBusConnectionPrivate::SetConnection: Unable to get base service");
}
dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0);
qDebug("base service: %s", service);
}
struct QDBusPendingCall
{
QPointer<QObject> receiver;
int methodIdx;
DBusPendingCall *pending;
};
static void qDBusResultReceived(DBusPendingCall *pending, void *user_data)
{
QDBusPendingCall *call = reinterpret_cast<QDBusPendingCall *>(user_data);
Q_ASSERT(call->pending == pending);
if (!call->receiver.isNull() && call->methodIdx != -1) {
DBusMessage *reply = dbus_pending_call_steal_reply(pending);
qInvokeDBusSlot(call->receiver, call->methodIdx, QDBusMessage::fromDBusMessage(reply));
}
dbus_pending_call_unref(pending);
delete call;
}
int QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
const char *method) const
{
DBusMessage *msg = message.toDBusMessage();
if (!msg)
return 0;
int slotIdx = -1;
if (receiver && method && *method) {
QByteArray normalized = QMetaObject::normalizedSignature(method + 1);
slotIdx = receiver->metaObject()->indexOfMethod(normalized.constData());
if (slotIdx == -1)
qWarning("QDBusConnection::sendWithReplyAsync: no such method: '%s'",
normalized.constData());
}
DBusPendingCall *pending = 0;
if (dbus_connection_send_with_reply(connection, msg, &pending, message.timeout())) {
if (slotIdx != -1) {
QDBusPendingCall *pcall = new QDBusPendingCall;
pcall->receiver = receiver;
pcall->methodIdx = slotIdx;
pcall->pending = dbus_pending_call_ref(pending);
dbus_pending_call_set_notify(pending, qDBusResultReceived, pcall, 0);
}
return dbus_message_get_serial(msg);
}
return 0;
}
--- NEW FILE: qdbusmacros.h ---
/* qdbusmessage.h QDBusMessage object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef QDBUSMACROS_H
#define QDBUSMACROS_H
#include <QtCore/qglobal.h>
#ifdef QDBUS_MAKEDLL
# define QDBUS_EXPORT Q_DECL_EXPORT
#else
# define QDBUS_EXPORT Q_DECL_IMPORT
#endif
#endif
--- NEW FILE: qdbusmarshall.cpp ---
/* qdbusmarshall.cpp
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "qdbusmarshall.h"
#include "qdbusvariant.h"
#include <QtCore/qdebug.h>
#include <QtCore/qvariant.h>
#include <QtCore/qlist.h>
#include <QtCore/qmap.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qvector.h>
#include <dbus/dbus.h>
template <typename T>
inline T qIterGet(DBusMessageIter *it)
{
T t;
dbus_message_iter_get_basic(it, &t);
return t;
}
static QStringList qFetchStringList(DBusMessageIter *arrayIt)
{
QStringList list;
DBusMessageIter it;
dbus_message_iter_recurse(arrayIt, &it);
do {
list.append(QString::fromUtf8(qIterGet<char *>(&it)));
} while (dbus_message_iter_next(&it));
return list;
}
static QVariant qFetchParameter(DBusMessageIter *it)
{
switch (dbus_message_iter_get_arg_type(it)) {
case DBUS_TYPE_BYTE:
return qIterGet<unsigned char>(it);
case DBUS_TYPE_INT32:
return qIterGet<dbus_int32_t>(it);
case DBUS_TYPE_UINT32:
return qIterGet<dbus_uint32_t>(it);
case DBUS_TYPE_DOUBLE:
return qIterGet<double>(it);
case DBUS_TYPE_BOOLEAN:
return qIterGet<dbus_bool_t>(it);
case DBUS_TYPE_INT64:
return qIterGet<dbus_int64_t>(it);
case DBUS_TYPE_UINT64:
return qIterGet<dbus_uint64_t>(it);
case DBUS_TYPE_STRING:
case DBUS_TYPE_OBJECT_PATH:
case DBUS_TYPE_SIGNATURE:
return QString::fromUtf8(qIterGet<char *>(it));
case DBUS_TYPE_ARRAY: {
int arrayType = dbus_message_iter_get_element_type(it);
if (arrayType == DBUS_TYPE_STRING || arrayType == DBUS_TYPE_OBJECT_PATH) {
return qFetchStringList(it);
} else if (arrayType == DBUS_TYPE_DICT_ENTRY) {
// ### support other types of maps?
QMap<QString, QVariant> map;
DBusMessageIter sub;
dbus_message_iter_recurse(it, &sub);
if (!dbus_message_iter_has_next(&sub))
return map;
do {
DBusMessageIter itemIter;
dbus_message_iter_recurse(&sub, &itemIter);
Q_ASSERT(dbus_message_iter_has_next(&itemIter));
QString key = qFetchParameter(&itemIter).toString();
dbus_message_iter_next(&itemIter);
map.insertMulti(key, qFetchParameter(&itemIter));
} while (dbus_message_iter_next(&sub));
return map;
} else {
QList<QVariant> list;
DBusMessageIter sub;
dbus_message_iter_recurse(it, &sub);
if (!dbus_message_iter_has_next(&sub))
return list;
do {
list.append(qFetchParameter(&sub));
} while (dbus_message_iter_next(&sub));
return list;
}
break; }
case DBUS_TYPE_VARIANT: {
QDBusVariant dvariant;
DBusMessageIter sub;
dbus_message_iter_recurse(it, &sub);
dvariant.signature = QString::fromUtf8(dbus_message_iter_get_signature(&sub));
dvariant.value = qFetchParameter(&sub);
return qVariantFromValue(dvariant);
}
#if 0
case DBUS_TYPE_DICT: {
QMap<QString, QVariant> map;
DBusMessageIter sub;
dbus_message
if (dbus_message_iter_init_dict_iterator(it, &dictIt)) {
do {
map[QString::fromUtf8(dbus_message_iter_get_dict_key(&dictIt))] =
qFetchParameter(&dictIt);
} while (dbus_message_iter_next(&dictIt));
}
return map;
break; }
case DBUS_TYPE_CUSTOM:
return qGetCustomValue(it);
break;
#endif
default:
qWarning("Don't know how to handle type %d '%c'", dbus_message_iter_get_arg_type(it), dbus_message_iter_get_arg_type(it));
return QVariant();
break;
}
}
void QDBusMarshall::messageToList(QList<QVariant> &list, DBusMessage *message)
{
Q_ASSERT(message);
DBusMessageIter it;
if (!dbus_message_iter_init(message, &it))
return;
do {
list.append(qFetchParameter(&it));
} while (dbus_message_iter_next(&it));
}
#define DBUS_APPEND(type,dtype,var) \
type dtype##v=(var); \
dbus_message_append_args(msg, dtype, &dtype##v, DBUS_TYPE_INVALID)
#define DBUS_APPEND_LIST(type,dtype,var,size) \
type dtype##v=(var); \
dbus_message_append_args(msg, DBUS_TYPE_ARRAY, dtype, &dtype##v, size, DBUS_TYPE_INVALID)
static void qAppendToMessage(DBusMessageIter *it, const QString &str)
{
QByteArray ba = str.toUtf8();
const char *cdata = ba.constData();
dbus_message_iter_append_basic(it, DBUS_TYPE_STRING, &cdata);
}
static QVariant::Type qVariantListType(const QList<QVariant> &list)
{
// TODO - catch lists that have a list as first parameter
QVariant::Type tp = list.value(0).type();
if (tp < QVariant::Int || tp > QVariant::Double)
return QVariant::Invalid;
for (int i = 1; i < list.count(); ++i) {
const QVariant &var = list.at(i);
if (var.type() != tp
&& (var.type() != QVariant::List || qVariantListType(var.toList()) != tp))
return QVariant::Invalid;
}
return tp;
}
static const char *qDBusListType(const QList<QVariant> &list)
{
static const char *DBusArgs[] = { 0, 0, DBUS_TYPE_INT32_AS_STRING, DBUS_TYPE_UINT32_AS_STRING,
DBUS_TYPE_INT64_AS_STRING, DBUS_TYPE_UINT64_AS_STRING, DBUS_TYPE_DOUBLE_AS_STRING };
return DBusArgs[qVariantListType(list)];
}
static void qListToIterator(DBusMessageIter *it, const QList<QVariant> &list);
static void qVariantToIterator(DBusMessageIter *it, const QVariant &var)
{
static const int Variant2DBus[] = { DBUS_TYPE_INVALID,
DBUS_TYPE_BOOLEAN, DBUS_TYPE_INT32, DBUS_TYPE_UINT32,
DBUS_TYPE_INT64, DBUS_TYPE_UINT64, DBUS_TYPE_DOUBLE };
// these really are static asserts
Q_ASSERT(QVariant::Invalid == 0);
Q_ASSERT(QVariant::Int == 2);
Q_ASSERT(QVariant::Double == 6);
switch (var.type()) {
case QVariant::Int:
case QVariant::UInt:
case QVariant::LongLong:
case QVariant::ULongLong:
case QVariant::Double:
dbus_message_iter_append_basic(it, Variant2DBus[var.type()],
var.constData());
break;
case QVariant::String:
qAppendToMessage(it, var.toString());
break;
case QVariant::StringList: {
const QStringList list = var.toStringList();
DBusMessageIter sub;
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY,
DBUS_TYPE_STRING_AS_STRING, &sub);
for (int s = 0; s < list.count(); ++s)
qAppendToMessage(&sub, list.at(s));
dbus_message_iter_close_container(it, &sub);
break;
}
case QVariant::List: {
const QList<QVariant> &list = var.toList();
const char *listType = qDBusListType(list);
if (!listType) {
qWarning("Don't know how to marshall list.");
break;
}
DBusMessageIter sub;
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, listType, &sub);
qListToIterator(&sub, list);
dbus_message_iter_close_container(it, &sub);
break;
}
case QVariant::Map: {
// ### TODO - marshall more than qstring/qstring maps
const QMap<QString, QVariant> &map = var.toMap();
DBusMessageIter sub;
QVarLengthArray<char, 16> sig;
sig.append(DBUS_DICT_ENTRY_BEGIN_CHAR);
sig.append(DBUS_TYPE_STRING);
sig.append(DBUS_TYPE_STRING);
sig.append(DBUS_DICT_ENTRY_END_CHAR);
sig.append('\0');
qDebug() << QString::fromAscii(sig.constData());
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, sig.constData(), &sub);
for (QMap<QString, QVariant>::const_iterator mit = map.constBegin();
mit != map.constEnd(); ++mit) {
DBusMessageIter itemIterator;
dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, 0, &itemIterator);
qAppendToMessage(&itemIterator, mit.key());
qAppendToMessage(&itemIterator, mit.value().toString());
dbus_message_iter_close_container(&sub, &itemIterator);
}
dbus_message_iter_close_container(it, &sub);
break;
}
case QVariant::UserType: {
if (var.userType() == QMetaTypeId<QDBusVariant>::qt_metatype_id()) {
DBusMessageIter sub;
QDBusVariant dvariant = qvariant_cast<QDBusVariant>(var);
dbus_message_iter_open_container(it, DBUS_TYPE_VARIANT,
dvariant.signature.toUtf8().constData(), &sub);
qVariantToIterator(&sub, dvariant.value);
dbus_message_iter_close_container(it, &sub);
break;
}
}
// fall through
default:
qWarning("Don't know how to handle type %s", var.typeName());
break;
}
}
void qListToIterator(DBusMessageIter *it, const QList<QVariant> &list)
{
if (list.isEmpty())
return;
for (int i = 0; i < list.count(); ++i)
qVariantToIterator(it, list.at(i));
}
void QDBusMarshall::listToMessage(const QList<QVariant> &list, DBusMessage *msg)
{
Q_ASSERT(msg);
DBusMessageIter it;
dbus_message_iter_init_append(msg, &it);
qListToIterator(&it, list);
}
--- NEW FILE: qdbusmarshall.h ---
/* qdbusmarshall.h QDBusMarshall object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef QDBUSMARSHALL_H
#define QDBUSMARSHALL_H
struct DBusMessage;
class QVariant;
template <typename T>
class QList;
class QDBusMarshall
{
public:
static void listToMessage(const QList<QVariant> &list, DBusMessage *message);
static void messageToList(QList<QVariant> &list, DBusMessage *message);
};
#endif
--- NEW FILE: qdbusmessage.cpp ---
/* qdbusmessage.cpp
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "qdbusmessage.h"
#include <QtCore/qdebug.h>
#include <QtCore/qstringlist.h>
#include <dbus/dbus.h>
#include "qdbusmarshall.h"
#include "qdbusmessage_p.h"
QDBusMessagePrivate::QDBusMessagePrivate(QDBusMessage *qq)
: msg(0), reply(0), q(qq), type(DBUS_MESSAGE_TYPE_INVALID), timeout(-1), ref(1)
{
}
QDBusMessagePrivate::~QDBusMessagePrivate()
{
if (msg)
dbus_message_unref(msg);
if (reply)
dbus_message_unref(reply);
}
///////////////
QDBusMessage QDBusMessage::signal(const QString &path, const QString &interface,
const QString &name)
{
QDBusMessage message;
message.d->type = DBUS_MESSAGE_TYPE_SIGNAL;
message.d->path = path;
message.d->interface = interface;
message.d->name = name;
return message;
}
QDBusMessage QDBusMessage::methodCall(const QString &service, const QString &path,
const QString &interface, const QString &method)
{
QDBusMessage message;
message.d->type = DBUS_MESSAGE_TYPE_METHOD_CALL;
message.d->service = service;
message.d->path = path;
message.d->interface = interface;
message.d->method = method;
return message;
}
QDBusMessage QDBusMessage::methodReply(const QDBusMessage &other)
{
Q_ASSERT(other.d->msg);
QDBusMessage message;
message.d->type = DBUS_MESSAGE_TYPE_METHOD_RETURN;
message.d->reply = dbus_message_ref(other.d->msg);
return message;
}
QDBusMessage::QDBusMessage()
{
d = new QDBusMessagePrivate(this);
}
QDBusMessage::QDBusMessage(const QDBusMessage &other)
: QList<QVariant>(other)
{
d = other.d;
d->ref.ref();
}
QDBusMessage::~QDBusMessage()
{
if (!d->ref.deref())
delete d;
}
QDBusMessage &QDBusMessage::operator=(const QDBusMessage &other)
{
QList<QVariant>::operator=(other);
qAtomicAssign(d, other.d);
return *this;
}
DBusMessage *QDBusMessage::toDBusMessage() const
{
DBusMessage *msg = 0;
switch (d->type) {
case DBUS_MESSAGE_TYPE_METHOD_CALL:
msg = dbus_message_new_method_call(d->service.toUtf8().constData(),
d->path.toUtf8().constData(), d->interface.toUtf8().constData(),
d->method.toUtf8().constData());
break;
case DBUS_MESSAGE_TYPE_SIGNAL:
msg = dbus_message_new_signal(d->path.toUtf8().constData(),
d->interface.toUtf8().constData(), d->name.toUtf8().constData());
break;
case DBUS_MESSAGE_TYPE_METHOD_RETURN:
msg = dbus_message_new_method_return(d->reply);
break;
}
if (!msg)
return 0;
QDBusMarshall::listToMessage(*this, msg);
return msg;
}
QDBusMessage QDBusMessage::fromDBusMessage(DBusMessage *dmsg)
{
QDBusMessage message;
if (!dmsg)
return message;
message.d->type = dbus_message_get_type(dmsg);
message.d->path = QString::fromUtf8(dbus_message_get_path(dmsg));
message.d->interface = QString::fromUtf8(dbus_message_get_interface(dmsg));
message.d->name = QString::fromUtf8(dbus_message_get_member(dmsg));
message.d->sender = QString::fromUtf8(dbus_message_get_sender(dmsg));
message.d->msg = dbus_message_ref(dmsg);
QDBusMarshall::messageToList(message, dmsg);
return message;
}
QString QDBusMessage::path() const
{
return d->path;
}
QString QDBusMessage::interface() const
{
return d->interface;
}
QString QDBusMessage::name() const
{
return d->name;
}
QString QDBusMessage::sender() const
{
return d->sender;
}
int QDBusMessage::timeout() const
{
return d->timeout;
}
void QDBusMessage::setTimeout(int ms)
{
d->timeout = ms;
}
/*!
Returns the unique serial number assigned to this message
or 0 if the message was not sent yet.
*/
int QDBusMessage::serialNumber() const
{
if (!d->msg)
return 0;
return dbus_message_get_serial(d->msg);
}
/*!
Returns the unique serial number assigned to the message
that triggered this reply message.
If this message is not a reply to another message, 0
is returned.
*/
int QDBusMessage::replySerialNumber() const
{
if (!d->msg)
return 0;
return dbus_message_get_reply_serial(d->msg);
}
QDBusMessage::MessageType QDBusMessage::type() const
{
switch (d->type) {
case DBUS_MESSAGE_TYPE_METHOD_CALL:
return MethodCallMessage;
case DBUS_MESSAGE_TYPE_METHOD_RETURN:
return ReplyMessage;
case DBUS_MESSAGE_TYPE_ERROR:
return ErrorMessage;
case DBUS_MESSAGE_TYPE_SIGNAL:
return SignalMessage;
default:
return InvalidMessage;
}
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const QDBusMessage &msg)
{
dbg.nospace() << "QDBusMessage(" << msg.path() << ", " << msg.interface() << ", "
<< msg.name() << ", " << msg.sender() << ", "
<< static_cast<QList<QVariant> >(msg) << ")";
return dbg.space();
}
#endif
--- NEW FILE: qdbusmessage.h ---
/* qdbusmessage.h QDBusMessage object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef QDBUSMESSAGE_H
#define QDBUSMESSAGE_H
#include "qdbusmacros.h"
#include <QtCore/qlist.h>
#include <QtCore/qvariant.h>
#include <limits.h>
class QDBusMessagePrivate;
struct DBusMessage;
class QDBUS_EXPORT QDBusMessage: public QList<QVariant>
{
friend class QDBusConnection;
public:
enum { DefaultTimeout = -1, NoTimeout = INT_MAX};
enum MessageType { InvalidMessage, MethodCallMessage, ReplyMessage,
ErrorMessage, SignalMessage };
QDBusMessage();
QDBusMessage(const QDBusMessage &other);
~QDBusMessage();
QDBusMessage &operator=(const QDBusMessage &other);
static QDBusMessage signal(const QString &path, const QString &interface,
const QString &name);
static QDBusMessage methodCall(const QString &service, const QString &path,
const QString &interface, const QString &method);
static QDBusMessage methodReply(const QDBusMessage &other);
QString path() const;
QString interface() const;
QString name() const; //rename to member?
QString sender() const; //rename to service?
MessageType type() const;
int timeout() const;
void setTimeout(int ms);
//protected:
DBusMessage *toDBusMessage() const;
static QDBusMessage fromDBusMessage(DBusMessage *dmsg);
int serialNumber() const;
int replySerialNumber() const;
private:
QDBusMessagePrivate *d;
};
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug, const QDBusMessage &);
#endif
#endif
--- NEW FILE: qdbusmessage_p.h ---
/* qdbusmessage.h QDBusMessage private object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef QDBUSMESSAGE_P_H
#define QDBUSMESSAGE_P_H
#include <QtCore/qatomic.h>
#include <QtCore/qstring.h>
struct DBusMessage;
class QDBusMessagePrivate
{
public:
QDBusMessagePrivate(QDBusMessage *qq);
~QDBusMessagePrivate();
QString path, interface, name, service, method, sender;
DBusMessage *msg;
DBusMessage *reply;
QDBusMessage *q;
int type;
int timeout;
QAtomic ref;
};
#endif
--- NEW FILE: qdbusserver.cpp ---
/* qdbusserver.cpp
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "qdbusserver.h"
#include "qdbusconnection_p.h"
QDBusServer::QDBusServer(const QString &addr, QObject *parent)
: QObject(parent)
{
d = new QDBusConnectionPrivate(this);
if (addr.isEmpty())
return;
d->setServer(dbus_server_listen(addr.toUtf8().constData(), &d->error));
}
bool QDBusServer::isConnected() const
{
return d->server && dbus_server_get_is_connected(d->server);
}
QDBusError QDBusServer::lastError() const
{
return d->lastError;
}
QString QDBusServer::address() const
{
QString addr;
if (d->server) {
char *c = dbus_server_get_address(d->server);
addr = QString::fromUtf8(c);
dbus_free(c);
}
return addr;
}
#include "qdbusserver.moc"
--- NEW FILE: qdbusserver.h ---
/* qdbusserver.h QDBusServer object
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef QDBUSSERVER_H
#define QDBUSSERVER_H
#include "qdbusmacros.h"
#include <QtCore/qobject.h>
#include <QtCore/qstring.h>
class QDBusConnectionPrivate;
class QDBusError;
class QDBUS_EXPORT QDBusServer: public QObject
{
Q_OBJECT
public:
QDBusServer(const QString &address, QObject *parent = 0);
bool isConnected() const;
QDBusError lastError() const;
QString address() const;
private:
Q_DISABLE_COPY(QDBusServer)
QDBusConnectionPrivate *d;
};
#endif
--- NEW FILE: qdbusvariant.h ---
/* qdbusvariant.h DBUS variant struct
*
* Copyright (C) 2005 Harald Fernengel <harry at kdevelop.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef QDBUSVARIANT_H
#define QDBUSVARIANT_H
#include "qdbusmacros.h"
#include <QtCore/qmetatype.h>
#include <QtCore/qstring.h>
#include <QtCore/qvariant.h>
struct QDBUS_EXPORT QDBusVariant
{
QString signature;
QVariant value;
};
Q_DECLARE_METATYPE(QDBusVariant)
#endif
--- server.cpp DELETED ---
--- server.h DELETED ---
More information about the dbus-commit
mailing list