summaryrefslogtreecommitdiffstats
path: root/src/dbus
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/dbus
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/dbus')
-rw-r--r--src/dbus/dbus.pro90
-rw-r--r--src/dbus/qdbus_symbols.cpp118
-rw-r--r--src/dbus/qdbus_symbols_p.h375
-rw-r--r--src/dbus/qdbusabstractadaptor.cpp384
-rw-r--r--src/dbus/qdbusabstractadaptor.h80
-rw-r--r--src/dbus/qdbusabstractadaptor_p.h138
-rw-r--r--src/dbus/qdbusabstractinterface.cpp776
-rw-r--r--src/dbus/qdbusabstractinterface.h165
-rw-r--r--src/dbus/qdbusabstractinterface_p.h104
-rw-r--r--src/dbus/qdbusargument.cpp1362
-rw-r--r--src/dbus/qdbusargument.h405
-rw-r--r--src/dbus/qdbusargument_p.h222
-rw-r--r--src/dbus/qdbusconnection.cpp1154
-rw-r--r--src/dbus/qdbusconnection.h199
-rw-r--r--src/dbus/qdbusconnection_p.h347
-rw-r--r--src/dbus/qdbusconnectioninterface.cpp419
-rw-r--r--src/dbus/qdbusconnectioninterface.h132
-rw-r--r--src/dbus/qdbusconnectionmanager_p.h88
-rw-r--r--src/dbus/qdbuscontext.cpp208
-rw-r--r--src/dbus/qdbuscontext.h87
-rw-r--r--src/dbus/qdbuscontext_p.h83
-rw-r--r--src/dbus/qdbusdemarshaller.cpp364
-rw-r--r--src/dbus/qdbuserror.cpp368
-rw-r--r--src/dbus/qdbuserror.h126
-rw-r--r--src/dbus/qdbusextratypes.cpp242
-rw-r--r--src/dbus/qdbusextratypes.h193
-rw-r--r--src/dbus/qdbusintegrator.cpp2411
-rw-r--r--src/dbus/qdbusintegrator_p.h162
-rw-r--r--src/dbus/qdbusinterface.cpp328
-rw-r--r--src/dbus/qdbusinterface.h82
-rw-r--r--src/dbus/qdbusinterface_p.h82
-rw-r--r--src/dbus/qdbusinternalfilters.cpp503
-rw-r--r--src/dbus/qdbusintrospection.cpp429
-rw-r--r--src/dbus/qdbusintrospection_p.h180
-rw-r--r--src/dbus/qdbusmacros.h70
-rw-r--r--src/dbus/qdbusmarshaller.cpp573
-rw-r--r--src/dbus/qdbusmessage.cpp805
-rw-r--r--src/dbus/qdbusmessage.h132
-rw-r--r--src/dbus/qdbusmessage_p.h110
-rw-r--r--src/dbus/qdbusmetaobject.cpp703
-rw-r--r--src/dbus/qdbusmetaobject_p.h94
-rw-r--r--src/dbus/qdbusmetatype.cpp483
-rw-r--r--src/dbus/qdbusmetatype.h100
-rw-r--r--src/dbus/qdbusmetatype_p.h75
-rw-r--r--src/dbus/qdbusmisc.cpp201
-rw-r--r--src/dbus/qdbuspendingcall.cpp539
-rw-r--r--src/dbus/qdbuspendingcall.h125
-rw-r--r--src/dbus/qdbuspendingcall_p.h141
-rw-r--r--src/dbus/qdbuspendingreply.cpp281
-rw-r--r--src/dbus/qdbuspendingreply.h217
-rw-r--r--src/dbus/qdbusreply.cpp248
-rw-r--r--src/dbus/qdbusreply.h199
-rw-r--r--src/dbus/qdbusserver.cpp140
-rw-r--r--src/dbus/qdbusserver.h84
-rw-r--r--src/dbus/qdbusservicewatcher.cpp381
-rw-r--r--src/dbus/qdbusservicewatcher.h106
-rw-r--r--src/dbus/qdbusthreaddebug_p.h235
-rw-r--r--src/dbus/qdbusunixfiledescriptor.cpp316
-rw-r--r--src/dbus/qdbusunixfiledescriptor.h103
-rw-r--r--src/dbus/qdbusutil.cpp568
-rw-r--r--src/dbus/qdbusutil_p.h167
-rw-r--r--src/dbus/qdbusxmlgenerator.cpp308
-rw-r--r--src/dbus/qdbusxmlparser.cpp378
-rw-r--r--src/dbus/qdbusxmlparser_p.h88
64 files changed, 20376 insertions, 0 deletions
diff --git a/src/dbus/dbus.pro b/src/dbus/dbus.pro
new file mode 100644
index 0000000000..08c9ea1fb2
--- /dev/null
+++ b/src/dbus/dbus.pro
@@ -0,0 +1,90 @@
+TARGET = QtDBus
+QPRO_PWD = $$PWD
+QT = core \
+ xml
+CONFIG += link_pkgconfig
+DEFINES += QT_BUILD_DBUS_LIB \
+ DBUS_API_SUBJECT_TO_CHANGE
+QMAKE_CXXFLAGS += $$QT_CFLAGS_DBUS
+contains(QT_CONFIG, dbus-linked) {
+ LIBS_PRIVATE += $$QT_LIBS_DBUS
+ DEFINES += QT_LINKED_LIBDBUS
+}
+
+# INCLUDEPATH += .
+unix|win32-g++* {
+ QMAKE_PKGCONFIG_DESCRIPTION = Qt \
+ DBus \
+ module
+ QMAKE_PKGCONFIG_REQUIRES = QtCore \
+ QtXml
+}
+win32 {
+ wince*:LIBS_PRIVATE += -lws2
+ else:LIBS_PRIVATE += -lws2_32 \
+ -ladvapi32 \
+ -lnetapi32 \
+ -luser32
+ CONFIG(debug, debug|release):LIBS_PRIVATE += -ldbus-1d
+ else:LIBS_PRIVATE += -ldbus-1
+}
+include(../qbase.pri)
+PUB_HEADERS = qdbusargument.h \
+ qdbusconnectioninterface.h \
+ qdbusmacros.h \
+ qdbuserror.h \
+ qdbusextratypes.h \
+ qdbusmessage.h \
+ qdbusserver.h \
+ qdbusconnection.h \
+ qdbusabstractinterface.h \
+ qdbusinterface.h \
+ qdbusabstractadaptor.h \
+ qdbusreply.h \
+ qdbusmetatype.h \
+ qdbuspendingcall.h \
+ qdbuspendingreply.h \
+ qdbuscontext.h
+HEADERS += $$PUB_HEADERS \
+ qdbusconnection_p.h \
+ qdbusmessage_p.h \
+ qdbusinterface_p.h \
+ qdbusxmlparser_p.h \
+ qdbusabstractadaptor_p.h \
+ qdbusargument_p.h \
+ qdbusutil_p.h \
+ qdbusabstractinterface_p.h \
+ qdbuscontext_p.h \
+ qdbusthreaddebug_p.h \
+ qdbusintegrator_p.h \
+ qdbuspendingcall_p.h \
+ qdbus_symbols_p.h \
+ qdbusservicewatcher.h \
+ qdbusunixfiledescriptor.h
+SOURCES += qdbusconnection.cpp \
+ qdbusconnectioninterface.cpp \
+ qdbuserror.cpp \
+ qdbusintegrator.cpp \
+ qdbusmessage.cpp \
+ qdbusserver.cpp \
+ qdbusabstractinterface.cpp \
+ qdbusinterface.cpp \
+ qdbusxmlparser.cpp \
+ qdbusutil.cpp \
+ qdbusintrospection.cpp \
+ qdbusabstractadaptor.cpp \
+ qdbusinternalfilters.cpp \
+ qdbusmetaobject.cpp \
+ qdbusxmlgenerator.cpp \
+ qdbusmisc.cpp \
+ qdbusargument.cpp \
+ qdbusreply.cpp \
+ qdbusmetatype.cpp \
+ qdbusextratypes.cpp \
+ qdbusmarshaller.cpp \
+ qdbuscontext.cpp \
+ qdbuspendingcall.cpp \
+ qdbuspendingreply.cpp \
+ qdbus_symbols.cpp \
+ qdbusservicewatcher.cpp \
+ qdbusunixfiledescriptor.cpp
diff --git a/src/dbus/qdbus_symbols.cpp b/src/dbus/qdbus_symbols.cpp
new file mode 100644
index 0000000000..a62d52e04e
--- /dev/null
+++ b/src/dbus/qdbus_symbols.cpp
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qlibrary.h>
+#include <QtCore/qmutex.h>
+#include <private/qmutexpool_p.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+void *qdbus_resolve_me(const char *name);
+
+#if !defined QT_LINKED_LIBDBUS
+
+static QLibrary *qdbus_libdbus = 0;
+
+void qdbus_unloadLibDBus()
+{
+ delete qdbus_libdbus;
+ qdbus_libdbus = 0;
+}
+
+bool qdbus_loadLibDBus()
+{
+ static volatile bool triedToLoadLibrary = false;
+#ifndef QT_NO_THREAD
+ QMutexLocker locker(QMutexPool::globalInstanceGet((void *)&qdbus_resolve_me));
+#endif
+ QLibrary *&lib = qdbus_libdbus;
+ if (triedToLoadLibrary)
+ return lib && lib->isLoaded();
+
+ lib = new QLibrary;
+ triedToLoadLibrary = true;
+
+ static int majorversions[] = { 3, 2, -1 };
+ lib->unload();
+ lib->setFileName(QLatin1String("dbus-1"));
+ for (uint i = 0; i < sizeof(majorversions) / sizeof(majorversions[0]); ++i) {
+ lib->setFileNameAndVersion(lib->fileName(), majorversions[i]);
+ if (lib->load() && lib->resolve("dbus_connection_open_private"))
+ return true;
+
+ lib->unload();
+ }
+
+ delete lib;
+ lib = 0;
+ return false;
+}
+
+void *qdbus_resolve_conditionally(const char *name)
+{
+ if (qdbus_loadLibDBus())
+ return qdbus_libdbus->resolve(name);
+ return 0;
+}
+
+void *qdbus_resolve_me(const char *name)
+{
+ void *ptr = 0;
+ if (!qdbus_loadLibDBus())
+ qFatal("Cannot find libdbus-1 in your system to resolve symbol '%s'.", name);
+
+ ptr = qdbus_libdbus->resolve(name);
+ if (!ptr)
+ qFatal("Cannot resolve '%s' in your libdbus-1.", name);
+
+ return ptr;
+}
+
+Q_DESTRUCTOR_FUNCTION(qdbus_unloadLibDBus)
+
+#endif // QT_LINKED_LIBDBUS
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbus_symbols_p.h b/src/dbus/qdbus_symbols_p.h
new file mode 100644
index 0000000000..039657ef0b
--- /dev/null
+++ b/src/dbus/qdbus_symbols_p.h
@@ -0,0 +1,375 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+//
+
+#ifndef QDBUS_SYMBOLS_P_H
+#define QDBUS_SYMBOLS_P_H
+
+#include <QtCore/qglobal.h>
+#include <dbus/dbus.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+#if !defined QT_LINKED_LIBDBUS
+
+void *qdbus_resolve_conditionally(const char *name); // doesn't print a warning
+void *qdbus_resolve_me(const char *name); // prints a warning
+bool qdbus_loadLibDBus();
+
+# define DEFINEFUNC(ret, func, args, argcall, funcret) \
+ typedef ret (* _q_PTR_##func) args; \
+ static inline ret q_##func args \
+ { \
+ static _q_PTR_##func ptr; \
+ if (!ptr) \
+ ptr = (_q_PTR_##func) qdbus_resolve_me(#func); \
+ funcret ptr argcall; \
+ }
+
+#else // defined QT_LINKED_LIBDBUS
+
+inline bool qdbus_loadLibDBus() { return true; }
+
+# define DEFINEFUNC(ret, func, args, argcall, funcret) \
+ static inline ret q_##func args { funcret func argcall; }
+
+#endif // defined QT_LINKED_LIBDBUS
+
+/* dbus-bus.h */
+DEFINEFUNC(void, dbus_bus_add_match, (DBusConnection *connection,
+ const char *rule,
+ DBusError *error),
+ (connection, rule, error), )
+DEFINEFUNC(void, dbus_bus_remove_match, (DBusConnection *connection,
+ const char *rule,
+ DBusError *error),
+ (connection, rule, error), )
+DEFINEFUNC(dbus_bool_t, dbus_bus_register,(DBusConnection *connection,
+ DBusError *error),
+ (connection, error), return)
+DEFINEFUNC(DBusConnection *, dbus_bus_get_private, (DBusBusType type,
+ DBusError *error),
+ (type, error), return)
+DEFINEFUNC(const char*, dbus_bus_get_unique_name, (DBusConnection *connection),
+ (connection), return)
+
+/* dbus-connection.h */
+DEFINEFUNC(dbus_bool_t , dbus_connection_add_filter, (DBusConnection *connection,
+ DBusHandleMessageFunction function,
+ void *user_data,
+ DBusFreeFunction free_data_function),
+ (connection, function, user_data, free_data_function), return)
+DEFINEFUNC(void , dbus_connection_close, (DBusConnection *connection),
+ (connection), return)
+DEFINEFUNC(DBusDispatchStatus , dbus_connection_dispatch, (DBusConnection *connection),
+ (connection), return)
+DEFINEFUNC(DBusDispatchStatus , dbus_connection_get_dispatch_status, (DBusConnection *connection),
+ (connection), return)
+DEFINEFUNC(dbus_bool_t , dbus_connection_get_is_connected, (DBusConnection *connection),
+ (connection), return)
+DEFINEFUNC(DBusConnection* , dbus_connection_open_private, (const char *address,
+ DBusError *error),
+ (address, error), return)
+DEFINEFUNC(DBusConnection* , dbus_connection_ref, (DBusConnection *connection),
+ (connection), return)
+DEFINEFUNC(dbus_bool_t , dbus_connection_send, (DBusConnection *connection,
+ DBusMessage *message,
+ dbus_uint32_t *client_serial),
+ (connection, message, client_serial), return)
+DEFINEFUNC(dbus_bool_t , dbus_connection_send_with_reply, (DBusConnection *connection,
+ DBusMessage *message,
+ DBusPendingCall **pending_return,
+ int timeout_milliseconds),
+ (connection, message, pending_return, timeout_milliseconds), return)
+DEFINEFUNC(DBusMessage * , dbus_connection_send_with_reply_and_block, (DBusConnection *connection,
+ DBusMessage *message,
+ int timeout_milliseconds,
+ DBusError *error),
+ (connection, message, timeout_milliseconds, error), return)
+DEFINEFUNC(void , dbus_connection_set_exit_on_disconnect, (DBusConnection *connection,
+ dbus_bool_t exit_on_disconnect),
+ (connection, exit_on_disconnect), )
+DEFINEFUNC(dbus_bool_t , dbus_connection_set_timeout_functions, (DBusConnection *connection,
+ DBusAddTimeoutFunction add_function,
+ DBusRemoveTimeoutFunction remove_function,
+ DBusTimeoutToggledFunction toggled_function,
+ void *data,
+ DBusFreeFunction free_data_function),
+ (connection, add_function, remove_function, toggled_function, data, free_data_function), return)
+DEFINEFUNC(dbus_bool_t , dbus_connection_set_watch_functions, (DBusConnection *connection,
+ DBusAddWatchFunction add_function,
+ DBusRemoveWatchFunction remove_function,
+ DBusWatchToggledFunction toggled_function,
+ void *data,
+ DBusFreeFunction free_data_function),
+ (connection, add_function, remove_function, toggled_function, data, free_data_function), return)
+DEFINEFUNC(void , dbus_connection_set_wakeup_main_function, (DBusConnection *connection,
+ DBusWakeupMainFunction wakeup_main_function,
+ void *data,
+ DBusFreeFunction free_data_function),
+ (connection, wakeup_main_function, data, free_data_function), )
+DEFINEFUNC(void , dbus_connection_set_dispatch_status_function, (DBusConnection *connection,
+ DBusDispatchStatusFunction function,
+ void *data,
+ DBusFreeFunction free_data_function),
+ (connection, function, data, free_data_function), )
+
+DEFINEFUNC(void , dbus_connection_unref, (DBusConnection *connection),
+ (connection), )
+DEFINEFUNC(dbus_bool_t , dbus_timeout_get_enabled, (DBusTimeout *timeout),
+ (timeout), return)
+DEFINEFUNC(int , dbus_timeout_get_interval, (DBusTimeout *timeout),
+ (timeout), return)
+DEFINEFUNC(dbus_bool_t , dbus_timeout_handle, (DBusTimeout *timeout),
+ (timeout), return)
+
+DEFINEFUNC(dbus_bool_t , dbus_watch_get_enabled, (DBusWatch *watch),
+ (watch), return)
+DEFINEFUNC(int , dbus_watch_get_fd, (DBusWatch *watch),
+ (watch), return)
+DEFINEFUNC(unsigned int , dbus_watch_get_flags, (DBusWatch *watch),
+ (watch), return)
+DEFINEFUNC(dbus_bool_t , dbus_watch_handle, (DBusWatch *watch,
+ unsigned int flags),
+ (watch, flags), return)
+
+/* dbus-errors.h */
+DEFINEFUNC(void , dbus_error_free, (DBusError *error),
+ (error), )
+DEFINEFUNC(void , dbus_error_init, (DBusError *error),
+ (error), )
+DEFINEFUNC(dbus_bool_t , dbus_error_is_set, (const DBusError *error),
+ (error), return)
+
+/* dbus-memory.h */
+DEFINEFUNC(void , dbus_free, (void *memory), (memory), )
+
+/* dbus-message.h */
+DEFINEFUNC(DBusMessage* , dbus_message_copy, (const DBusMessage *message),
+ (message), return)
+DEFINEFUNC(dbus_bool_t , dbus_message_get_auto_start, (DBusMessage *message),
+ (message), return)
+DEFINEFUNC(const char* , dbus_message_get_error_name, (DBusMessage *message),
+ (message), return)
+DEFINEFUNC(const char* , dbus_message_get_interface, (DBusMessage *message),
+ (message), return)
+DEFINEFUNC(const char* , dbus_message_get_member, (DBusMessage *message),
+ (message), return)
+DEFINEFUNC(dbus_bool_t , dbus_message_get_no_reply, (DBusMessage *message),
+ (message), return)
+DEFINEFUNC(const char* , dbus_message_get_path, (DBusMessage *message),
+ (message), return)
+DEFINEFUNC(const char* , dbus_message_get_sender, (DBusMessage *message),
+ (message), return)
+DEFINEFUNC(dbus_uint32_t , dbus_message_get_serial, (DBusMessage *message),
+ (message), return)
+DEFINEFUNC(const char* , dbus_message_get_signature, (DBusMessage *message),
+ (message), return)
+DEFINEFUNC(int , dbus_message_get_type, (DBusMessage *message),
+ (message), return)
+DEFINEFUNC(dbus_bool_t , dbus_message_iter_append_basic, (DBusMessageIter *iter,
+ int type,
+ const void *value),
+ (iter, type, value), return)
+DEFINEFUNC(dbus_bool_t , dbus_message_iter_append_fixed_array, (DBusMessageIter *iter,
+ int element_type,
+ const void *value,
+ int n_elements),
+ (iter, element_type, value, n_elements), return)
+DEFINEFUNC(dbus_bool_t , dbus_message_iter_close_container, (DBusMessageIter *iter,
+ DBusMessageIter *sub),
+ (iter, sub), return)
+DEFINEFUNC(int , dbus_message_iter_get_arg_type, (DBusMessageIter *iter),
+ (iter), return)
+DEFINEFUNC(void , dbus_message_iter_get_basic, (DBusMessageIter *iter,
+ void *value),
+ (iter, value), )
+DEFINEFUNC(int , dbus_message_iter_get_element_type, (DBusMessageIter *iter),
+ (iter), return)
+DEFINEFUNC(void , dbus_message_iter_get_fixed_array, (DBusMessageIter *iter,
+ void *value,
+ int *n_elements),
+ (iter, value, n_elements), return)
+DEFINEFUNC(char* , dbus_message_iter_get_signature, (DBusMessageIter *iter),
+ (iter), return)
+DEFINEFUNC(dbus_bool_t , dbus_message_iter_init, (DBusMessage *message,
+ DBusMessageIter *iter),
+ (message, iter), return)
+DEFINEFUNC(void , dbus_message_iter_init_append, (DBusMessage *message,
+ DBusMessageIter *iter),
+ (message, iter), return)
+DEFINEFUNC(dbus_bool_t , dbus_message_iter_next, (DBusMessageIter *iter),
+ (iter), return)
+DEFINEFUNC(dbus_bool_t , dbus_message_iter_open_container, (DBusMessageIter *iter,
+ int type,
+ const char *contained_signature,
+ DBusMessageIter *sub),
+ (iter, type, contained_signature, sub), return)
+DEFINEFUNC(void , dbus_message_iter_recurse, (DBusMessageIter *iter,
+ DBusMessageIter *sub),
+ (iter, sub), )
+DEFINEFUNC(DBusMessage* , dbus_message_new, (int message_type),
+ (message_type), return)
+DEFINEFUNC(DBusMessage* , dbus_message_new_method_call, (const char *bus_name,
+ const char *path,
+ const char *interface,
+ const char *method),
+ (bus_name, path, interface, method), return)
+DEFINEFUNC(DBusMessage* , dbus_message_new_signal, (const char *path,
+ const char *interface,
+ const char *name),
+ (path, interface, name), return)
+DEFINEFUNC(DBusMessage* , dbus_message_ref, (DBusMessage *message),
+ (message), return)
+DEFINEFUNC(void , dbus_message_set_auto_start, (DBusMessage *message,
+ dbus_bool_t auto_start),
+ (message, auto_start), return)
+DEFINEFUNC(dbus_bool_t , dbus_message_set_destination, (DBusMessage *message,
+ const char *destination),
+ (message, destination), return)
+DEFINEFUNC(dbus_bool_t , dbus_message_set_error_name, (DBusMessage *message,
+ const char *name),
+ (message, name), return)
+DEFINEFUNC(void , dbus_message_set_no_reply, (DBusMessage *message,
+ dbus_bool_t no_reply),
+ (message, no_reply), return)
+DEFINEFUNC(dbus_bool_t , dbus_message_set_path, (DBusMessage *message,
+ const char *object_path),
+ (message, object_path), return)
+DEFINEFUNC(dbus_bool_t , dbus_message_set_reply_serial, (DBusMessage *message,
+ dbus_uint32_t reply_serial),
+ (message, reply_serial), return)
+DEFINEFUNC(dbus_bool_t , dbus_message_set_sender, (DBusMessage *message,
+ const char *sender),
+ (message, sender), return)
+DEFINEFUNC(void , dbus_message_unref, (DBusMessage *message),
+ (message), )
+
+/* dbus-misc.h */
+DEFINEFUNC(void , dbus_get_version , (int *major_version_p,
+ int *minor_version_p,
+ int *micro_version_p),
+ (major_version_p, minor_version_p, micro_version_p), )
+
+/* dbus-pending-call.h */
+DEFINEFUNC(dbus_bool_t , dbus_pending_call_set_notify, (DBusPendingCall *pending,
+ DBusPendingCallNotifyFunction function,
+ void *user_data,
+ DBusFreeFunction free_user_data),
+ (pending, function, user_data, free_user_data), return)
+DEFINEFUNC(void , dbus_pending_call_block, (DBusPendingCall *pending),
+ (pending), )
+DEFINEFUNC(void , dbus_pending_call_cancel, (DBusPendingCall *pending),
+ (pending), )
+DEFINEFUNC(dbus_bool_t , dbus_pending_call_get_completed, (DBusPendingCall *pending),
+ (pending), return)
+DEFINEFUNC(DBusMessage* , dbus_pending_call_steal_reply, (DBusPendingCall *pending),
+ (pending), return)
+DEFINEFUNC(void , dbus_pending_call_unref, (DBusPendingCall *pending),
+ (pending), return)
+
+/* dbus-server.h */
+DEFINEFUNC(dbus_bool_t , dbus_server_allocate_data_slot, (dbus_int32_t *slot_p),
+ (slot_p), return)
+DEFINEFUNC(void , dbus_server_disconnect, (DBusServer *server),
+ (server), )
+DEFINEFUNC(char* , dbus_server_get_address, (DBusServer *server),
+ (server), return)
+DEFINEFUNC(dbus_bool_t , dbus_server_get_is_connected, (DBusServer *server),
+ (server), return)
+DEFINEFUNC(DBusServer* , dbus_server_listen, (const char *address,
+ DBusError *error),
+ (address, error), return)
+DEFINEFUNC(dbus_bool_t , dbus_server_set_data, (DBusServer *server,
+ int slot,
+ void *data,
+ DBusFreeFunction free_data_func),
+ (server, slot, data, free_data_func), return)
+DEFINEFUNC(void , dbus_server_set_new_connection_function, (DBusServer *server,
+ DBusNewConnectionFunction function,
+ void *data,
+ DBusFreeFunction free_data_function),
+ (server, function, data, free_data_function), )
+DEFINEFUNC(dbus_bool_t , dbus_server_set_timeout_functions, (DBusServer *server,
+ DBusAddTimeoutFunction add_function,
+ DBusRemoveTimeoutFunction remove_function,
+ DBusTimeoutToggledFunction toggled_function,
+ void *data,
+ DBusFreeFunction free_data_function),
+ (server, add_function, remove_function, toggled_function, data, free_data_function), return)
+DEFINEFUNC(dbus_bool_t , dbus_server_set_watch_functions, (DBusServer *server,
+ DBusAddWatchFunction add_function,
+ DBusRemoveWatchFunction remove_function,
+ DBusWatchToggledFunction toggled_function,
+ void *data,
+ DBusFreeFunction free_data_function),
+ (server, add_function, remove_function, toggled_function, data, free_data_function), return)
+DEFINEFUNC(void , dbus_server_unref, (DBusServer *server),
+ (server), )
+
+/* dbus-thread.h */
+DEFINEFUNC(dbus_bool_t , dbus_threads_init_default, (), (), return)
+
+
+/* D-Bus 1.4 symbols */
+#if !defined(QT_LINKED_LIBDBUS) || (DBUS_VERSION >= 0x010400)
+DEFINEFUNC(dbus_bool_t , dbus_connection_can_send_type , (DBusConnection *connection,
+ int type),
+ (connection, type), return)
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
+#endif // QDBUS_SYMBOLS_P_H
diff --git a/src/dbus/qdbusabstractadaptor.cpp b/src/dbus/qdbusabstractadaptor.cpp
new file mode 100644
index 0000000000..c75bbaa639
--- /dev/null
+++ b/src/dbus/qdbusabstractadaptor.cpp
@@ -0,0 +1,384 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusabstractadaptor.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qset.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qthread.h>
+
+#include "qdbusconnection.h"
+
+#include "qdbusconnection_p.h" // for qDBusParametersForMethod
+#include "qdbusabstractadaptor_p.h"
+#include "qdbusmetatype_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+QDBusAdaptorConnector *qDBusFindAdaptorConnector(QObject *obj)
+{
+ if (!obj)
+ return 0;
+ const QObjectList &children = obj->children();
+ QObjectList::ConstIterator it = children.constBegin();
+ QObjectList::ConstIterator end = children.constEnd();
+ for ( ; it != end; ++it) {
+ QDBusAdaptorConnector *connector = qobject_cast<QDBusAdaptorConnector *>(*it);
+ if (connector) {
+ connector->polish();
+ return connector;
+ }
+ }
+ return 0;
+}
+
+QDBusAdaptorConnector *qDBusFindAdaptorConnector(QDBusAbstractAdaptor *adaptor)
+{
+ return qDBusFindAdaptorConnector(adaptor->parent());
+}
+
+QDBusAdaptorConnector *qDBusCreateAdaptorConnector(QObject *obj)
+{
+ QDBusAdaptorConnector *connector = qDBusFindAdaptorConnector(obj);
+ if (connector)
+ return connector;
+ return new QDBusAdaptorConnector(obj);
+}
+
+QString QDBusAbstractAdaptorPrivate::retrieveIntrospectionXml(QDBusAbstractAdaptor *adaptor)
+{
+ return adaptor->d_func()->xml;
+}
+
+void QDBusAbstractAdaptorPrivate::saveIntrospectionXml(QDBusAbstractAdaptor *adaptor,
+ const QString &xml)
+{
+ adaptor->d_func()->xml = xml;
+}
+
+/*!
+ \class QDBusAbstractAdaptor
+ \inmodule QtDBus
+ \since 4.2
+
+ \brief The QDBusAbstractAdaptor class is the base class of D-Bus adaptor classes.
+
+ The QDBusAbstractAdaptor class is the starting point for all objects intending to provide
+ interfaces to the external world using D-Bus. This is accomplished by attaching a one or more
+ classes derived from QDBusAbstractAdaptor to a normal QObject and then registering that QObject
+ with QDBusConnection::registerObject. QDBusAbstractAdaptor objects are intended to be
+ light-weight wrappers, mostly just relaying calls into the real object (its parent) and the
+ signals from it.
+
+ Each QDBusAbstractAdaptor-derived class should define the D-Bus interface it is implementing
+ using the Q_CLASSINFO macro in the class definition. Note that only one interface can be
+ exposed in this way.
+
+ QDBusAbstractAdaptor uses the standard QObject mechanism of signals, slots and properties to
+ determine what signals, methods and properties to export to the bus. Any signal emitted by
+ QDBusAbstractAdaptor-derived classes will be automatically be relayed through any D-Bus
+ connections the object is registered on.
+
+ Classes derived from QDBusAbstractAdaptor must be created on the heap using the \a new operator
+ and must not be deleted by the user (they will be deleted automatically when the object they are
+ connected to is also deleted).
+
+ \sa {usingadaptors.html}{Using adaptors}, QDBusConnection
+*/
+
+/*!
+ Constructs a QDBusAbstractAdaptor with \a obj as the parent object.
+*/
+QDBusAbstractAdaptor::QDBusAbstractAdaptor(QObject* obj)
+ : QObject(*new QDBusAbstractAdaptorPrivate, obj)
+{
+ QDBusAdaptorConnector *connector = qDBusCreateAdaptorConnector(obj);
+
+ connector->waitingForPolish = true;
+ QMetaObject::invokeMethod(connector, "polish", Qt::QueuedConnection);
+}
+
+/*!
+ Destroys the adaptor.
+
+ \warning Adaptors are destroyed automatically when the real object they refer to is
+ destroyed. Do not delete the adaptors yourself.
+*/
+QDBusAbstractAdaptor::~QDBusAbstractAdaptor()
+{
+}
+
+/*!
+ Toggles automatic signal relaying from the real object (see object()).
+
+ Automatic signal relaying consists of signal-to-signal connection of the signals on the parent
+ that have the exact same method signatue in both classes.
+
+ If \a enable is set to true, connect the signals; if set to false, disconnect all signals.
+*/
+void QDBusAbstractAdaptor::setAutoRelaySignals(bool enable)
+{
+ const QMetaObject *us = metaObject();
+ const QMetaObject *them = parent()->metaObject();
+ bool connected = false;
+ for (int idx = staticMetaObject.methodCount(); idx < us->methodCount(); ++idx) {
+ QMetaMethod mm = us->method(idx);
+
+ if (mm.methodType() != QMetaMethod::Signal)
+ continue;
+
+ // try to connect/disconnect to a signal on the parent that has the same method signature
+ QByteArray sig = QMetaObject::normalizedSignature(mm.signature());
+ if (them->indexOfSignal(sig) == -1)
+ continue;
+ sig.prepend(QSIGNAL_CODE + '0');
+ parent()->disconnect(sig, this, sig);
+ if (enable)
+ connected = connect(parent(), sig, sig) || connected;
+ }
+ d_func()->autoRelaySignals = connected;
+}
+
+/*!
+ Returns true if automatic signal relaying from the real object (see object()) is enabled,
+ otherwiser returns false.
+
+ \sa setAutoRelaySignals()
+*/
+bool QDBusAbstractAdaptor::autoRelaySignals() const
+{
+ return d_func()->autoRelaySignals;
+}
+
+QDBusAdaptorConnector::QDBusAdaptorConnector(QObject *obj)
+ : QObject(obj), waitingForPolish(false)
+{
+}
+
+QDBusAdaptorConnector::~QDBusAdaptorConnector()
+{
+}
+
+void QDBusAdaptorConnector::addAdaptor(QDBusAbstractAdaptor *adaptor)
+{
+ // find the interface name
+ const QMetaObject *mo = adaptor->metaObject();
+ int ciid = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
+ if (ciid != -1) {
+ QMetaClassInfo mci = mo->classInfo(ciid);
+ if (*mci.value()) {
+ // find out if this interface exists first
+ const char *interface = mci.value();
+ AdaptorMap::Iterator it = qLowerBound(adaptors.begin(), adaptors.end(),
+ QByteArray(interface));
+ if (it != adaptors.end() && qstrcmp(interface, it->interface) == 0) {
+ // exists. Replace it (though it's probably the same)
+ if (it->adaptor != adaptor) {
+ // reconnect the signals
+ disconnectAllSignals(it->adaptor);
+ connectAllSignals(adaptor);
+ }
+ it->adaptor = adaptor;
+ } else {
+ // create a new one
+ AdaptorData entry;
+ entry.interface = interface;
+ entry.adaptor = adaptor;
+ adaptors << entry;
+
+ // connect the adaptor's signals to our relaySlot slot
+ connectAllSignals(adaptor);
+ }
+ }
+ }
+}
+
+void QDBusAdaptorConnector::disconnectAllSignals(QObject *obj)
+{
+ QMetaObject::disconnect(obj, -1, this, metaObject()->methodOffset());
+}
+
+void QDBusAdaptorConnector::connectAllSignals(QObject *obj)
+{
+ QMetaObject::connect(obj, -1, this, metaObject()->methodOffset(), Qt::DirectConnection);
+}
+
+void QDBusAdaptorConnector::polish()
+{
+ if (!waitingForPolish)
+ return; // avoid working multiple times if multiple adaptors were added
+
+ waitingForPolish = false;
+ const QObjectList &objs = parent()->children();
+ QObjectList::ConstIterator it = objs.constBegin();
+ QObjectList::ConstIterator end = objs.constEnd();
+ for ( ; it != end; ++it) {
+ QDBusAbstractAdaptor *adaptor = qobject_cast<QDBusAbstractAdaptor *>(*it);
+ if (adaptor)
+ addAdaptor(adaptor);
+ }
+
+ // sort the adaptor list
+ qSort(adaptors);
+}
+
+void QDBusAdaptorConnector::relaySlot(void **argv)
+{
+ QObjectPrivate *d = static_cast<QObjectPrivate *>(d_ptr.data());
+ relay(d->currentSender->sender, d->currentSender->signal, argv);
+}
+
+void QDBusAdaptorConnector::relay(QObject *senderObj, int lastSignalIdx, void **argv)
+{
+ if (lastSignalIdx < QObject::staticMetaObject.methodCount())
+ // QObject signal (destroyed(QObject *)) -- ignore
+ return;
+
+ const QMetaObject *senderMetaObject = senderObj->metaObject();
+ QMetaMethod mm = senderMetaObject->method(lastSignalIdx);
+
+ QObject *realObject = senderObj;
+ if (qobject_cast<QDBusAbstractAdaptor *>(senderObj))
+ // it's an adaptor, so the real object is in fact its parent
+ realObject = realObject->parent();
+
+ // break down the parameter list
+ QList<int> types;
+ int inputCount = qDBusParametersForMethod(mm, types);
+ if (inputCount == -1)
+ // invalid signal signature
+ // qDBusParametersForMethod has already complained
+ return;
+ if (inputCount + 1 != types.count() ||
+ types.at(inputCount) == QDBusMetaTypeId::message) {
+ // invalid signal signature
+ // qDBusParametersForMethod has not yet complained about this one
+ qWarning("QDBusAbstractAdaptor: Cannot relay signal %s::%s",
+ senderMetaObject->className(), mm.signature());
+ return;
+ }
+
+ QVariantList args;
+ for (int i = 1; i < types.count(); ++i)
+ args << QVariant(types.at(i), argv[i]);
+
+ // now emit the signal with all the information
+ emit relaySignal(realObject, senderMetaObject, lastSignalIdx, args);
+}
+
+// our Meta Object
+// modify carefully: this has been hand-edited!
+// the relaySlot slot has local ID 0 (we use this when calling QMetaObject::connect)
+// it also gets called with the void** array
+
+static const uint qt_meta_data_QDBusAdaptorConnector[] = {
+ // content:
+ 1, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 3, 10, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+
+ // slots: signature, parameters, type, tag, flags
+ 106, 22, 22, 22, 0x0a,
+ 118, 22, 22, 22, 0x0a,
+
+ // signals: signature, parameters, type, tag, flags
+ 47, 23, 22, 22, 0x05,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_QDBusAdaptorConnector[] = {
+ "QDBusAdaptorConnector\0\0obj,metaobject,sid,args\0"
+ "relaySignal(QObject*,const QMetaObject*,int,QVariantList)\0\0relaySlot()\0"
+ "polish()\0"
+};
+
+const QMetaObject QDBusAdaptorConnector::staticMetaObject = {
+ { &QObject::staticMetaObject, qt_meta_stringdata_QDBusAdaptorConnector,
+ qt_meta_data_QDBusAdaptorConnector, 0 }
+};
+
+const QMetaObject *QDBusAdaptorConnector::metaObject() const
+{
+ return &staticMetaObject;
+}
+
+void *QDBusAdaptorConnector::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_QDBusAdaptorConnector))
+ return static_cast<void*>(const_cast<QDBusAdaptorConnector*>(this));
+ return QObject::qt_metacast(_clname);
+}
+
+int QDBusAdaptorConnector::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QObject::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ switch (_id) {
+ case 0: relaySlot(_a); break; // HAND EDIT: add the _a parameter
+ case 1: polish(); break;
+ case 2: relaySignal((*reinterpret_cast< QObject*(*)>(_a[1])),(*reinterpret_cast< const QMetaObject*(*)>(_a[2])),(*reinterpret_cast< int(*)>(_a[3])),(*reinterpret_cast< const QVariantList(*)>(_a[4]))); break;
+ }
+ _id -= 3;
+ }
+ return _id;
+}
+
+// SIGNAL 0
+void QDBusAdaptorConnector::relaySignal(QObject * _t1, const QMetaObject * _t2, int _t3, const QVariantList & _t4)
+{
+ void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)), const_cast<void*>(reinterpret_cast<const void*>(&_t2)), const_cast<void*>(reinterpret_cast<const void*>(&_t3)), const_cast<void*>(reinterpret_cast<const void*>(&_t4)) };
+ QMetaObject::activate(this, &staticMetaObject, 2, _a);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusabstractadaptor.h b/src/dbus/qdbusabstractadaptor.h
new file mode 100644
index 0000000000..a9241a1f61
--- /dev/null
+++ b/src/dbus/qdbusabstractadaptor.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSABSTRACTADAPTOR_H
+#define QDBUSABSTRACTADAPTOR_H
+
+#include <QtCore/qobject.h>
+#include <QtDBus/qdbusmacros.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(DBus)
+
+class QDBusAbstractAdaptorPrivate;
+class Q_DBUS_EXPORT QDBusAbstractAdaptor: public QObject
+{
+ Q_OBJECT
+protected:
+ QDBusAbstractAdaptor(QObject *parent);
+
+public:
+ ~QDBusAbstractAdaptor();
+
+protected:
+ void setAutoRelaySignals(bool enable);
+ bool autoRelaySignals() const;
+
+private:
+ Q_DECLARE_PRIVATE(QDBusAbstractAdaptor)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+
+#endif
diff --git a/src/dbus/qdbusabstractadaptor_p.h b/src/dbus/qdbusabstractadaptor_p.h
new file mode 100644
index 0000000000..678fc2ddf6
--- /dev/null
+++ b/src/dbus/qdbusabstractadaptor_p.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+//
+
+#ifndef QDBUSABSTRACTADAPTORPRIVATE_H
+#define QDBUSABSTRACTADAPTORPRIVATE_H
+
+#include <qdbusabstractadaptor.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qreadwritelock.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qvector.h>
+#include "private/qobject_p.h"
+
+#define QCLASSINFO_DBUS_INTERFACE "D-Bus Interface"
+#define QCLASSINFO_DBUS_INTROSPECTION "D-Bus Introspection"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+class QDBusAbstractAdaptor;
+class QDBusAdaptorConnector;
+class QDBusAdaptorManager;
+class QDBusConnectionPrivate;
+
+class QDBusAbstractAdaptorPrivate: public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDBusAbstractAdaptor)
+public:
+ QDBusAbstractAdaptorPrivate() : autoRelaySignals(false) {}
+ QString xml;
+ bool autoRelaySignals;
+
+ static QString retrieveIntrospectionXml(QDBusAbstractAdaptor *adaptor);
+ static void saveIntrospectionXml(QDBusAbstractAdaptor *adaptor, const QString &xml);
+};
+
+class QDBusAdaptorConnector: public QObject
+{
+ Q_OBJECT_FAKE
+
+public: // typedefs
+ struct AdaptorData
+ {
+ const char *interface;
+ QDBusAbstractAdaptor *adaptor;
+
+ inline bool operator<(const AdaptorData &other) const
+ { return QByteArray(interface) < other.interface; }
+ inline bool operator<(const QString &other) const
+ { return QLatin1String(interface) < other; }
+ inline bool operator<(const QByteArray &other) const
+ { return interface < other; }
+ };
+ typedef QVector<AdaptorData> AdaptorMap;
+
+public: // methods
+ explicit QDBusAdaptorConnector(QObject *parent);
+ ~QDBusAdaptorConnector();
+
+ void addAdaptor(QDBusAbstractAdaptor *adaptor);
+ void connectAllSignals(QObject *object);
+ void disconnectAllSignals(QObject *object);
+ void relay(QObject *sender, int id, void **);
+
+//public slots:
+ void relaySlot(void **);
+ void polish();
+
+protected:
+//signals:
+ void relaySignal(QObject *obj, const QMetaObject *metaObject, int sid, const QVariantList &args);
+
+public: // member variables
+ AdaptorMap adaptors;
+ bool waitingForPolish : 1;
+};
+
+extern QDBusAdaptorConnector *qDBusFindAdaptorConnector(QObject *object);
+extern QDBusAdaptorConnector *qDBusCreateAdaptorConnector(QObject *object);
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
+#endif // QDBUSABSTRACTADAPTORPRIVATE_H
diff --git a/src/dbus/qdbusabstractinterface.cpp b/src/dbus/qdbusabstractinterface.cpp
new file mode 100644
index 0000000000..9e82c09ed0
--- /dev/null
+++ b/src/dbus/qdbusabstractinterface.cpp
@@ -0,0 +1,776 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusabstractinterface.h"
+#include "qdbusabstractinterface_p.h"
+
+#include <qthread.h>
+
+#include "qdbusargument.h"
+#include "qdbuspendingcall.h"
+#include "qdbusmessage_p.h"
+#include "qdbusmetaobject_p.h"
+#include "qdbusmetatype_p.h"
+#include "qdbusutil_p.h"
+
+#include <qdebug.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+static QDBusError checkIfValid(const QString &service, const QString &path,
+ const QString &interface, bool isDynamic, bool isPeer)
+{
+ // We should be throwing exceptions here... oh well
+ QDBusError error;
+
+ // dynamic interfaces (QDBusInterface) can have empty interfaces, but not service and object paths
+ // non-dynamic is the opposite: service and object paths can be empty, but not the interface
+ if (!isDynamic) {
+ // use assertion here because this should never happen, at all
+ Q_ASSERT_X(!interface.isEmpty(), "QDBusAbstractInterface", "Interface name cannot be empty");
+ }
+ if (!QDBusUtil::checkBusName(service, (isDynamic && !isPeer) ? QDBusUtil::EmptyNotAllowed : QDBusUtil::EmptyAllowed, &error))
+ return error;
+ if (!QDBusUtil::checkObjectPath(path, isDynamic ? QDBusUtil::EmptyNotAllowed : QDBusUtil::EmptyAllowed, &error))
+ return error;
+ if (!QDBusUtil::checkInterfaceName(interface, QDBusUtil::EmptyAllowed, &error))
+ return error;
+
+ // no error
+ return QDBusError();
+}
+
+QDBusAbstractInterfacePrivate::QDBusAbstractInterfacePrivate(const QString &serv,
+ const QString &p,
+ const QString &iface,
+ const QDBusConnection& con,
+ bool isDynamic)
+ : connection(con), service(serv), path(p), interface(iface),
+ lastError(checkIfValid(serv, p, iface, isDynamic, (connectionPrivate() &&
+ connectionPrivate()->mode == QDBusConnectionPrivate::PeerMode))),
+ isValid(!lastError.isValid())
+{
+ if (!isValid)
+ return;
+
+ if (!connection.isConnected()) {
+ lastError = QDBusError(QDBusError::Disconnected,
+ QLatin1String("Not connected to D-Bus server"));
+ } else if (!service.isEmpty()) {
+ currentOwner = connectionPrivate()->getNameOwner(service); // verify the name owner
+ if (currentOwner.isEmpty()) {
+ lastError = connectionPrivate()->lastError;
+ }
+ }
+}
+
+bool QDBusAbstractInterfacePrivate::canMakeCalls() const
+{
+ // recheck only if we have a wildcard (i.e. empty) service or path
+ // if any are empty, set the error message according to QDBusUtil
+ if (service.isEmpty() && connectionPrivate()->mode != QDBusConnectionPrivate::PeerMode)
+ return QDBusUtil::checkBusName(service, QDBusUtil::EmptyNotAllowed, &lastError);
+ if (path.isEmpty())
+ return QDBusUtil::checkObjectPath(path, QDBusUtil::EmptyNotAllowed, &lastError);
+ return true;
+}
+
+void QDBusAbstractInterfacePrivate::property(const QMetaProperty &mp, QVariant &where) const
+{
+ if (!isValid || !canMakeCalls()) { // can't make calls
+ where.clear();
+ return;
+ }
+
+ // is this metatype registered?
+ const char *expectedSignature = "";
+ if (mp.type() != 0xff) {
+ expectedSignature = QDBusMetaType::typeToSignature(where.userType());
+ if (expectedSignature == 0) {
+ qWarning("QDBusAbstractInterface: type %s must be registered with QtDBus before it can be "
+ "used to read property %s.%s",
+ mp.typeName(), qPrintable(interface), mp.name());
+ lastError = QDBusError(QDBusError::Failed,
+ QString::fromLatin1("Unregistered type %1 cannot be handled")
+ .arg(QLatin1String(mp.typeName())));
+ where.clear();
+ return;
+ }
+ }
+
+ // try to read this property
+ QDBusMessage msg = QDBusMessage::createMethodCall(service, path,
+ QLatin1String(DBUS_INTERFACE_PROPERTIES),
+ QLatin1String("Get"));
+ QDBusMessagePrivate::setParametersValidated(msg, true);
+ msg << interface << QString::fromUtf8(mp.name());
+ QDBusMessage reply = connection.call(msg, QDBus::Block);
+
+ if (reply.type() != QDBusMessage::ReplyMessage) {
+ lastError = reply;
+ where.clear();
+ return;
+ }
+ if (reply.signature() != QLatin1String("v")) {
+ QString errmsg = QLatin1String("Invalid signature `%1' in return from call to "
+ DBUS_INTERFACE_PROPERTIES);
+ lastError = QDBusError(QDBusError::InvalidSignature, errmsg.arg(reply.signature()));
+ where.clear();
+ return;
+ }
+
+ QByteArray foundSignature;
+ const char *foundType = 0;
+ QVariant value = qvariant_cast<QDBusVariant>(reply.arguments().at(0)).variant();
+
+ if (value.userType() == where.userType() || mp.type() == 0xff
+ || (expectedSignature[0] == 'v' && expectedSignature[1] == '\0')) {
+ // simple match
+ where = value;
+ return;
+ }
+
+ if (value.userType() == qMetaTypeId<QDBusArgument>()) {
+ QDBusArgument arg = qvariant_cast<QDBusArgument>(value);
+
+ foundType = "user type";
+ foundSignature = arg.currentSignature().toLatin1();
+ if (foundSignature == expectedSignature) {
+ // signatures match, we can demarshall
+ QDBusMetaType::demarshall(arg, where.userType(), where.data());
+ return;
+ }
+ } else {
+ foundType = value.typeName();
+ foundSignature = QDBusMetaType::typeToSignature(value.userType());
+ }
+
+ // there was an error...
+ QString errmsg = QLatin1String("Unexpected `%1' (%2) when retrieving property `%3.%4' "
+ "(expected type `%5' (%6))");
+ lastError = QDBusError(QDBusError::InvalidSignature,
+ errmsg.arg(QString::fromLatin1(foundType),
+ QString::fromLatin1(foundSignature),
+ interface,
+ QString::fromUtf8(mp.name()),
+ QString::fromLatin1(mp.typeName()),
+ QString::fromLatin1(expectedSignature)));
+ where.clear();
+ return;
+}
+
+bool QDBusAbstractInterfacePrivate::setProperty(const QMetaProperty &mp, const QVariant &value)
+{
+ if (!isValid || !canMakeCalls()) // can't make calls
+ return false;
+
+ // send the value
+ QDBusMessage msg = QDBusMessage::createMethodCall(service, path,
+ QLatin1String(DBUS_INTERFACE_PROPERTIES),
+ QLatin1String("Set"));
+ QDBusMessagePrivate::setParametersValidated(msg, true);
+ msg << interface << QString::fromUtf8(mp.name()) << QVariant::fromValue(QDBusVariant(value));
+ QDBusMessage reply = connection.call(msg, QDBus::Block);
+
+ if (reply.type() != QDBusMessage::ReplyMessage) {
+ lastError = reply;
+ return false;
+ }
+ return true;
+}
+
+void QDBusAbstractInterfacePrivate::_q_serviceOwnerChanged(const QString &name,
+ const QString &oldOwner,
+ const QString &newOwner)
+{
+ Q_UNUSED(oldOwner);
+ //qDebug() << "QDBusAbstractInterfacePrivate serviceOwnerChanged" << name << oldOwner << newOwner;
+ if (name == service) {
+ currentOwner = newOwner;
+ }
+}
+
+QDBusAbstractInterfaceBase::QDBusAbstractInterfaceBase(QDBusAbstractInterfacePrivate &d, QObject *parent)
+ : QObject(d, parent)
+{
+}
+
+int QDBusAbstractInterfaceBase::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ int saved_id = _id;
+ _id = QObject::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+
+ if (_c == QMetaObject::ReadProperty || _c == QMetaObject::WriteProperty) {
+ QMetaProperty mp = metaObject()->property(saved_id);
+ int &status = *reinterpret_cast<int *>(_a[2]);
+ QVariant &variant = *reinterpret_cast<QVariant *>(_a[1]);
+
+ if (_c == QMetaObject::WriteProperty) {
+ status = d_func()->setProperty(mp, variant) ? 1 : 0;
+ } else {
+ d_func()->property(mp, variant);
+ status = variant.isValid() ? 1 : 0;
+ }
+ _id = -1;
+ }
+ return _id;
+}
+
+/*!
+ \class QDBusAbstractInterface
+ \inmodule QtDBus
+ \since 4.2
+
+ \brief The QDBusAbstractInterface class is the base class for all D-Bus interfaces in the QtDBus binding, allowing access to remote interfaces
+
+ Generated-code classes also derive from QDBusAbstractInterface,
+ all methods described here are also valid for generated-code
+ classes. In addition to those described here, generated-code
+ classes provide member functions for the remote methods, which
+ allow for compile-time checking of the correct parameters and
+ return values, as well as property type-matching and signal
+ parameter-matching.
+
+ \sa {qdbusxml2cpp.html}{The QDBus compiler}, QDBusInterface
+*/
+
+/*!
+ \internal
+ This is the constructor called from QDBusInterface::QDBusInterface.
+*/
+QDBusAbstractInterface::QDBusAbstractInterface(QDBusAbstractInterfacePrivate &d, QObject *parent)
+ : QDBusAbstractInterfaceBase(d, parent)
+{
+ // keep track of the service owner
+ if (d.isValid &&
+ d.connection.isConnected()
+ && !d.service.isEmpty()
+ && !d.service.startsWith(QLatin1Char(':')))
+ d_func()->connection.connect(QLatin1String(DBUS_SERVICE_DBUS), // service
+ QString(), // path
+ QLatin1String(DBUS_INTERFACE_DBUS), // interface
+ QLatin1String("NameOwnerChanged"),
+ QStringList() << d.service,
+ QString(), // signature
+ this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
+}
+
+/*!
+ \internal
+ This is the constructor called from static classes derived from
+ QDBusAbstractInterface (i.e., those generated by dbusxml2cpp).
+*/
+QDBusAbstractInterface::QDBusAbstractInterface(const QString &service, const QString &path,
+ const char *interface, const QDBusConnection &con,
+ QObject *parent)
+ : QDBusAbstractInterfaceBase(*new QDBusAbstractInterfacePrivate(service, path, QString::fromLatin1(interface),
+ con, false), parent)
+{
+ // keep track of the service owner
+ if (d_func()->isValid &&
+ d_func()->connection.isConnected()
+ && !service.isEmpty()
+ && !service.startsWith(QLatin1Char(':')))
+ d_func()->connection.connect(QLatin1String(DBUS_SERVICE_DBUS), // service
+ QString(), // path
+ QLatin1String(DBUS_INTERFACE_DBUS), // interface
+ QLatin1String("NameOwnerChanged"),
+ QStringList() << service,
+ QString(), //signature
+ this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
+}
+
+/*!
+ Releases this object's resources.
+*/
+QDBusAbstractInterface::~QDBusAbstractInterface()
+{
+}
+
+/*!
+ Returns true if this is a valid reference to a remote object. It returns false if
+ there was an error during the creation of this interface (for instance, if the remote
+ application does not exist).
+
+ Note: when dealing with remote objects, it is not always possible to determine if it
+ exists when creating a QDBusInterface.
+*/
+bool QDBusAbstractInterface::isValid() const
+{
+ return !d_func()->currentOwner.isEmpty();
+}
+
+/*!
+ Returns the connection this interface is assocated with.
+*/
+QDBusConnection QDBusAbstractInterface::connection() const
+{
+ return d_func()->connection;
+}
+
+/*!
+ Returns the name of the service this interface is associated with.
+*/
+QString QDBusAbstractInterface::service() const
+{
+ return d_func()->service;
+}
+
+/*!
+ Returns the object path that this interface is associated with.
+*/
+QString QDBusAbstractInterface::path() const
+{
+ return d_func()->path;
+}
+
+/*!
+ Returns the name of this interface.
+*/
+QString QDBusAbstractInterface::interface() const
+{
+ return d_func()->interface;
+}
+
+/*!
+ Returns the error the last operation produced, or an invalid error if the last operation did not
+ produce an error.
+*/
+QDBusError QDBusAbstractInterface::lastError() const
+{
+ return d_func()->lastError;
+}
+
+/*!
+ Places a call to the remote method specified by \a method on this interface, using \a args as
+ arguments. This function returns the message that was received as a reply, which can be a normal
+ QDBusMessage::ReplyMessage (indicating success) or QDBusMessage::ErrorMessage (if the call
+ failed). The \a mode parameter specifies how this call should be placed.
+
+ If the call succeeds, lastError() will be cleared; otherwise, it will contain the error this
+ call produced.
+
+ Normally, you should place calls using call().
+
+ \warning If you use \c UseEventLoop, your code must be prepared to deal with any reentrancy:
+ other method calls and signals may be delivered before this function returns, as well
+ as other Qt queued signals and events.
+
+ \threadsafe
+*/
+QDBusMessage QDBusAbstractInterface::callWithArgumentList(QDBus::CallMode mode,
+ const QString& method,
+ const QList<QVariant>& args)
+{
+ Q_D(QDBusAbstractInterface);
+
+ if (!d->isValid || !d->canMakeCalls())
+ return QDBusMessage::createError(d->lastError);
+
+ QString m = method;
+ // split out the signature from the method
+ int pos = method.indexOf(QLatin1Char('.'));
+ if (pos != -1)
+ m.truncate(pos);
+
+ if (mode == QDBus::AutoDetect) {
+ // determine if this a sync or async call
+ mode = QDBus::Block;
+ const QMetaObject *mo = metaObject();
+ QByteArray match = m.toLatin1() + '(';
+
+ for (int i = staticMetaObject.methodCount(); i < mo->methodCount(); ++i) {
+ QMetaMethod mm = mo->method(i);
+ if (QByteArray(mm.signature()).startsWith(match)) {
+ // found a method with the same name as what we're looking for
+ // hopefully, nobody is overloading asynchronous and synchronous methods with
+ // the same name
+
+ QList<QByteArray> tags = QByteArray(mm.tag()).split(' ');
+ if (tags.contains("Q_NOREPLY"))
+ mode = QDBus::NoBlock;
+
+ break;
+ }
+ }
+ }
+
+// qDebug() << "QDBusAbstractInterface" << "Service" << service() << "Path:" << path();
+ QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), interface(), m);
+ QDBusMessagePrivate::setParametersValidated(msg, true);
+ msg.setArguments(args);
+
+ QDBusMessage reply = d->connection.call(msg, mode);
+ if (thread() == QThread::currentThread())
+ d->lastError = reply; // will clear if reply isn't an error
+
+ // ensure that there is at least one element
+ if (reply.arguments().isEmpty())
+ reply << QVariant();
+
+ return reply;
+}
+
+/*!
+ \since 4.5
+ Places a call to the remote method specified by \a method on this
+ interface, using \a args as arguments. This function returns a
+ QDBusPendingCall object that can be used to track the status of the
+ reply and access its contents once it has arrived.
+
+ Normally, you should place calls using asyncCall().
+
+ \threadsafe
+*/
+QDBusPendingCall QDBusAbstractInterface::asyncCallWithArgumentList(const QString& method,
+ const QList<QVariant>& args)
+{
+ Q_D(QDBusAbstractInterface);
+
+ if (!d->isValid || !d->canMakeCalls())
+ return QDBusPendingCall::fromError(d->lastError);
+
+ QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), interface(), method);
+ QDBusMessagePrivate::setParametersValidated(msg, true);
+ msg.setArguments(args);
+ return d->connection.asyncCall(msg);
+}
+
+/*!
+ Places a call to the remote method specified by \a method
+ on this interface, using \a args as arguments. This function
+ returns immediately after queueing the call. The reply from
+ the remote function is delivered to the \a returnMethod on
+ object \a receiver. If an error occurs, the \a errorMethod
+ on object \a receiver is called instead.
+
+ This function returns true if the queueing succeeds. It does
+ not indicate that the executed call succeeded. If it fails,
+ the \a errorMethod is called. If the queueing failed, this
+ function returns false and no slot will be called.
+
+ The \a returnMethod must have as its parameters the types returned
+ by the function call. Optionally, it may have a QDBusMessage
+ parameter as its last or only parameter. The \a errorMethod must
+ have a QDBusError as its only parameter.
+
+ \since 4.3
+ \sa QDBusError, QDBusMessage
+ */
+bool QDBusAbstractInterface::callWithCallback(const QString &method,
+ const QList<QVariant> &args,
+ QObject *receiver,
+ const char *returnMethod,
+ const char *errorMethod)
+{
+ Q_D(QDBusAbstractInterface);
+
+ if (!d->isValid || !d->canMakeCalls())
+ return false;
+
+ QDBusMessage msg = QDBusMessage::createMethodCall(service(),
+ path(),
+ interface(),
+ method);
+ QDBusMessagePrivate::setParametersValidated(msg, true);
+ msg.setArguments(args);
+
+ d->lastError = 0;
+ return d->connection.callWithCallback(msg,
+ receiver,
+ returnMethod,
+ errorMethod);
+}
+
+/*!
+ \overload
+
+ This function is deprecated. Please use the overloaded version.
+
+ Places a call to the remote method specified by \a method
+ on this interface, using \a args as arguments. This function
+ returns immediately after queueing the call. The reply from
+ the remote function or any errors emitted by it are delivered
+ to the \a slot slot on object \a receiver.
+
+ This function returns true if the queueing succeeded: it does
+ not indicate that the call succeeded. If it failed, the slot
+ will be called with an error message. lastError() will not be
+ set under those circumstances.
+
+ \sa QDBusError, QDBusMessage
+*/
+bool QDBusAbstractInterface::callWithCallback(const QString &method,
+ const QList<QVariant> &args,
+ QObject *receiver,
+ const char *slot)
+{
+ return callWithCallback(method, args, receiver, slot, 0);
+}
+
+/*!
+ \internal
+ Catch signal connections.
+*/
+void QDBusAbstractInterface::connectNotify(const char *signal)
+{
+ // someone connecting to one of our signals
+ Q_D(QDBusAbstractInterface);
+ if (!d->isValid)
+ return;
+
+ // we end up recursing here, so optimize away
+ if (qstrcmp(signal + 1, "destroyed(QObject*)") == 0)
+ return;
+
+ QDBusConnectionPrivate *conn = d->connectionPrivate();
+ if (conn) {
+ conn->connectRelay(d->service, d->path, d->interface,
+ this, signal);
+ }
+}
+
+/*!
+ \internal
+ Catch signal disconnections.
+*/
+void QDBusAbstractInterface::disconnectNotify(const char *signal)
+{
+ // someone disconnecting from one of our signals
+ Q_D(QDBusAbstractInterface);
+ if (!d->isValid)
+ return;
+
+ QDBusConnectionPrivate *conn = d->connectionPrivate();
+ if (conn)
+ conn->disconnectRelay(d->service, d->path, d->interface,
+ this, signal);
+}
+
+/*!
+ \internal
+ Get the value of the property \a propname.
+*/
+QVariant QDBusAbstractInterface::internalPropGet(const char *propname) const
+{
+ // assume this property exists and is readable
+ // we're only called from generated code anyways
+
+ return property(propname);
+}
+
+/*!
+ \internal
+ Set the value of the property \a propname to \a value.
+*/
+void QDBusAbstractInterface::internalPropSet(const char *propname, const QVariant &value)
+{
+ setProperty(propname, value);
+}
+
+/*!
+ Calls the method \a method on this interface and passes the parameters to this function to the
+ method.
+
+ The parameters to \c call are passed on to the remote function via D-Bus as input
+ arguments. Output arguments are returned in the QDBusMessage reply. If the reply is an error
+ reply, lastError() will also be set to the contents of the error message.
+
+ This function can be used with up to 8 parameters, passed in arguments \a arg1, \a arg2,
+ \a arg3, \a arg4, \a arg5, \a arg6, \a arg7 and \a arg8. If you need more than 8
+ parameters or if you have a variable number of parameters to be passed, use
+ callWithArgumentList().
+
+ It can be used the following way:
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbusabstractinterface.cpp 0
+
+ This example illustrates function calling with 0, 1 and 2 parameters and illustrates different
+ parameter types passed in each (the first call to \c "ProcessWorkUnicode" will contain one
+ Unicode string, the second call to \c "ProcessWork" will contain one string and one byte array).
+*/
+QDBusMessage QDBusAbstractInterface::call(const QString &method, const QVariant &arg1,
+ const QVariant &arg2,
+ const QVariant &arg3,
+ const QVariant &arg4,
+ const QVariant &arg5,
+ const QVariant &arg6,
+ const QVariant &arg7,
+ const QVariant &arg8)
+{
+ return call(QDBus::AutoDetect, method, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+}
+
+/*!
+ \overload
+
+ Calls the method \a method on this interface and passes the
+ parameters to this function to the method. If \a mode is \c
+ NoWaitForReply, then this function will return immediately after
+ placing the call, without waiting for a reply from the remote
+ method. Otherwise, \a mode indicates whether this function should
+ activate the Qt Event Loop while waiting for the reply to arrive.
+
+ This function can be used with up to 8 parameters, passed in arguments \a arg1, \a arg2,
+ \a arg3, \a arg4, \a arg5, \a arg6, \a arg7 and \a arg8. If you need more than 8
+ parameters or if you have a variable number of parameters to be passed, use
+ callWithArgumentList().
+
+ If this function reenters the Qt event loop in order to wait for the
+ reply, it will exclude user input. During the wait, it may deliver
+ signals and other method calls to your application. Therefore, it
+ must be prepared to handle a reentrancy whenever a call is placed
+ with call().
+*/
+QDBusMessage QDBusAbstractInterface::call(QDBus::CallMode mode, const QString &method,
+ const QVariant &arg1,
+ const QVariant &arg2,
+ const QVariant &arg3,
+ const QVariant &arg4,
+ const QVariant &arg5,
+ const QVariant &arg6,
+ const QVariant &arg7,
+ const QVariant &arg8)
+{
+ QList<QVariant> argList;
+ int count = 0 + arg1.isValid() + arg2.isValid() + arg3.isValid() + arg4.isValid() +
+ arg5.isValid() + arg6.isValid() + arg7.isValid() + arg8.isValid();
+
+ switch (count) {
+ case 8:
+ argList.prepend(arg8);
+ case 7:
+ argList.prepend(arg7);
+ case 6:
+ argList.prepend(arg6);
+ case 5:
+ argList.prepend(arg5);
+ case 4:
+ argList.prepend(arg4);
+ case 3:
+ argList.prepend(arg3);
+ case 2:
+ argList.prepend(arg2);
+ case 1:
+ argList.prepend(arg1);
+ }
+
+ return callWithArgumentList(mode, method, argList);
+}
+
+
+/*!
+ \since 4.5
+ Calls the method \a method on this interface and passes the parameters to this function to the
+ method.
+
+ The parameters to \c call are passed on to the remote function via D-Bus as input
+ arguments. The returned QDBusPendingCall object can be used to find out information about
+ the reply.
+
+ This function can be used with up to 8 parameters, passed in arguments \a arg1, \a arg2,
+ \a arg3, \a arg4, \a arg5, \a arg6, \a arg7 and \a arg8. If you need more than 8
+ parameters or if you have a variable number of parameters to be passed, use
+ asyncCallWithArgumentList().
+
+ It can be used the following way:
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbusabstractinterface.cpp 1
+
+ This example illustrates function calling with 0, 1 and 2 parameters and illustrates different
+ parameter types passed in each (the first call to \c "ProcessWorkUnicode" will contain one
+ Unicode string, the second call to \c "ProcessWork" will contain one string and one byte array).
+*/
+QDBusPendingCall QDBusAbstractInterface::asyncCall(const QString &method, const QVariant &arg1,
+ const QVariant &arg2,
+ const QVariant &arg3,
+ const QVariant &arg4,
+ const QVariant &arg5,
+ const QVariant &arg6,
+ const QVariant &arg7,
+ const QVariant &arg8)
+{
+ QList<QVariant> argList;
+ int count = 0 + arg1.isValid() + arg2.isValid() + arg3.isValid() + arg4.isValid() +
+ arg5.isValid() + arg6.isValid() + arg7.isValid() + arg8.isValid();
+
+ switch (count) {
+ case 8:
+ argList.prepend(arg8);
+ case 7:
+ argList.prepend(arg7);
+ case 6:
+ argList.prepend(arg6);
+ case 5:
+ argList.prepend(arg5);
+ case 4:
+ argList.prepend(arg4);
+ case 3:
+ argList.prepend(arg3);
+ case 2:
+ argList.prepend(arg2);
+ case 1:
+ argList.prepend(arg1);
+ }
+
+ return asyncCallWithArgumentList(method, argList);
+}
+
+/*!
+ \internal
+*/
+QDBusMessage QDBusAbstractInterface::internalConstCall(QDBus::CallMode mode,
+ const QString &method,
+ const QList<QVariant> &args) const
+{
+ // ### move the code here, and make the other functions call this
+ return const_cast<QDBusAbstractInterface*>(this)->callWithArgumentList(mode, method, args);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
+
+#include "moc_qdbusabstractinterface.cpp"
diff --git a/src/dbus/qdbusabstractinterface.h b/src/dbus/qdbusabstractinterface.h
new file mode 100644
index 0000000000..ec7cd8ed89
--- /dev/null
+++ b/src/dbus/qdbusabstractinterface.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSABSTRACTINTERFACE_H
+#define QDBUSABSTRACTINTERFACE_H
+
+#include <QtCore/qstring.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qobject.h>
+
+#include <QtDBus/qdbusmessage.h>
+#include <QtDBus/qdbusextratypes.h>
+#include <QtDBus/qdbusconnection.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(DBus)
+
+class QDBusError;
+class QDBusPendingCall;
+
+class QDBusAbstractInterfacePrivate;
+
+class Q_DBUS_EXPORT QDBusAbstractInterfaceBase: public QObject
+{
+public:
+ int qt_metacall(QMetaObject::Call, int, void**);
+protected:
+ QDBusAbstractInterfaceBase(QDBusAbstractInterfacePrivate &dd, QObject *parent);
+private:
+ Q_DECLARE_PRIVATE(QDBusAbstractInterface)
+};
+
+class Q_DBUS_EXPORT QDBusAbstractInterface:
+#ifdef Q_QDOC
+ public QObject
+#else
+ public QDBusAbstractInterfaceBase
+#endif
+{
+ Q_OBJECT
+
+public:
+ virtual ~QDBusAbstractInterface();
+ bool isValid() const;
+
+ QDBusConnection connection() const;
+
+ QString service() const;
+ QString path() const;
+ QString interface() const;
+
+ QDBusError lastError() const;
+
+ QDBusMessage call(const QString &method,
+ const QVariant &arg1 = QVariant(),
+ const QVariant &arg2 = QVariant(),
+ const QVariant &arg3 = QVariant(),
+ const QVariant &arg4 = QVariant(),
+ const QVariant &arg5 = QVariant(),
+ const QVariant &arg6 = QVariant(),
+ const QVariant &arg7 = QVariant(),
+ const QVariant &arg8 = QVariant());
+
+ QDBusMessage call(QDBus::CallMode mode,
+ const QString &method,
+ const QVariant &arg1 = QVariant(),
+ const QVariant &arg2 = QVariant(),
+ const QVariant &arg3 = QVariant(),
+ const QVariant &arg4 = QVariant(),
+ const QVariant &arg5 = QVariant(),
+ const QVariant &arg6 = QVariant(),
+ const QVariant &arg7 = QVariant(),
+ const QVariant &arg8 = QVariant());
+
+ QDBusMessage callWithArgumentList(QDBus::CallMode mode,
+ const QString &method,
+ const QList<QVariant> &args);
+
+ bool callWithCallback(const QString &method,
+ const QList<QVariant> &args,
+ QObject *receiver, const char *member, const char *errorSlot);
+ bool callWithCallback(const QString &method,
+ const QList<QVariant> &args,
+ QObject *receiver, const char *member);
+
+ QDBusPendingCall asyncCall(const QString &method,
+ const QVariant &arg1 = QVariant(),
+ const QVariant &arg2 = QVariant(),
+ const QVariant &arg3 = QVariant(),
+ const QVariant &arg4 = QVariant(),
+ const QVariant &arg5 = QVariant(),
+ const QVariant &arg6 = QVariant(),
+ const QVariant &arg7 = QVariant(),
+ const QVariant &arg8 = QVariant());
+ QDBusPendingCall asyncCallWithArgumentList(const QString &method,
+ const QList<QVariant> &args);
+
+protected:
+ QDBusAbstractInterface(const QString &service, const QString &path, const char *interface,
+ const QDBusConnection &connection, QObject *parent);
+ QDBusAbstractInterface(QDBusAbstractInterfacePrivate &, QObject *parent);
+
+ void connectNotify(const char *signal);
+ void disconnectNotify(const char *signal);
+ QVariant internalPropGet(const char *propname) const;
+ void internalPropSet(const char *propname, const QVariant &value);
+ QDBusMessage internalConstCall(QDBus::CallMode mode,
+ const QString &method,
+ const QList<QVariant> &args = QList<QVariant>()) const;
+
+private:
+ Q_DECLARE_PRIVATE(QDBusAbstractInterface)
+ Q_PRIVATE_SLOT(d_func(), void _q_serviceOwnerChanged(QString,QString,QString))
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusabstractinterface_p.h b/src/dbus/qdbusabstractinterface_p.h
new file mode 100644
index 0000000000..fd6c69a51a
--- /dev/null
+++ b/src/dbus/qdbusabstractinterface_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+//
+
+#ifndef QDBUSABSTRACTINTERFACEPRIVATE_H
+#define QDBUSABSTRACTINTERFACEPRIVATE_H
+
+#include <qdbusabstractinterface.h>
+#include <qdbusconnection.h>
+#include <qdbuserror.h>
+#include "qdbusconnection_p.h"
+#include "private/qobject_p.h"
+
+#define ANNOTATION_NO_WAIT "org.freedesktop.DBus.Method.NoReply"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+class QDBusAbstractInterfacePrivate : public QObjectPrivate
+{
+public:
+ Q_DECLARE_PUBLIC(QDBusAbstractInterface)
+
+ mutable QDBusConnection connection; // mutable because we want to make calls from const functions
+ QString service;
+ QString currentOwner;
+ QString path;
+ QString interface;
+ mutable QDBusError lastError;
+
+ // this is set during creation and never changed
+ // it can't be const because QDBusInterfacePrivate has one more check
+ bool isValid;
+
+ QDBusAbstractInterfacePrivate(const QString &serv, const QString &p,
+ const QString &iface, const QDBusConnection& con, bool dynamic);
+ virtual ~QDBusAbstractInterfacePrivate() { }
+ bool canMakeCalls() const;
+
+ // these functions do not check if the property is valid
+ void property(const QMetaProperty &mp, QVariant &where) const;
+ bool setProperty(const QMetaProperty &mp, const QVariant &value);
+
+ // return conn's d pointer
+ inline QDBusConnectionPrivate *connectionPrivate() const
+ { return QDBusConnectionPrivate::d(connection); }
+
+ void _q_serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusargument.cpp b/src/dbus/qdbusargument.cpp
new file mode 100644
index 0000000000..806b7fec16
--- /dev/null
+++ b/src/dbus/qdbusargument.cpp
@@ -0,0 +1,1362 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusargument.h"
+
+#include <qatomic.h>
+#include <qbytearray.h>
+#include <qlist.h>
+#include <qmap.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qvariant.h>
+#include <qdatetime.h>
+#include <qrect.h>
+#include <qline.h>
+
+#include "qdbusargument_p.h"
+#include "qdbusmetatype_p.h"
+#include "qdbusutil_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+QDBusArgumentPrivate::~QDBusArgumentPrivate()
+{
+ if (message)
+ q_dbus_message_unref(message);
+}
+
+QByteArray QDBusArgumentPrivate::createSignature(int id)
+{
+ if (!qdbus_loadLibDBus())
+ return "";
+
+ QByteArray signature;
+ QDBusMarshaller *marshaller = new QDBusMarshaller(0);
+ marshaller->ba = &signature;
+
+ // run it
+ void *null = 0;
+ QVariant v(id, null);
+ QDBusArgument arg(marshaller);
+ QDBusMetaType::marshall(arg, v.userType(), v.constData());
+ arg.d = 0;
+
+ // delete it
+ bool ok = marshaller->ok;
+ delete marshaller;
+
+ if (signature.isEmpty() || !ok || !QDBusUtil::isValidSingleSignature(QString::fromLatin1(signature))) {
+ qWarning("QDBusMarshaller: type `%s' produces invalid D-BUS signature `%s' "
+ "(Did you forget to call beginStructure() ?)",
+ QVariant::typeToName( QVariant::Type(id) ),
+ signature.isEmpty() ? "<empty>" : signature.constData());
+ return "";
+ } else if ((signature.at(0) != DBUS_TYPE_ARRAY && signature.at(0) != DBUS_STRUCT_BEGIN_CHAR) ||
+ (signature.at(0) == DBUS_TYPE_ARRAY && (signature.at(1) == DBUS_TYPE_BYTE ||
+ signature.at(1) == DBUS_TYPE_STRING))) {
+ qWarning("QDBusMarshaller: type `%s' attempts to redefine basic D-BUS type '%s' (%s) "
+ "(Did you forget to call beginStructure() ?)",
+ QVariant::typeToName( QVariant::Type(id) ),
+ signature.constData(),
+ QVariant::typeToName( QVariant::Type(QDBusMetaType::signatureToType(signature))) );
+ return "";
+ }
+ return signature;
+}
+
+bool QDBusArgumentPrivate::checkWrite(QDBusArgumentPrivate *&d)
+{
+ if (!d)
+ return false;
+ if (d->direction == Marshalling) {
+ if (!d->marshaller()->ok)
+ return false;
+
+ if (d->message && d->ref != 1) {
+ QDBusMarshaller *dd = new QDBusMarshaller(d->capabilities);
+ dd->message = q_dbus_message_copy(d->message);
+ q_dbus_message_iter_init_append(dd->message, &dd->iterator);
+
+ if (!d->ref.deref())
+ delete d;
+ d = dd;
+ }
+ return true;
+ }
+
+#ifdef QT_DEBUG
+ qFatal("QDBusArgument: write from a read-only object");
+#else
+ qWarning("QDBusArgument: write from a read-only object");
+#endif
+ return false;
+}
+
+bool QDBusArgumentPrivate::checkRead(QDBusArgumentPrivate *d)
+{
+ if (!d)
+ return false;
+ if (d->direction == Demarshalling)
+ return true;
+
+#ifdef QT_DEBUG
+ qFatal("QDBusArgument: read from a write-only object");
+#else
+ qWarning("QDBusArgument: read from a write-only object");
+#endif
+
+ return false;
+}
+
+bool QDBusArgumentPrivate::checkReadAndDetach(QDBusArgumentPrivate *&d)
+{
+ if (!checkRead(d))
+ return false; // don't bother
+
+ if (d->ref == 1)
+ return true; // no need to detach
+
+ QDBusDemarshaller *dd = new QDBusDemarshaller(d->capabilities);
+ dd->message = q_dbus_message_ref(d->message);
+ dd->iterator = static_cast<QDBusDemarshaller*>(d)->iterator;
+
+ if (!d->ref.deref())
+ delete d;
+ d = dd;
+ return true;
+}
+
+/*!
+ \class QDBusArgument
+ \inmodule QtDBus
+ \since 4.2
+
+ \brief The QDBusArgument class is used to marshall and demarshall D-Bus arguments.
+
+ The class is used to send arguments over D-Bus to remote
+ applications and to receive them back. D-Bus offers an extensible
+ type system, based on a few primitive types and associations of
+ them. See the \l {qdbustypesystem.html}{QtDBus type system} page
+ for more information on the type system.
+
+ QDBusArgument is the central class in the QtDBus type system,
+ providing functions to marshall and demarshall the primitive
+ types. The compound types are then created by association of one
+ or more of the primitive types in arrays, dictionaries or
+ structures.
+
+ The following example illustrates how a structure containing an
+ integer and a string can be constructed using the \l
+ {qdbustypesystem.html}{QtDBus type system}:
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbusargument.cpp 0
+
+ The type has to be registered with qDBusRegisterMetaType() before
+ it can be used with QDBusArgument. Therefore, somewhere in your
+ program, you should add the following code:
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbusargument.cpp 1
+
+ Once registered, a type can be used in outgoing method calls
+ (placed with QDBusAbstractInterface::call()), signal emissions
+ from registered objects or in incoming calls from remote
+ applications.
+
+ It is important to note that the \c{operator<<} and \c{operator>>}
+ streaming functions must always produce the same number of entries
+ in case of structures, both in reading and in writing (marshalling
+ and demarshalling), otherwise calls and signals may start to
+ silently fail.
+
+ The following example illustrates this wrong usage
+ in context of a class that may contain invalid data:
+
+ \badcode
+ // Wrongly marshall the MyTime data into a D-Bus argument
+ QDBusArgument &operator<<(QDBusArgument &argument, const MyTime &mytime)
+ {
+ argument.beginStructure();
+ if (mytime.isValid)
+ argument << true << mytime.hour
+ << mytime.minute << mytime.second;
+ else
+ argument << false;
+ argument.endStructure();
+ return argument;
+ }
+ \endcode
+
+ In this example, both the \c{operator<<} and the \c{operator>>}
+ functions may produce a different number of reads/writes. This can
+ confuse the QtDBus type system and should be avoided.
+
+ \sa QDBusAbstractInterface, {qdbustypesystem.html}{The QtDBus type
+ system}, {usingadaptors.html}{Using Adaptors}, qdbus_cast()
+*/
+
+/*!
+ \enum QDBusArgument::ElementType
+ \since 4.5
+
+ This enum describes the type of element held by the argument.
+
+ \value BasicType A basic element, which is understood by
+ QVariant. The following types are considered basic: bool,
+ byte, short, ushort, int, uint, qint64, quint64, double,
+ QString, QByteArray, QDBusObjectPath, QDBusSignature
+
+ \value VariantType The variant element (QDBusVariant)
+
+ \value ArrayType An array element, usually represented by QList<T>
+ or QVector<T>. Note: QByteArray and associative maps are not
+ considered arrays, even if the D-Bus protocol transports them as such.
+
+ \value StructureType A custom type represented by a structure,
+ like QDateTime, QPoint, etc.
+
+ \value MapType An associative container, like QMap<Key, Value> or
+ QHash<Key, Value>
+
+ \value MapEntryType One entry in an associative container: both
+ the key and the value form one map-entry type.
+
+ \value UnknownType The type is unknown or we have reached the end
+ of the list.
+
+ \sa currentType()
+*/
+
+/*!
+ \fn qdbus_cast(const QDBusArgument &argument)
+ \relates QDBusArgument
+ \since 4.2
+
+ Attempts to demarshall the contents of \a argument into the type
+ \c{T}. For example:
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbusargument.cpp 2
+
+ Note that it is equivalent to the following:
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbusargument.cpp 3
+*/
+
+/*!
+ Constructs an empty QDBusArgument argument.
+
+ An empty QDBusArgument object does not allow either reading or
+ writing to be performed.
+*/
+QDBusArgument::QDBusArgument()
+{
+ if (!qdbus_loadLibDBus()) {
+ d = 0;
+ return;
+ }
+
+ QDBusMarshaller *dd = new QDBusMarshaller(0);
+ d = dd;
+
+ // create a new message with any type, we won't sent it anyways
+ dd->message = q_dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL);
+ q_dbus_message_iter_init_append(dd->message, &dd->iterator);
+}
+
+/*!
+ Constructs a copy of the \a other QDBusArgument object.
+
+ Both objects will therefore contain the same state from this point
+ forward. QDBusArguments are explicitly shared and, therefore, any
+ modification to either copy will affect the other one too.
+*/
+QDBusArgument::QDBusArgument(const QDBusArgument &other)
+ : d(other.d)
+{
+ if (d)
+ d->ref.ref();
+}
+
+/*!
+ \internal
+*/
+QDBusArgument::QDBusArgument(QDBusArgumentPrivate *dd)
+ : d(dd)
+{
+}
+
+/*!
+ Copies the \a other QDBusArgument object into this one.
+
+ Both objects will therefore contain the same state from this point
+ forward. QDBusArguments are explicitly shared and, therefore, any
+ modification to either copy will affect the other one too.
+*/
+QDBusArgument &QDBusArgument::operator=(const QDBusArgument &other)
+{
+ qAtomicAssign(d, other.d);
+ return *this;
+}
+
+/*!
+ Disposes of the resources associated with this QDBusArgument
+ object.
+*/
+QDBusArgument::~QDBusArgument()
+{
+ if (d && !d->ref.deref())
+ delete d;
+}
+
+/*!
+ Appends the primitive value \a arg of type \c{BYTE} to the D-Bus stream.
+*/
+QDBusArgument &QDBusArgument::operator<<(uchar arg)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d->marshaller()->append(arg);
+ return *this;
+}
+
+/*!
+ \overload
+ Appends the primitive value \a arg of type \c{BOOLEAN} to the D-Bus stream.
+*/
+QDBusArgument &QDBusArgument::operator<<(bool arg)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d->marshaller()->append(arg);
+ return *this;
+}
+
+/*!
+ \overload
+ Appends the primitive value \a arg of type \c{INT16} to the D-Bus stream.
+*/
+QDBusArgument &QDBusArgument::operator<<(short arg)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d->marshaller()->append(arg);
+ return *this;
+}
+
+/*!
+ \overload
+ Appends the primitive value \a arg of type \c{UINT16} to the D-Bus stream.
+*/
+QDBusArgument &QDBusArgument::operator<<(ushort arg)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d->marshaller()->append(arg);
+ return *this;
+}
+
+/*!
+ \overload
+ Appends the primitive value \a arg of type \c{INT32} to the D-Bus stream.
+*/
+QDBusArgument &QDBusArgument::operator<<(int arg)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d->marshaller()->append(arg);
+ return *this;
+}
+
+/*!
+ \overload
+ Appends the primitive value \a arg of type \c{UINT32} to the D-Bus stream.
+*/
+QDBusArgument &QDBusArgument::operator<<(uint arg)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d->marshaller()->append(arg);
+ return *this;
+}
+
+/*!
+ \overload
+ Appends the primitive value \a arg of type \c{INT64} to the D-Bus stream.
+*/
+QDBusArgument &QDBusArgument::operator<<(qlonglong arg)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d->marshaller()->append(arg);
+ return *this;
+}
+
+/*!
+ \overload
+ Appends the primitive value \a arg of type \c{UINT64} to the D-Bus stream.
+*/
+QDBusArgument &QDBusArgument::operator<<(qulonglong arg)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d->marshaller()->append(arg);
+ return *this;
+}
+
+/*!
+ \overload
+ Appends the primitive value \a arg of type \c{DOUBLE} (double-precision
+ floating-point) to the D-Bus stream.
+*/
+QDBusArgument &QDBusArgument::operator<<(double arg)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d->marshaller()->append(arg);
+ return *this;
+}
+
+/*!
+ \overload
+ Appends the primitive value \a arg of type \c{STRING} (Unicode character
+ string) to the D-Bus stream.
+*/
+QDBusArgument &QDBusArgument::operator<<(const QString &arg)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d->marshaller()->append(arg);
+ return *this;
+}
+
+/*!
+ \overload
+ \internal
+ Appends the primitive value \a arg of type \c{OBJECT_PATH} (path to a D-Bus
+ object) to the D-Bus stream.
+*/
+QDBusArgument &QDBusArgument::operator<<(const QDBusObjectPath &arg)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d->marshaller()->append(arg);
+ return *this;
+}
+
+/*!
+ \overload
+ \internal
+ Appends the primitive value \a arg of type \c{SIGNATURE} (D-Bus type
+ signature) to the D-Bus stream.
+*/
+QDBusArgument &QDBusArgument::operator<<(const QDBusSignature &arg)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d->marshaller()->append(arg);
+ return *this;
+}
+
+/*!
+ \overload
+ \since 4.8
+ \internal
+ Appends the primitive value \a arg of type \c{UNIX_FILE_DESCRIPTOR} (Unix
+ File Descriptor) to the D-Bus stream.
+*/
+QDBusArgument &QDBusArgument::operator<<(const QDBusUnixFileDescriptor &arg)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d->marshaller()->append(arg);
+ return *this;
+}
+
+/*!
+ \overload
+ Appends the primitive value \a arg of type \c{VARIANT} to the D-Bus stream.
+
+ A D-Bus variant type can contain any type, including other
+ variants. It is similar to the Qt QVariant type.
+*/
+QDBusArgument &QDBusArgument::operator<<(const QDBusVariant &arg)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d->marshaller()->append(arg);
+ return *this;
+}
+
+/*!
+ \overload
+ Appends the QStringList given by \a arg as \c{ARRAY of STRING}
+ to the D-Bus stream.
+
+ QStringList and QByteArray are the only two non-primitive types
+ that are supported directly by QDBusArgument because of their
+ widespread usage in Qt applications.
+
+ Other arrays are supported through compound types in QtDBus.
+*/
+QDBusArgument &QDBusArgument::operator<<(const QStringList &arg)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d->marshaller()->append(arg);
+ return *this;
+}
+
+/*!
+ \overload
+ Appends the QByteArray given by \a arg as \c{ARRAY of BYTE}
+ to the D-Bus stream.
+
+ QStringList and QByteArray are the only two non-primitive types
+ that are supported directly by QDBusArgument because of their
+ widespread usage in Qt applications.
+
+ Other arrays are supported through compound types in QtDBus.
+*/
+QDBusArgument &QDBusArgument::operator<<(const QByteArray &arg)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d->marshaller()->append(arg);
+ return *this;
+}
+
+/*!
+ \internal
+ \since 4.5
+
+ Appends the variant \a v.
+
+ \sa asVariant()
+*/
+void QDBusArgument::appendVariant(const QVariant &v)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d->marshaller()->appendVariantInternal(v);
+}
+
+/*!
+ \internal
+ Returns the type signature of the D-Bus type this QDBusArgument
+ object is currently pointing to.
+*/
+QString QDBusArgument::currentSignature() const
+{
+ if (!d)
+ return QString();
+ if (d->direction == QDBusArgumentPrivate::Demarshalling)
+ return d->demarshaller()->currentSignature();
+ else
+ return d->marshaller()->currentSignature();
+}
+
+/*!
+ \since 4.5
+ Returns the classification of the current element type. If an
+ error decoding the type occurs or if we're at the end of the
+ argument, this function returns QDBusArgument::UnknownType.
+
+ This function only makes sense when demarshalling arguments. If it
+ is used while marshalling, it will always return UnknownType.
+*/
+QDBusArgument::ElementType QDBusArgument::currentType() const
+{
+ if (!d)
+ return UnknownType;
+ if (d->direction == QDBusArgumentPrivate::Demarshalling)
+ return d->demarshaller()->currentType();
+ return UnknownType;
+}
+
+/*!
+ Extracts one D-BUS primitive argument of type \c{BYTE} from the
+ D-BUS stream and puts it into \a arg.
+*/
+const QDBusArgument &QDBusArgument::operator>>(uchar &arg) const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ arg = d->demarshaller()->toByte();
+ return *this;
+}
+
+/*!
+ \overload
+ Extracts one D-Bus primitive argument of type \c{BOOLEAN} from the
+ D-Bus stream.
+*/
+const QDBusArgument &QDBusArgument::operator>>(bool &arg) const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ arg = d->demarshaller()->toBool();
+ return *this;
+}
+
+/*!
+ \overload
+ Extracts one D-Bus primitive argument of type \c{UINT16} from the
+ D-Bus stream.
+*/
+const QDBusArgument &QDBusArgument::operator>>(ushort &arg) const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ arg = d->demarshaller()->toUShort();
+ return *this;
+}
+
+/*!
+ \overload
+ Extracts one D-Bus primitive argument of type \c{INT16} from the
+ D-Bus stream.
+*/
+const QDBusArgument &QDBusArgument::operator>>(short &arg) const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ arg = d->demarshaller()->toShort();
+ return *this;
+}
+
+/*!
+ \overload
+ Extracts one D-Bus primitive argument of type \c{INT32} from the
+ D-Bus stream.
+*/
+const QDBusArgument &QDBusArgument::operator>>(int &arg) const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ arg = d->demarshaller()->toInt();
+ return *this;
+}
+
+/*!
+ \overload
+ Extracts one D-Bus primitive argument of type \c{UINT32} from the
+ D-Bus stream.
+*/
+const QDBusArgument &QDBusArgument::operator>>(uint &arg) const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ arg = d->demarshaller()->toUInt();
+ return *this;
+}
+
+/*!
+ \overload
+ Extracts one D-Bus primitive argument of type \c{INT64} from the
+ D-Bus stream.
+*/
+const QDBusArgument &QDBusArgument::operator>>(qlonglong &arg) const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ arg = d->demarshaller()->toLongLong();
+ return *this;
+}
+
+/*!
+ \overload
+ Extracts one D-Bus primitive argument of type \c{UINT64} from the
+ D-Bus stream.
+*/
+const QDBusArgument &QDBusArgument::operator>>(qulonglong &arg) const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ arg = d->demarshaller()->toULongLong();
+ return *this;
+}
+
+/*!
+ \overload
+ Extracts one D-Bus primitive argument of type \c{DOUBLE}
+ (double-precision floating pount) from the D-Bus stream.
+*/
+const QDBusArgument &QDBusArgument::operator>>(double &arg) const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ arg = d->demarshaller()->toDouble();
+ return *this;
+}
+
+/*!
+ \overload
+ Extracts one D-Bus primitive argument of type \c{STRING} (Unicode
+ character string) from the D-Bus stream.
+*/
+const QDBusArgument &QDBusArgument::operator>>(QString &arg) const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ arg = d->demarshaller()->toString();
+ return *this;
+}
+
+/*!
+ \overload
+ \internal
+ Extracts one D-Bus primitive argument of type \c{OBJECT_PATH}
+ (D-Bus path to an object) from the D-Bus stream.
+*/
+const QDBusArgument &QDBusArgument::operator>>(QDBusObjectPath &arg) const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ arg = d->demarshaller()->toObjectPath();
+ return *this;
+}
+
+/*!
+ \overload
+ \internal
+ Extracts one D-Bus primitive argument of type \c{SIGNATURE} (D-Bus
+ type signature) from the D-Bus stream.
+*/
+const QDBusArgument &QDBusArgument::operator>>(QDBusSignature &arg) const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ arg = d->demarshaller()->toSignature();
+ return *this;
+}
+
+/*!
+ \overload
+ \since 4.8
+ \internal
+ Extracts one D-Bus primitive argument of type \c{UNIX_FILE_DESCRIPTOR}
+ (Unix file descriptor) from the D-Bus stream.
+*/
+const QDBusArgument &QDBusArgument::operator>>(QDBusUnixFileDescriptor &arg) const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ arg = d->demarshaller()->toUnixFileDescriptor();
+ return *this;
+}
+
+/*!
+ \overload
+ Extracts one D-Bus primitive argument of type \c{VARIANT} from the
+ D-Bus stream.
+
+ A D-Bus variant type can contain any type, including other
+ variants. It is similar to the Qt QVariant type.
+
+ In case the variant contains a type not directly supported by
+ QDBusArgument, the value of the returned QDBusVariant will contain
+ another QDBusArgument. It is your responsibility to further
+ demarshall it into another type.
+*/
+const QDBusArgument &QDBusArgument::operator>>(QDBusVariant &arg) const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ arg = d->demarshaller()->toVariant();
+ return *this;
+}
+
+/*!
+ \overload
+ Extracts an array of strings from the D-Bus stream and return it
+ as a QStringList.
+
+ QStringList and QByteArray are the only two non-primitive types
+ that are supported directly by QDBusArgument because of their
+ widespread usage in Qt applications.
+
+ Other arrays are supported through compound types in QtDBus.
+*/
+const QDBusArgument &QDBusArgument::operator>>(QStringList &arg) const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ arg = d->demarshaller()->toStringList();
+ return *this;
+}
+
+/*!
+ \overload
+ Extracts an array of bytes from the D-Bus stream and return it
+ as a QByteArray.
+
+ QStringList and QByteArray are the only two non-primitive types
+ that are supported directly by QDBusArgument because of their
+ widespread usage in Qt applications.
+
+ Other arrays are supported through compound types in QtDBus.
+*/
+const QDBusArgument &QDBusArgument::operator>>(QByteArray &arg) const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ arg = d->demarshaller()->toByteArray();
+ return *this;
+}
+
+/*!
+ Opens a new D-Bus structure suitable for appending new arguments.
+
+ This function is used usually in \c{operator<<} streaming
+ operators, as in the following example:
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbusargument.cpp 4
+
+ Structures can contain other structures, so the following code is
+ also valid:
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbusargument.cpp 5
+
+ \sa endStructure(), beginArray(), beginMap()
+*/
+void QDBusArgument::beginStructure()
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d = d->marshaller()->beginStructure();
+}
+
+/*!
+ Closes a D-Bus structure opened with beginStructure(). This function must be called
+ same number of times that beginStructure() is called.
+
+ \sa beginStructure(), endArray(), endMap()
+*/
+void QDBusArgument::endStructure()
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d = d->marshaller()->endStructure();
+}
+
+/*!
+ Opens a new D-Bus array suitable for appending elements of meta-type \a id.
+
+ This function is used usually in \c{operator<<} streaming
+ operators, as in the following example:
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbusargument.cpp 6
+
+ If the type you want to marshall is a QList, QVector or any of the
+ Qt's \l {Container Classes} that take one template parameter,
+ you need not declare an \c{operator<<} function for it, since
+ QtDBus provides generic templates to do the job of marshalling
+ the data. The same applies for STL's sequence containers, such
+ as \c {std::list}, \c {std::vector}, etc.
+
+ \sa endArray(), beginStructure(), beginMap()
+*/
+void QDBusArgument::beginArray(int id)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d = d->marshaller()->beginArray(id);
+}
+
+/*!
+ Closes a D-Bus array opened with beginArray(). This function must be called
+ same number of times that beginArray() is called.
+
+ \sa beginArray(), endStructure(), endMap()
+*/
+void QDBusArgument::endArray()
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d = d->marshaller()->endArray();
+}
+
+/*!
+ Opens a new D-Bus map suitable for
+ appending elements. Maps are containers that associate one entry
+ (the key) to another (the value), such as Qt's QMap or QHash. The
+ ids of the map's key and value meta types must be passed in \a kid
+ and \a vid respectively.
+
+ This function is used usually in \c{operator<<} streaming
+ operators, as in the following example:
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbusargument.cpp 7
+
+ If the type you want to marshall is a QMap or QHash, you need not
+ declare an \c{operator<<} function for it, since QtDBus provides
+ generic templates to do the job of marshalling the data.
+
+ \sa endMap(), beginStructure(), beginArray(), beginMapEntry()
+*/
+void QDBusArgument::beginMap(int kid, int vid)
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d = d->marshaller()->beginMap(kid, vid);
+}
+
+/*!
+ Closes a D-Bus map opened with beginMap(). This function must be called
+ same number of times that beginMap() is called.
+
+ \sa beginMap(), endStructure(), endArray()
+*/
+void QDBusArgument::endMap()
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d = d->marshaller()->endMap();
+}
+
+/*!
+ Opens a D-Bus map entry suitable for
+ appending the key and value entries. This function is only valid
+ when a map has been opened with beginMap().
+
+ See beginMap() for an example of usage of this function.
+
+ \sa endMapEntry(), beginMap()
+*/
+void QDBusArgument::beginMapEntry()
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d = d->marshaller()->beginMapEntry();
+}
+
+/*!
+ Closes a D-Bus map entry opened with beginMapEntry(). This function must be called
+ same number of times that beginMapEntry() is called.
+
+ \sa beginMapEntry()
+*/
+void QDBusArgument::endMapEntry()
+{
+ if (QDBusArgumentPrivate::checkWrite(d))
+ d = d->marshaller()->endMapEntry();
+}
+
+/*!
+ Opens a D-Bus structure suitable for extracting elements.
+
+ This function is used usually in \c{operator>>} streaming
+ operators, as in the following example:
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbusargument.cpp 8
+
+ \sa endStructure(), beginArray(), beginMap()
+*/
+void QDBusArgument::beginStructure() const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ d = d->demarshaller()->beginStructure();
+}
+
+/*!
+ Closes the D-Bus structure and allow extracting of the next element
+ after the structure.
+
+ \sa beginStructure()
+*/
+void QDBusArgument::endStructure() const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ d = d->demarshaller()->endStructure();
+}
+
+/*!
+ Recurses into the D-Bus array to allow extraction of
+ the array elements.
+
+ This function is used usually in \c{operator>>} streaming
+ operators, as in the following example:
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbusargument.cpp 9
+
+ If the type you want to demarshall is a QList, QVector or any of the
+ Qt's \l {Container Classes} that take one template parameter, you
+ need not declare an \c{operator>>} function for it, since QtDBus
+ provides generic templates to do the job of demarshalling the data.
+ The same applies for STL's sequence containers, such as \c {std::list},
+ \c {std::vector}, etc.
+
+ \sa atEnd(), beginStructure(), beginMap()
+*/
+void QDBusArgument::beginArray() const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ d = d->demarshaller()->beginArray();
+}
+
+/*!
+ Closes the D-Bus array and allow extracting of the next element
+ after the array.
+
+ \sa beginArray()
+*/
+void QDBusArgument::endArray() const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ d = d->demarshaller()->endArray();
+}
+
+/*!
+ Recurses into the D-Bus map to allow extraction of
+ the map's elements.
+
+ This function is used usually in \c{operator>>} streaming
+ operators, as in the following example:
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbusargument.cpp 10
+
+ If the type you want to demarshall is a QMap or QHash, you need not
+ declare an \c{operator>>} function for it, since QtDBus provides
+ generic templates to do the job of demarshalling the data.
+
+ \sa endMap(), beginStructure(), beginArray(), beginMapEntry()
+*/
+void QDBusArgument::beginMap() const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ d = d->demarshaller()->beginMap();
+}
+
+/*!
+ Closes the D-Bus map and allow extracting of the next element
+ after the map.
+
+ \sa beginMap()
+*/
+void QDBusArgument::endMap() const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ d = d->demarshaller()->endMap();
+}
+
+/*!
+ Recurses into the D-Bus map entry to allow extraction
+ of the key and value pair.
+
+ See beginMap() for an example of how this function is usually used.
+
+ \sa endMapEntry(), beginMap()
+*/
+void QDBusArgument::beginMapEntry() const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ d = d->demarshaller()->beginMapEntry();
+}
+
+/*!
+ Closes the D-Bus map entry and allow extracting of the next element
+ on the map.
+
+ \sa beginMapEntry()
+*/
+void QDBusArgument::endMapEntry() const
+{
+ if (QDBusArgumentPrivate::checkReadAndDetach(d))
+ d = d->demarshaller()->endMapEntry();
+}
+
+/*!
+ Returns true if there are no more elements to be extracted from
+ this QDBusArgument. This function is usually used in QDBusArgument
+ objects returned from beginMap() and beginArray().
+*/
+bool QDBusArgument::atEnd() const
+{
+ if (QDBusArgumentPrivate::checkRead(d))
+ return d->demarshaller()->atEnd();
+
+ return true; // at least, stop reading
+}
+
+/*!
+ \since 4.5
+
+ Returns the current argument in the form of a QVariant. Basic
+ types will be decoded and returned in the QVariant, but for
+ complex types, this function will return a QDBusArgument object in
+ the QVariant. It is the caller's responsibility to decode the
+ argument (for example, by calling asVariant() in it).
+
+ For example, if the current argument is an INT32, this function
+ will return a QVariant with an argument of type QVariant::Int. For
+ an array of INT32, it will return a QVariant containing a
+ QDBusArgument.
+
+ If an error occurs or if there are no more arguments to decode
+ (i.e., we are at the end of the argument list), this function will
+ return an invalid QVariant.
+
+ \sa atEnd()
+*/
+QVariant QDBusArgument::asVariant() const
+{
+ if (QDBusArgumentPrivate::checkRead(d))
+ return d->demarshaller()->toVariantInternal();
+
+ return QVariant();
+}
+
+QT_END_NAMESPACE
+
+// for optimization purposes, we include the marshallers here
+#include "qdbusmarshaller.cpp"
+#include "qdbusdemarshaller.cpp"
+
+QT_BEGIN_NAMESPACE
+
+// QDBusArgument operators
+
+const QDBusArgument &operator>>(const QDBusArgument &a, QVariant &v)
+{
+ QDBusVariant dbv;
+ a >> dbv;
+ v = dbv.variant();
+ return a;
+}
+
+// QVariant types
+#ifndef QDBUS_NO_SPECIALTYPES
+const QDBusArgument &operator>>(const QDBusArgument &a, QDate &date)
+{
+ int y, m, d;
+ a.beginStructure();
+ a >> y >> m >> d;
+ a.endStructure();
+
+ if (y != 0 && m != 0 && d != 0)
+ date.setYMD(y, m, d);
+ else
+ date = QDate();
+ return a;
+}
+
+QDBusArgument &operator<<(QDBusArgument &a, const QDate &date)
+{
+ a.beginStructure();
+ if (date.isValid())
+ a << date.year() << date.month() << date.day();
+ else
+ a << 0 << 0 << 0;
+ a.endStructure();
+ return a;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &a, QTime &time)
+{
+ int h, m, s, ms;
+ a.beginStructure();
+ a >> h >> m >> s >> ms;
+ a.endStructure();
+
+ if (h < 0)
+ time = QTime();
+ else
+ time.setHMS(h, m, s, ms);
+ return a;
+}
+
+QDBusArgument &operator<<(QDBusArgument &a, const QTime &time)
+{
+ a.beginStructure();
+ if (time.isValid())
+ a << time.hour() << time.minute() << time.second() << time.msec();
+ else
+ a << -1 << -1 << -1 << -1;
+ a.endStructure();
+ return a;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &a, QDateTime &dt)
+{
+ QDate date;
+ QTime time;
+ int timespec;
+
+ a.beginStructure();
+ a >> date >> time >> timespec;
+ a.endStructure();
+
+ dt = QDateTime(date, time, Qt::TimeSpec(timespec));
+ return a;
+}
+
+QDBusArgument &operator<<(QDBusArgument &a, const QDateTime &dt)
+{
+ a.beginStructure();
+ a << dt.date() << dt.time() << int(dt.timeSpec());
+ a.endStructure();
+ return a;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &a, QRect &rect)
+{
+ int x, y, width, height;
+ a.beginStructure();
+ a >> x >> y >> width >> height;
+ a.endStructure();
+
+ rect.setRect(x, y, width, height);
+ return a;
+}
+
+QDBusArgument &operator<<(QDBusArgument &a, const QRect &rect)
+{
+ a.beginStructure();
+ a << rect.x() << rect.y() << rect.width() << rect.height();
+ a.endStructure();
+
+ return a;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &a, QRectF &rect)
+{
+ double x, y, width, height;
+ a.beginStructure();
+ a >> x >> y >> width >> height;
+ a.endStructure();
+
+ rect.setRect(qreal(x), qreal(y), qreal(width), qreal(height));
+ return a;
+}
+
+QDBusArgument &operator<<(QDBusArgument &a, const QRectF &rect)
+{
+ a.beginStructure();
+ a << double(rect.x()) << double(rect.y()) << double(rect.width()) << double(rect.height());
+ a.endStructure();
+
+ return a;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &a, QSize &size)
+{
+ a.beginStructure();
+ a >> size.rwidth() >> size.rheight();
+ a.endStructure();
+
+ return a;
+}
+
+QDBusArgument &operator<<(QDBusArgument &a, const QSize &size)
+{
+ a.beginStructure();
+ a << size.width() << size.height();
+ a.endStructure();
+
+ return a;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &a, QSizeF &size)
+{
+ double width, height;
+ a.beginStructure();
+ a >> width >> height;
+ a.endStructure();
+
+ size.setWidth(qreal(width));
+ size.setHeight(qreal(height));
+ return a;
+}
+
+QDBusArgument &operator<<(QDBusArgument &a, const QSizeF &size)
+{
+ a.beginStructure();
+ a << double(size.width()) << double(size.height());
+ a.endStructure();
+
+ return a;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &a, QPoint &pt)
+{
+ a.beginStructure();
+ a >> pt.rx() >> pt.ry();
+ a.endStructure();
+
+ return a;
+}
+
+QDBusArgument &operator<<(QDBusArgument &a, const QPoint &pt)
+{
+ a.beginStructure();
+ a << pt.x() << pt.y();
+ a.endStructure();
+
+ return a;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &a, QPointF &pt)
+{
+ double x, y;
+ a.beginStructure();
+ a >> x >> y;
+ a.endStructure();
+
+ pt.setX(qreal(x));
+ pt.setY(qreal(y));
+ return a;
+}
+
+QDBusArgument &operator<<(QDBusArgument &a, const QPointF &pt)
+{
+ a.beginStructure();
+ a << double(pt.x()) << double(pt.y());
+ a.endStructure();
+
+ return a;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &a, QLine &line)
+{
+ QPoint p1, p2;
+ a.beginStructure();
+ a >> p1 >> p2;
+ a.endStructure();
+
+ line = QLine(p1, p2);
+ return a;
+}
+
+QDBusArgument &operator<<(QDBusArgument &a, const QLine &line)
+{
+ a.beginStructure();
+ a << line.p1() << line.p2();
+ a.endStructure();
+
+ return a;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &a, QLineF &line)
+{
+ QPointF p1, p2;
+ a.beginStructure();
+ a >> p1 >> p2;
+ a.endStructure();
+
+ line = QLineF(p1, p2);
+ return a;
+}
+
+QDBusArgument &operator<<(QDBusArgument &a, const QLineF &line)
+{
+ a.beginStructure();
+ a << line.p1() << line.p2();
+ a.endStructure();
+
+ return a;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusargument.h b/src/dbus/qdbusargument.h
new file mode 100644
index 0000000000..f80723e6b4
--- /dev/null
+++ b/src/dbus/qdbusargument.h
@@ -0,0 +1,405 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSARGUMENT_H
+#define QDBUSARGUMENT_H
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qvariant.h>
+#include <QtDBus/qdbusextratypes.h>
+#include <QtDBus/qdbusmacros.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(DBus)
+
+class QDBusUnixFileDescriptor;
+
+class QDBusArgumentPrivate;
+class QDBusDemarshaller;
+class QDBusMarshaller;
+class Q_DBUS_EXPORT QDBusArgument
+{
+public:
+ enum ElementType {
+ BasicType,
+ VariantType,
+ ArrayType,
+ StructureType,
+ MapType,
+ MapEntryType,
+ UnknownType = -1
+ };
+
+ QDBusArgument();
+ QDBusArgument(const QDBusArgument &other);
+ QDBusArgument &operator=(const QDBusArgument &other);
+ ~QDBusArgument();
+
+ // used for marshalling (Qt -> D-BUS)
+ QDBusArgument &operator<<(uchar arg);
+ QDBusArgument &operator<<(bool arg);
+ QDBusArgument &operator<<(short arg);
+ QDBusArgument &operator<<(ushort arg);
+ QDBusArgument &operator<<(int arg);
+ QDBusArgument &operator<<(uint arg);
+ QDBusArgument &operator<<(qlonglong arg);
+ QDBusArgument &operator<<(qulonglong arg);
+ QDBusArgument &operator<<(double arg);
+ QDBusArgument &operator<<(const QString &arg);
+ QDBusArgument &operator<<(const QDBusVariant &arg);
+ QDBusArgument &operator<<(const QDBusObjectPath &arg);
+ QDBusArgument &operator<<(const QDBusSignature &arg);
+ QDBusArgument &operator<<(const QDBusUnixFileDescriptor &arg);
+ QDBusArgument &operator<<(const QStringList &arg);
+ QDBusArgument &operator<<(const QByteArray &arg);
+
+ void beginStructure();
+ void endStructure();
+ void beginArray(int elementMetaTypeId);
+ void endArray();
+ void beginMap(int keyMetaTypeId, int valueMetaTypeId);
+ void endMap();
+ void beginMapEntry();
+ void endMapEntry();
+
+ void appendVariant(const QVariant &v);
+
+ // used for de-marshalling (D-BUS -> Qt)
+ QString currentSignature() const;
+ ElementType currentType() const;
+
+ const QDBusArgument &operator>>(uchar &arg) const;
+ const QDBusArgument &operator>>(bool &arg) const;
+ const QDBusArgument &operator>>(short &arg) const;
+ const QDBusArgument &operator>>(ushort &arg) const;
+ const QDBusArgument &operator>>(int &arg) const;
+ const QDBusArgument &operator>>(uint &arg) const;
+ const QDBusArgument &operator>>(qlonglong &arg) const;
+ const QDBusArgument &operator>>(qulonglong &arg) const;
+ const QDBusArgument &operator>>(double &arg) const;
+ const QDBusArgument &operator>>(QString &arg) const;
+ const QDBusArgument &operator>>(QDBusVariant &arg) const;
+ const QDBusArgument &operator>>(QDBusObjectPath &arg) const;
+ const QDBusArgument &operator>>(QDBusSignature &arg) const;
+ const QDBusArgument &operator>>(QDBusUnixFileDescriptor &arg) const;
+ const QDBusArgument &operator>>(QStringList &arg) const;
+ const QDBusArgument &operator>>(QByteArray &arg) const;
+
+ void beginStructure() const;
+ void endStructure() const;
+ void beginArray() const;
+ void endArray() const;
+ void beginMap() const;
+ void endMap() const;
+ void beginMapEntry() const;
+ void endMapEntry() const;
+ bool atEnd() const;
+
+ QVariant asVariant() const;
+
+protected:
+ QDBusArgument(QDBusArgumentPrivate *d);
+ friend class QDBusArgumentPrivate;
+ mutable QDBusArgumentPrivate *d;
+};
+
+template<typename T> inline T qdbus_cast(const QDBusArgument &arg
+#ifndef Q_QDOC
+, T * = 0
+#endif
+ )
+{
+ T item;
+ arg >> item;
+ return item;
+}
+
+template<typename T> inline T qdbus_cast(const QVariant &v
+#ifndef Q_QDOC
+, T * = 0
+#endif
+ )
+{
+ int id = v.userType();
+ if (id == qMetaTypeId<QDBusArgument>())
+ return qdbus_cast<T>(qvariant_cast<QDBusArgument>(v));
+ else
+ return qvariant_cast<T>(v);
+}
+
+// specialize for QVariant, allowing it to be used in place of QDBusVariant
+template<> inline QVariant qdbus_cast<QVariant>(const QDBusArgument &arg, QVariant *)
+{
+ QDBusVariant item;
+ arg >> item;
+ return item.variant();
+}
+template<> inline QVariant qdbus_cast<QVariant>(const QVariant &v, QVariant *)
+{
+ return qdbus_cast<QDBusVariant>(v).variant();
+}
+
+Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QVariant &v);
+
+// QVariant types
+#ifndef QDBUS_NO_SPECIALTYPES
+
+Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QDate &date);
+Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QDate &date);
+
+Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QTime &time);
+Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QTime &time);
+
+Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QDateTime &dt);
+Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QDateTime &dt);
+
+Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QRect &rect);
+Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QRect &rect);
+
+Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QRectF &rect);
+Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QRectF &rect);
+
+Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QSize &size);
+Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QSize &size);
+
+Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QSizeF &size);
+Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QSizeF &size);
+
+Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QPoint &pt);
+Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QPoint &pt);
+
+Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QPointF &pt);
+Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QPointF &pt);
+
+Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QLine &line);
+Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QLine &line);
+
+Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QLineF &line);
+Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QLineF &line);
+#endif
+
+template<template <typename> class Container, typename T>
+inline QDBusArgument &operator<<(QDBusArgument &arg, const Container<T> &list)
+{
+ int id = qMetaTypeId<T>();
+ arg.beginArray(id);
+ typename Container<T>::const_iterator it = list.begin();
+ typename Container<T>::const_iterator end = list.end();
+ for ( ; it != end; ++it)
+ arg << *it;
+ arg.endArray();
+ return arg;
+}
+
+template<template <typename> class Container, typename T>
+inline const QDBusArgument &operator>>(const QDBusArgument &arg, Container<T> &list)
+{
+ arg.beginArray();
+ list.clear();
+ while (!arg.atEnd()) {
+ T item;
+ arg >> item;
+ list.push_back(item);
+ }
+
+ arg.endArray();
+ return arg;
+}
+
+// QList specializations
+template<typename T>
+inline QDBusArgument &operator<<(QDBusArgument &arg, const QList<T> &list)
+{
+ int id = qMetaTypeId<T>();
+ arg.beginArray(id);
+ typename QList<T>::ConstIterator it = list.constBegin();
+ typename QList<T>::ConstIterator end = list.constEnd();
+ for ( ; it != end; ++it)
+ arg << *it;
+ arg.endArray();
+ return arg;
+}
+
+template<typename T>
+inline const QDBusArgument &operator>>(const QDBusArgument &arg, QList<T> &list)
+{
+ arg.beginArray();
+ list.clear();
+ while (!arg.atEnd()) {
+ T item;
+ arg >> item;
+ list.push_back(item);
+ }
+ arg.endArray();
+
+ return arg;
+}
+
+inline QDBusArgument &operator<<(QDBusArgument &arg, const QVariantList &list)
+{
+ int id = qMetaTypeId<QDBusVariant>();
+ arg.beginArray(id);
+ QVariantList::ConstIterator it = list.constBegin();
+ QVariantList::ConstIterator end = list.constEnd();
+ for ( ; it != end; ++it)
+ arg << QDBusVariant(*it);
+ arg.endArray();
+ return arg;
+}
+
+// QMap specializations
+template<typename Key, typename T>
+inline QDBusArgument &operator<<(QDBusArgument &arg, const QMap<Key, T> &map)
+{
+ int kid = qMetaTypeId<Key>();
+ int vid = qMetaTypeId<T>();
+ arg.beginMap(kid, vid);
+ typename QMap<Key, T>::ConstIterator it = map.constBegin();
+ typename QMap<Key, T>::ConstIterator end = map.constEnd();
+ for ( ; it != end; ++it) {
+ arg.beginMapEntry();
+ arg << it.key() << it.value();
+ arg.endMapEntry();
+ }
+ arg.endMap();
+ return arg;
+}
+
+template<typename Key, typename T>
+inline const QDBusArgument &operator>>(const QDBusArgument &arg, QMap<Key, T> &map)
+{
+ arg.beginMap();
+ map.clear();
+ while (!arg.atEnd()) {
+ Key key;
+ T value;
+ arg.beginMapEntry();
+ arg >> key >> value;
+ map.insertMulti(key, value);
+ arg.endMapEntry();
+ }
+ arg.endMap();
+ return arg;
+}
+
+inline QDBusArgument &operator<<(QDBusArgument &arg, const QVariantMap &map)
+{
+ arg.beginMap(QVariant::String, qMetaTypeId<QDBusVariant>());
+ QVariantMap::ConstIterator it = map.constBegin();
+ QVariantMap::ConstIterator end = map.constEnd();
+ for ( ; it != end; ++it) {
+ arg.beginMapEntry();
+ arg << it.key() << QDBusVariant(it.value());
+ arg.endMapEntry();
+ }
+ arg.endMap();
+ return arg;
+}
+
+// QHash specializations
+template<typename Key, typename T>
+inline QDBusArgument &operator<<(QDBusArgument &arg, const QHash<Key, T> &map)
+{
+ int kid = qMetaTypeId<Key>();
+ int vid = qMetaTypeId<T>();
+ arg.beginMap(kid, vid);
+ typename QHash<Key, T>::ConstIterator it = map.constBegin();
+ typename QHash<Key, T>::ConstIterator end = map.constEnd();
+ for ( ; it != end; ++it) {
+ arg.beginMapEntry();
+ arg << it.key() << it.value();
+ arg.endMapEntry();
+ }
+ arg.endMap();
+ return arg;
+}
+
+template<typename Key, typename T>
+inline const QDBusArgument &operator>>(const QDBusArgument &arg, QHash<Key, T> &map)
+{
+ arg.beginMap();
+ map.clear();
+ while (!arg.atEnd()) {
+ Key key;
+ T value;
+ arg.beginMapEntry();
+ arg >> key >> value;
+ map.insertMulti(key, value);
+ arg.endMapEntry();
+ }
+ arg.endMap();
+ return arg;
+}
+
+inline QDBusArgument &operator<<(QDBusArgument &arg, const QVariantHash &map)
+{
+ arg.beginMap(QVariant::String, qMetaTypeId<QDBusVariant>());
+ QVariantHash::ConstIterator it = map.constBegin();
+ QVariantHash::ConstIterator end = map.constEnd();
+ for ( ; it != end; ++it) {
+ arg.beginMapEntry();
+ arg << it.key() << QDBusVariant(it.value());
+ arg.endMapEntry();
+ }
+ arg.endMap();
+ return arg;
+}
+
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QDBusArgument)
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusargument_p.h b/src/dbus/qdbusargument_p.h
new file mode 100644
index 0000000000..1c713a3433
--- /dev/null
+++ b/src/dbus/qdbusargument_p.h
@@ -0,0 +1,222 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSARGUMENT_P_H
+#define QDBUSARGUMENT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qdbusargument.h>
+#include "qdbusunixfiledescriptor.h"
+#include "qdbus_symbols_p.h"
+
+#ifndef QT_NO_DBUS
+
+#ifndef DBUS_TYPE_UNIX_FD
+# define DBUS_TYPE_UNIX_FD int('h')
+# define DBUS_TYPE_UNIX_FD_AS_STRING "h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QDBusMarshaller;
+class QDBusDemarshaller;
+class QDBusArgumentPrivate
+{
+public:
+ inline QDBusArgumentPrivate(int flags = 0)
+ : message(0), ref(1), capabilities(flags)
+ { }
+ ~QDBusArgumentPrivate();
+
+ static bool checkRead(QDBusArgumentPrivate *d);
+ static bool checkReadAndDetach(QDBusArgumentPrivate *&d);
+ static bool checkWrite(QDBusArgumentPrivate *&d);
+
+ QDBusMarshaller *marshaller();
+ QDBusDemarshaller *demarshaller();
+
+ static QByteArray createSignature(int id);
+ static inline QDBusArgument create(QDBusArgumentPrivate *d)
+ {
+ QDBusArgument q(d);
+ return q;
+ }
+ static inline QDBusArgumentPrivate *d(QDBusArgument &q)
+ { return q.d; }
+
+public:
+ DBusMessage *message;
+ QAtomicInt ref;
+ int capabilities;
+ enum Direction {
+ Marshalling,
+ Demarshalling
+ } direction;
+};
+
+class QDBusMarshaller: public QDBusArgumentPrivate
+{
+public:
+ QDBusMarshaller(int flags) : QDBusArgumentPrivate(flags), parent(0), ba(0), closeCode(0), ok(true)
+ { direction = Marshalling; }
+ ~QDBusMarshaller();
+
+ QString currentSignature();
+
+ void append(uchar arg);
+ void append(bool arg);
+ void append(short arg);
+ void append(ushort arg);
+ void append(int arg);
+ void append(uint arg);
+ void append(qlonglong arg);
+ void append(qulonglong arg);
+ void append(double arg);
+ void append(const QString &arg);
+ void append(const QDBusObjectPath &arg);
+ void append(const QDBusSignature &arg);
+ void append(const QDBusUnixFileDescriptor &arg);
+ void append(const QStringList &arg);
+ void append(const QByteArray &arg);
+ bool append(const QDBusVariant &arg); // this one can fail
+
+ QDBusMarshaller *beginStructure();
+ QDBusMarshaller *endStructure();
+ QDBusMarshaller *beginArray(int id);
+ QDBusMarshaller *endArray();
+ QDBusMarshaller *beginMap(int kid, int vid);
+ QDBusMarshaller *endMap();
+ QDBusMarshaller *beginMapEntry();
+ QDBusMarshaller *endMapEntry();
+ QDBusMarshaller *beginCommon(int code, const char *signature);
+ QDBusMarshaller *endCommon();
+ void open(QDBusMarshaller &sub, int code, const char *signature);
+ void close();
+ void error(const QString &message);
+
+ bool appendVariantInternal(const QVariant &arg);
+ bool appendRegisteredType(const QVariant &arg);
+ bool appendCrossMarshalling(QDBusDemarshaller *arg);
+
+public:
+ DBusMessageIter iterator;
+ QDBusMarshaller *parent;
+ QByteArray *ba;
+ QString errorString;
+ char closeCode;
+ bool ok;
+
+private:
+ Q_DISABLE_COPY(QDBusMarshaller)
+};
+
+class QDBusDemarshaller: public QDBusArgumentPrivate
+{
+public:
+ inline QDBusDemarshaller(int flags) : QDBusArgumentPrivate(flags), parent(0)
+ { direction = Demarshalling; }
+ ~QDBusDemarshaller();
+
+ QString currentSignature();
+
+ uchar toByte();
+ bool toBool();
+ ushort toUShort();
+ short toShort();
+ int toInt();
+ uint toUInt();
+ qlonglong toLongLong();
+ qulonglong toULongLong();
+ double toDouble();
+ QString toString();
+ QDBusObjectPath toObjectPath();
+ QDBusSignature toSignature();
+ QDBusUnixFileDescriptor toUnixFileDescriptor();
+ QDBusVariant toVariant();
+ QStringList toStringList();
+ QByteArray toByteArray();
+
+ QDBusDemarshaller *beginStructure();
+ QDBusDemarshaller *endStructure();
+ QDBusDemarshaller *beginArray();
+ QDBusDemarshaller *endArray();
+ QDBusDemarshaller *beginMap();
+ QDBusDemarshaller *endMap();
+ QDBusDemarshaller *beginMapEntry();
+ QDBusDemarshaller *endMapEntry();
+ QDBusDemarshaller *beginCommon();
+ QDBusDemarshaller *endCommon();
+ QDBusArgument duplicate();
+ inline void close() { }
+
+ bool atEnd();
+
+ QVariant toVariantInternal();
+ QDBusArgument::ElementType currentType();
+
+public:
+ DBusMessageIter iterator;
+ QDBusDemarshaller *parent;
+
+private:
+ Q_DISABLE_COPY(QDBusDemarshaller)
+};
+
+inline QDBusMarshaller *QDBusArgumentPrivate::marshaller()
+{ return static_cast<QDBusMarshaller *>(this); }
+
+inline QDBusDemarshaller *QDBusArgumentPrivate::demarshaller()
+{ return static_cast<QDBusDemarshaller *>(this); }
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp
new file mode 100644
index 0000000000..c8cf6eaf66
--- /dev/null
+++ b/src/dbus/qdbusconnection.cpp
@@ -0,0 +1,1154 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qdebug.h>
+#include <qcoreapplication.h>
+#include <qstringlist.h>
+#include <qthread.h>
+
+#include "qdbusconnection.h"
+#include "qdbusconnectioninterface.h"
+#include "qdbuserror.h"
+#include "qdbusmessage.h"
+#include "qdbusmessage_p.h"
+#include "qdbusconnection_p.h"
+#include "qdbusinterface_p.h"
+#include "qdbusutil_p.h"
+#include "qdbusconnectionmanager_p.h"
+
+#include "qdbusthreaddebug_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QDBusConnectionManager, _q_manager)
+
+QDBusConnectionPrivate *QDBusConnectionManager::sender() const
+{
+ QMutexLocker locker(&senderMutex);
+ return connection(senderName);
+}
+
+void QDBusConnectionManager::setSender(const QDBusConnectionPrivate *s)
+{
+ QMutexLocker locker(&senderMutex);
+ senderName = (s ? s->name : QString());
+}
+
+QDBusConnectionPrivate *QDBusConnectionManager::connection(const QString &name) const
+{
+ return connectionHash.value(name, 0);
+}
+
+void QDBusConnectionManager::removeConnection(const QString &name)
+{
+ QDBusConnectionPrivate *d = 0;
+ d = connectionHash.take(name);
+ if (d && !d->ref.deref())
+ d->deleteYourself();
+
+ // Static objects may be keeping the connection open.
+ // However, it is harmless to have outstanding references to a connection that is
+ // closing as long as those references will be soon dropped without being used.
+
+ // ### Output a warning if connections are being used after they have been removed.
+}
+
+QDBusConnectionManager::~QDBusConnectionManager()
+{
+ for (QHash<QString, QDBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin();
+ it != connectionHash.constEnd(); ++it) {
+ QDBusConnectionPrivate *d = it.value();
+ if (!d->ref.deref())
+ d->deleteYourself();
+ else
+ d->closeConnection();
+ }
+ connectionHash.clear();
+}
+
+QDBusConnectionManager* QDBusConnectionManager::instance()
+{
+ return _q_manager();
+}
+
+Q_DBUS_EXPORT void qDBusBindToApplication();
+void qDBusBindToApplication()
+{
+}
+
+void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionPrivate *c)
+{
+ connectionHash[name] = c;
+ c->name = name;
+}
+
+/*!
+ \fn QDBusConnection &QDBusConnection::sessionBus()
+ \relates QDBusConnection
+
+ Returns a QDBusConnection object opened with the session bus. The object
+ reference returned by this function is valid until the application terminates,
+ at which point the connection will be closed and the object deleted.
+*/
+/*!
+ \fn QDBusConnection &QDBusConnection::systemBus()
+ \relates QDBusConnection
+
+ Returns a QDBusConnection object opened with the system bus. The object reference returned
+ by this function is valid until the QCoreApplication's destructor is run, when the
+ connection will be closed and the object, deleted.
+*/
+
+/*!
+ \class QDBusConnection
+ \inmodule QtDBus
+ \since 4.2
+
+ \brief The QDBusConnection class represents a connection to the D-Bus bus daemon.
+
+ This class is the initial point in a D-Bus session. Using it, you
+ can get access to remote objects, interfaces; connect remote
+ signals to your object's slots; register objects, etc.
+
+ D-Bus connections are created using the connectToBus() function,
+ which opens a connection to the server daemon and does the initial
+ handshaking, associating that connection with a name. Further
+ attempts to connect using the same name will return the same
+ connection.
+
+ The connection is then torn down using the disconnectFromBus()
+ function.
+
+ Once disconnected, calling connectToBus() will not reestablish a
+ connection, you must create a new QDBusConnection instance.
+
+ As a convenience for the two most common connection types, the
+ sessionBus() and systemBus() functions return open connections to
+ the session server daemon and the system server daemon,
+ respectively. Those connections are opened when first used and are
+ closed when the QCoreApplication destructor is run.
+
+ D-Bus also supports peer-to-peer connections, without the need for
+ a bus server daemon. Using this facility, two applications can
+ talk to each other and exchange messages. This can be achieved by
+ passing an address to connectToBus() function, which was opened by
+ another D-Bus application using QDBusServer.
+*/
+
+/*!
+ \enum QDBusConnection::BusType
+ Specifies the type of the bus connection. The valid bus types are:
+
+ \value SessionBus the session bus, associated with the running desktop session
+ \value SystemBus the system bus, used to communicate with system-wide processes
+ \value ActivationBus the activation bus, the "alias" for the bus that started the
+ service
+
+ On the Session Bus, one can find other applications by the same user that are sharing the same
+ desktop session (hence the name). On the System Bus, however, processes shared for the whole
+ system are usually found.
+*/
+
+/*!
+ \enum QDBusConnection::RegisterOption
+ Specifies the options for registering objects with the connection. The possible values are:
+
+ \value ExportAdaptors export the contents of adaptors found in this object
+
+ \value ExportScriptableSlots export this object's scriptable slots
+ \value ExportScriptableSignals export this object's scriptable signals
+ \value ExportScriptableProperties export this object's scriptable properties
+ \value ExportScriptableInvokables export this object's scriptable invokables
+ \value ExportScriptableContents shorthand form for ExportScriptableSlots |
+ ExportScriptableSignals |
+ ExportScriptableProperties
+
+ \value ExportNonScriptableSlots export this object's non-scriptable slots
+ \value ExportNonScriptableSignals export this object's non-scriptable signals
+ \value ExportNonScriptableProperties export this object's non-scriptable properties
+ \value ExportNonScriptableInvokables export this object's non-scriptable invokables
+ \value ExportNonScriptableContents shorthand form for ExportNonScriptableSlots |
+ ExportNonScriptableSignals |
+ ExportNonScriptableProperties
+
+ \value ExportAllSlots export all of this object's slots
+ \value ExportAllSignals export all of this object's signals
+ \value ExportAllProperties export all of this object's properties
+ \value ExportAllInvokables export all of this object's invokables
+ \value ExportAllContents export all of this object's contents
+ \value ExportChildObjects export this object's child objects
+
+ \sa registerObject(), QDBusAbstractAdaptor, {usingadaptors.html}{Using adaptors}
+*/
+
+/*!
+ \enum QDBusConnection::UnregisterMode
+ The mode for unregistering an object path:
+
+ \value UnregisterNode unregister this node only: do not unregister child objects
+ \value UnregisterTree unregister this node and all its sub-tree
+
+ Note, however, if this object was registered with the ExportChildObjects option, UnregisterNode
+ will unregister the child objects too.
+*/
+
+/*!
+ \since 4.8
+ \enum QDBusConnection::ConnectionCapabilities
+ The available capabilities for a D-Bus connection.
+
+ \value UnixFileDescriptorPassing passing of Unix file descriptors to other processes
+ (see QDBusUnixFileDescriptor)
+
+ \sa connectionCapabilities()
+*/
+
+/*!
+ Creates a QDBusConnection object attached to the connection with name \a name.
+
+ This does not open the connection. You have to call connectToBus() to open it.
+*/
+QDBusConnection::QDBusConnection(const QString &name)
+{
+ if (name.isEmpty()) {
+ d = 0;
+ } else {
+ QMutexLocker locker(&_q_manager()->mutex);
+ d = _q_manager()->connection(name);
+ if (d)
+ d->ref.ref();
+ }
+}
+
+/*!
+ Creates a copy of the \a other connection.
+*/
+QDBusConnection::QDBusConnection(const QDBusConnection &other)
+{
+ d = other.d;
+ if (d)
+ d->ref.ref();
+}
+
+/*!
+ \internal
+ Creates a connection object with the given \a dd as private object.
+*/
+QDBusConnection::QDBusConnection(QDBusConnectionPrivate *dd)
+{
+ d = dd;
+ if (d)
+ d->ref.ref();
+}
+
+/*!
+ Disposes of this object. This does not close the connection: you
+ have to call disconnectFromBus() to do that.
+*/
+QDBusConnection::~QDBusConnection()
+{
+ if (d && !d->ref.deref())
+ d->deleteYourself();
+}
+
+/*!
+ Creates a copy of the connection \a other in this object. Note
+ that the connection this object referenced before the copy, is not
+ spontaneously disconnected.
+
+ \sa disconnectFromBus()
+*/
+QDBusConnection &QDBusConnection::operator=(const QDBusConnection &other)
+{
+ if (other.d)
+ other.d->ref.ref();
+ if (d && !d->ref.deref())
+ d->deleteYourself();
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Opens a connection of type \a type to one of the known busses and
+ associate with it the connection name \a name. Returns a
+ QDBusConnection object associated with that connection.
+*/
+QDBusConnection QDBusConnection::connectToBus(BusType type, const QString &name)
+{
+// Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection",
+// "Cannot create connection without a Q[Core]Application instance");
+ if (!qdbus_loadLibDBus()) {
+ QDBusConnectionPrivate *d = 0;
+ return QDBusConnection(d);
+ }
+
+ QMutexLocker locker(&_q_manager()->mutex);
+
+ QDBusConnectionPrivate *d = _q_manager()->connection(name);
+ if (d || name.isEmpty())
+ return QDBusConnection(d);
+
+ d = new QDBusConnectionPrivate;
+ DBusConnection *c = 0;
+ QDBusErrorInternal error;
+ switch (type) {
+ case SystemBus:
+ c = q_dbus_bus_get_private(DBUS_BUS_SYSTEM, error);
+ break;
+ case SessionBus:
+ c = q_dbus_bus_get_private(DBUS_BUS_SESSION, error);
+ break;
+ case ActivationBus:
+ c = q_dbus_bus_get_private(DBUS_BUS_STARTER, error);
+ break;
+ }
+ d->setConnection(c, error); //setConnection does the error handling for us
+
+ _q_manager()->setConnection(name, d);
+
+ QDBusConnection retval(d);
+
+ // create the bus service
+ // will lock in QDBusConnectionPrivate::connectRelay()
+ d->setBusService(retval);
+
+ return retval;
+}
+
+/*!
+ Opens a connection to a private bus on address \a address and associate with it the
+ connection name \a name. Returns a QDBusConnection object associated with that connection.
+*/
+QDBusConnection QDBusConnection::connectToBus(const QString &address,
+ const QString &name)
+{
+// Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection",
+// "Cannot create connection without a Q[Core]Application instance");
+ if (!qdbus_loadLibDBus()) {
+ QDBusConnectionPrivate *d = 0;
+ return QDBusConnection(d);
+ }
+
+ QMutexLocker locker(&_q_manager()->mutex);
+
+ QDBusConnectionPrivate *d = _q_manager()->connection(name);
+ if (d || name.isEmpty())
+ return QDBusConnection(d);
+
+ d = new QDBusConnectionPrivate;
+ // setConnection does the error handling for us
+ QDBusErrorInternal error;
+ DBusConnection *c = q_dbus_connection_open_private(address.toUtf8().constData(), error);
+ if (c) {
+ if (!q_dbus_bus_register(c, error)) {
+ q_dbus_connection_unref(c);
+ c = 0;
+ }
+ }
+ d->setConnection(c, error);
+ _q_manager()->setConnection(name, d);
+
+ QDBusConnection retval(d);
+
+ // create the bus service
+ // will lock in QDBusConnectionPrivate::connectRelay()
+ d->setBusService(retval);
+
+ return retval;
+}
+/*!
+ \since 4.8
+
+ Opens a peer-to-peer connection on address \a address and associate with it the
+ connection name \a name. Returns a QDBusConnection object associated with that connection.
+*/
+QDBusConnection QDBusConnection::connectToPeer(const QString &address,
+ const QString &name)
+{
+// Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection",
+// "Cannot create connection without a Q[Core]Application instance");
+ if (!qdbus_loadLibDBus()) {
+ QDBusConnectionPrivate *d = 0;
+ return QDBusConnection(d);
+ }
+
+ QMutexLocker locker(&_q_manager()->mutex);
+
+ QDBusConnectionPrivate *d = _q_manager()->connection(name);
+ if (d || name.isEmpty())
+ return QDBusConnection(d);
+
+ d = new QDBusConnectionPrivate;
+ // setPeer does the error handling for us
+ QDBusErrorInternal error;
+ DBusConnection *c = q_dbus_connection_open_private(address.toUtf8().constData(), error);
+
+ d->setPeer(c, error);
+ _q_manager()->setConnection(name, d);
+
+ QDBusConnection retval(d);
+
+ return retval;
+}
+
+/*!
+ Closes the bus connection of name \a name.
+
+ Note that if there are still QDBusConnection objects associated
+ with the same connection, the connection will not be closed until
+ all references are dropped. However, no further references can be
+ created using the QDBusConnection constructor.
+*/
+void QDBusConnection::disconnectFromBus(const QString &name)
+{
+ if (_q_manager()) {
+ QMutexLocker locker(&_q_manager()->mutex);
+ QDBusConnectionPrivate *d = _q_manager()->connection(name);
+ if (d && d->mode != QDBusConnectionPrivate::ClientMode)
+ return;
+ _q_manager()->removeConnection(name);
+ }
+}
+
+/*!
+ \since 4.8
+
+ Closes the peer connection of name \a name.
+
+ Note that if there are still QDBusConnection objects associated
+ with the same connection, the connection will not be closed until
+ all references are dropped. However, no further references can be
+ created using the QDBusConnection constructor.
+*/
+void QDBusConnection::disconnectFromPeer(const QString &name)
+{
+ if (_q_manager()) {
+ QMutexLocker locker(&_q_manager()->mutex);
+ QDBusConnectionPrivate *d = _q_manager()->connection(name);
+ if (d && d->mode != QDBusConnectionPrivate::PeerMode)
+ return;
+ _q_manager()->removeConnection(name);
+ }
+}
+
+/*!
+ Sends the \a message over this connection, without waiting for a
+ reply. This is suitable for errors, signals, and return values as
+ well as calls whose return values are not necessary.
+
+ Returns true if the message was queued successfully, false otherwise.
+*/
+bool QDBusConnection::send(const QDBusMessage &message) const
+{
+ if (!d || !d->connection) {
+ QDBusError err = QDBusError(QDBusError::Disconnected,
+ QLatin1String("Not connected to D-BUS server"));
+ if (d)
+ d->lastError = err;
+ return false;
+ }
+ return d->send(message) != 0;
+}
+
+/*!
+ Sends the \a message over this connection and returns immediately.
+ When the reply is received, the method \a returnMethod is called in
+ the \a receiver object. If an error occurs, the method \a errorMethod
+ will be called instead.
+
+ If no reply is received within \a timeout milliseconds, an automatic
+ error will be delivered indicating the expiration of the call.
+ The default \a timeout is -1, which will be replaced with an
+ implementation-defined value that is suitable for inter-process
+ communications (generally, 25 seconds).
+
+ This function is suitable for method calls only. It is guaranteed
+ that the slot will be called exactly once with the reply, as long
+ as the parameter types match and no error occurs.
+
+ Returns true if the message was sent, or false if the message could
+ not be sent.
+*/
+bool QDBusConnection::callWithCallback(const QDBusMessage &message, QObject *receiver,
+ const char *returnMethod, const char *errorMethod,
+ int timeout) const
+{
+ if (!d || !d->connection) {
+ QDBusError err = QDBusError(QDBusError::Disconnected,
+ QLatin1String("Not connected to D-BUS server"));
+ if (d)
+ d->lastError = err;
+ return false;
+ }
+ return d->sendWithReplyAsync(message, receiver, returnMethod, errorMethod, timeout) != 0;
+}
+
+/*!
+ \overload
+ \deprecated
+ Sends the \a message over this connection and returns immediately.
+ When the reply is received, the method \a returnMethod is called in
+ the \a receiver object.
+
+ This function is suitable for method calls only. It is guaranteed
+ that the slot will be called exactly once with the reply, as long
+ as the parameter types match and no error occurs.
+
+ This function is dangerous because it cannot report errors, including
+ the expiration of the timeout.
+
+ Returns true if the message was sent, or false if the message could
+ not be sent.
+*/
+bool QDBusConnection::callWithCallback(const QDBusMessage &message, QObject *receiver,
+ const char *returnMethod, int timeout) const
+{
+ return callWithCallback(message, receiver, returnMethod, 0, timeout);
+}
+
+/*!
+ Sends the \a message over this connection and blocks, waiting for
+ a reply, for at most \a timeout milliseconds. This function is
+ suitable for method calls only. It returns the reply message as
+ its return value, which will be either of type
+ QDBusMessage::ReplyMessage or QDBusMessage::ErrorMessage.
+
+ If no reply is received within \a timeout milliseconds, an automatic
+ error will be delivered indicating the expiration of the call.
+ The default \a timeout is -1, which will be replaced with an
+ implementation-defined value that is suitable for inter-process
+ communications (generally, 25 seconds).
+
+ See the QDBusInterface::call() function for a more friendly way
+ of placing calls.
+
+ \warning If \a mode is QDBus::BlockWithGui, this function will
+ reenter the Qt event loop in order to wait for the
+ reply. During the wait, it may deliver signals and other
+ method calls to your application. Therefore, it must be
+ prepared to handle a reentrancy whenever a call is
+ placed with call().
+*/
+QDBusMessage QDBusConnection::call(const QDBusMessage &message, QDBus::CallMode mode, int timeout) const
+{
+ if (!d || !d->connection) {
+ QDBusError err = QDBusError(QDBusError::Disconnected,
+ QLatin1String("Not connected to D-Bus server"));
+ if (d)
+ d->lastError = err;
+
+ return QDBusMessage::createError(err);
+ }
+
+ if (mode != QDBus::NoBlock)
+ return d->sendWithReply(message, mode, timeout);
+
+ d->send(message);
+ QDBusMessage retval;
+ retval << QVariant(); // add one argument (to avoid .at(0) problems)
+ return retval;
+}
+
+/*!
+ \since 4.5
+ Sends the \a message over this connection and returns
+ immediately. This function is suitable for method calls only. It
+ returns an object of type QDBusPendingCall which can be used to
+ track the status of the reply.
+
+ If no reply is received within \a timeout milliseconds, an automatic
+ error will be delivered indicating the expiration of the call. The
+ default \a timeout is -1, which will be replaced with an
+ implementation-defined value that is suitable for inter-process
+ communications (generally, 25 seconds). This timeout is also the
+ upper limit for waiting in QDBusPendingCall::waitForFinished().
+
+ See the QDBusInterface::asyncCall() function for a more friendly way
+ of placing calls.
+*/
+QDBusPendingCall QDBusConnection::asyncCall(const QDBusMessage &message, int timeout) const
+{
+ if (!d || !d->connection) {
+ return QDBusPendingCall(0); // null pointer -> disconnected
+ }
+
+ QDBusPendingCallPrivate *priv = d->sendWithReplyAsync(message, timeout);
+ return QDBusPendingCall(priv);
+}
+
+/*!
+ Connects the signal specified by the \a service, \a path, \a interface and \a name parameters to
+ the slot \a slot in object \a receiver. The arguments \a service and \a path can be empty,
+ denoting a connection to any signal of the (\a interface, \a name) pair, from any remote
+ application.
+
+ Returns true if the connection was successful.
+
+ \warning The signal will only be delivered to the slot if the parameters match. This verification
+ can be done only when the signal is received, not at connection time.
+*/
+bool QDBusConnection::connect(const QString &service, const QString &path, const QString& interface,
+ const QString &name, QObject *receiver, const char *slot)
+{
+ return connect(service, path, interface, name, QStringList(), QString(), receiver, slot);
+}
+
+/*!
+ \overload
+
+ Connects the signal to the slot \a slot in object \a
+ receiver. Unlike the previous connect() overload, this function
+ allows one to specify the parameter signature to be connected
+ using the \a signature variable. The function will then verify
+ that this signature can be delivered to the slot specified by \a
+ slot and return false otherwise.
+
+ Returns true if the connection was successful.
+
+ \note This function verifies that the signal signature matches the
+ slot's parameters, but it does not verify that the actual
+ signal exists with the given signature in the remote
+ service.
+*/
+bool QDBusConnection::connect(const QString &service, const QString &path, const QString& interface,
+ const QString &name, const QString &signature,
+ QObject *receiver, const char *slot)
+{
+ return connect(service, path, interface, name, QStringList(), signature, receiver, slot);
+}
+
+/*!
+ \overload
+ \since 4.6
+
+ Connects the signal to the slot \a slot in object \a
+ receiver. Unlike the previous connect() overload, this function
+ allows one to specify the parameter signature to be connected
+ using the \a signature variable. The function will then verify
+ that this signature can be delivered to the slot specified by \a
+ slot and return false otherwise.
+
+ The \a argumentMatch parameter lists the string parameters to be matched,
+ in sequential order. Note that, to match an empty string, you need to
+ pass a QString that is empty but not null (i.e., QString("")). A null
+ QString skips matching at that position.
+
+ Returns true if the connection was successful.
+
+ \note This function verifies that the signal signature matches the
+ slot's parameters, but it does not verify that the actual
+ signal exists with the given signature in the remote
+ service.
+*/
+bool QDBusConnection::connect(const QString &service, const QString &path, const QString& interface,
+ const QString &name, const QStringList &argumentMatch, const QString &signature,
+ QObject *receiver, const char *slot)
+{
+
+ if (!receiver || !slot || !d || !d->connection)
+ return false;
+ if (interface.isEmpty() && name.isEmpty())
+ return false;
+ if (!interface.isEmpty() && !QDBusUtil::isValidInterfaceName(interface)) {
+#ifndef QT_NO_DEBUG
+ qWarning("QDBusConnection::connect: interface name '%s' is not valid", interface.toLatin1().constData());
+#endif
+ return false;
+ }
+ if (!service.isEmpty() && !QDBusUtil::isValidBusName(service)) {
+#ifndef QT_NO_DEBUG
+ qWarning("QDBusConnection::connect: service name '%s' is not valid", service.toLatin1().constData());
+#endif
+ return false;
+ }
+ if (!path.isEmpty() && !QDBusUtil::isValidObjectPath(path)) {
+#ifndef QT_NO_DEBUG
+ qWarning("QDBusConnection::connect: object path '%s' is not valid", path.toLatin1().constData());
+#endif
+ return false;
+ }
+
+ QDBusWriteLocker locker(ConnectAction, d);
+ return d->connectSignal(service, path, interface, name, argumentMatch, signature, receiver, slot);
+}
+
+/*!
+ Disconnects the signal specified by the \a service, \a path, \a interface
+ and \a name parameters from the slot \a slot in object \a receiver. The
+ arguments must be the same as passed to the connect() function.
+
+ Returns true if the disconnection was successful.
+*/
+bool QDBusConnection::disconnect(const QString &service, const QString &path, const QString &interface,
+ const QString &name, QObject *receiver, const char *slot)
+{
+ return disconnect(service, path, interface, name, QStringList(), QString(), receiver, slot);
+}
+
+/*!
+ \overload
+
+ Disconnects the signal specified by the \a service, \a path, \a
+ interface, \a name, and \a signature parameters from the slot \a slot in
+ object \a receiver. The arguments must be the same as passed to the
+ connect() function.
+
+ Returns true if the disconnection was successful.
+*/
+bool QDBusConnection::disconnect(const QString &service, const QString &path, const QString& interface,
+ const QString &name, const QString &signature,
+ QObject *receiver, const char *slot)
+{
+ return disconnect(service, path, interface, name, QStringList(), signature, receiver, slot);
+}
+
+/*!
+ \overload
+ \since 4.6
+
+ Disconnects the signal specified by the \a service, \a path, \a
+ interface, \a name, \a argumentMatch, and \a signature parameters from
+ the slot \a slot in object \a receiver. The arguments must be the same as
+ passed to the connect() function.
+
+ Returns true if the disconnection was successful.
+*/
+bool QDBusConnection::disconnect(const QString &service, const QString &path, const QString& interface,
+ const QString &name, const QStringList &argumentMatch, const QString &signature,
+ QObject *receiver, const char *slot)
+{
+ if (!receiver || !slot || !d || !d->connection)
+ return false;
+ if (!interface.isEmpty() && !QDBusUtil::isValidInterfaceName(interface))
+ return false;
+ if (interface.isEmpty() && name.isEmpty())
+ return false;
+
+ QDBusWriteLocker locker(DisconnectAction, d);
+ return d->disconnectSignal(service, path, interface, name, argumentMatch, signature, receiver, slot);
+}
+
+/*!
+ Registers the object \a object at path \a path and returns true if
+ the registration was successful. The \a options parameter
+ specifies how much of the object \a object will be exposed through
+ D-Bus.
+
+ This function does not replace existing objects: if there is already an object registered at
+ path \a path, this function will return false. Use unregisterObject() to unregister it first.
+
+ You cannot register an object as a child object of an object that
+ was registered with QDBusConnection::ExportChildObjects.
+*/
+bool QDBusConnection::registerObject(const QString &path, QObject *object, RegisterOptions options)
+{
+ Q_ASSERT_X(QDBusUtil::isValidObjectPath(path), "QDBusConnection::registerObject",
+ "Invalid object path given");
+ if (!d || !d->connection || !object || !options || !QDBusUtil::isValidObjectPath(path))
+ return false;
+
+ QStringList pathComponents = path.split(QLatin1Char('/'));
+ if (pathComponents.last().isEmpty())
+ pathComponents.removeLast();
+ QDBusWriteLocker locker(RegisterObjectAction, d);
+
+ // lower-bound search for where this object should enter in the tree
+ QDBusConnectionPrivate::ObjectTreeNode *node = &d->rootNode;
+ int i = 1;
+ while (node) {
+ if (pathComponents.count() == i) {
+ // this node exists
+ // consider it free if there's no object here and the user is not trying to
+ // replace the object sub-tree
+ if ((options & ExportChildObjects && !node->children.isEmpty()) || node->obj)
+ return false;
+
+ // we can add the object here
+ node->obj = object;
+ node->flags = options;
+
+ d->registerObject(node);
+ //qDebug("REGISTERED FOR %s", path.toLocal8Bit().constData());
+ return true;
+ }
+
+ // find the position where we'd insert the node
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it =
+ qLowerBound(node->children.begin(), node->children.end(), pathComponents.at(i));
+ if (it != node->children.end() && it->name == pathComponents.at(i)) {
+ // match: this node exists
+ node = it;
+
+ // are we allowed to go deeper?
+ if (node->flags & ExportChildObjects) {
+ // we're not
+ qDebug("Cannot register object at %s because %s exports its own child objects",
+ qPrintable(path), qPrintable(pathComponents.at(i)));
+ return false;
+ }
+ } else {
+ // add entry
+ node = node->children.insert(it, pathComponents.at(i));
+ }
+
+ // iterate
+ ++i;
+ }
+
+ Q_ASSERT_X(false, "QDBusConnection::registerObject", "The impossible happened");
+ return false;
+}
+
+/*!
+ Unregisters an object that was registered with the registerObject() at the object path given by
+ \a path and, if \a mode is QDBusConnection::UnregisterTree, all of its sub-objects too.
+
+ Note that you cannot unregister objects that were not registered with registerObject().
+*/
+void QDBusConnection::unregisterObject(const QString &path, UnregisterMode mode)
+{
+ if (!d || !d->connection || !QDBusUtil::isValidObjectPath(path))
+ return;
+
+ QStringList pathComponents = path.split(QLatin1Char('/'));
+ QDBusWriteLocker locker(UnregisterObjectAction, d);
+ QDBusConnectionPrivate::ObjectTreeNode *node = &d->rootNode;
+ int i = 1;
+
+ // find the object
+ while (node) {
+ if (pathComponents.count() == i || !path.compare(QLatin1String("/"))) {
+ // found it
+ node->obj = 0;
+ node->flags = 0;
+
+ if (mode == UnregisterTree) {
+ // clear the sub-tree as well
+ node->children.clear(); // can't disconnect the objects because we really don't know if they can
+ // be found somewhere else in the path too
+ }
+
+ return;
+ }
+
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it =
+ qLowerBound(node->children.begin(), node->children.end(), pathComponents.at(i));
+ if (it == node->children.end() || it->name != pathComponents.at(i))
+ break; // node not found
+
+ node = it;
+ ++i;
+ }
+}
+
+/*!
+ Return the object that was registered with the registerObject() at the object path given by
+ \a path.
+*/
+QObject *QDBusConnection::objectRegisteredAt(const QString &path) const
+{
+ Q_ASSERT_X(QDBusUtil::isValidObjectPath(path), "QDBusConnection::registeredObject",
+ "Invalid object path given");
+ if (!d || !d->connection || !QDBusUtil::isValidObjectPath(path))
+ return false;
+
+ QStringList pathComponents = path.split(QLatin1Char('/'));
+ if (pathComponents.last().isEmpty())
+ pathComponents.removeLast();
+
+ // lower-bound search for where this object should enter in the tree
+ QDBusReadLocker lock(ObjectRegisteredAtAction, d);
+ const QDBusConnectionPrivate::ObjectTreeNode *node = &d->rootNode;
+
+ int i = 1;
+ while (node) {
+ if (pathComponents.count() == i)
+ return node->obj;
+
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it =
+ qLowerBound(node->children.constBegin(), node->children.constEnd(), pathComponents.at(i));
+ if (it == node->children.constEnd() || it->name != pathComponents.at(i))
+ break; // node not found
+
+ node = it;
+ ++i;
+ }
+ return 0;
+}
+
+/*!
+ Returns a QDBusConnectionInterface object that represents the
+ D-Bus server interface on this connection.
+*/
+QDBusConnectionInterface *QDBusConnection::interface() const
+{
+ if (!d)
+ return 0;
+ return d->busService;
+}
+
+/*!
+ \internal
+ \since 4.8
+
+ Returns the internal, implementation-defined pointer for this
+ connection. Currently, this returns a DBusConnection* pointer,
+ without changing the reference count. It is the responsibility of
+ the caller to call dbus_connection_ref if it wants to store the
+ pointer.
+*/
+void *QDBusConnection::internalPointer() const
+{
+ return d ? d->connection : 0;
+}
+
+/*!
+ Returns true if this QDBusConnection object is connected.
+*/
+bool QDBusConnection::isConnected() const
+{
+ return d && d->connection && q_dbus_connection_get_is_connected(d->connection);
+}
+
+/*!
+ Returns the last error that happened in this connection.
+
+ This function is provided for low-level code. If you're using
+ QDBusInterface::call(), error codes are reported by its return
+ value.
+
+ \sa QDBusInterface, QDBusMessage
+*/
+QDBusError QDBusConnection::lastError() const
+{
+ return d ? d->lastError : QDBusError();
+}
+
+/*!
+ Returns the unique connection name for this connection, if this QDBusConnection object is
+ connected, or an empty QString otherwise.
+
+ A Unique Connection Name is a string in the form ":x.xxx" (where x
+ are decimal digits) that is assigned by the D-Bus server daemon
+ upon connection. It uniquely identifies this client in the bus.
+
+ This function returns an empty QString for peer-to-peer connections.
+*/
+QString QDBusConnection::baseService() const
+{
+ return d ? d->baseService : QString();
+}
+
+/*!
+ \since 4.5
+
+ Returns the connection name for this connection, as given as the
+ name parameter to connectToBus().
+
+ The connection name can be used to uniquely identify actual
+ underlying connections to buses. Copies made from a single
+ connection will always implicitly share the underlying connection,
+ and hence will have the same connection name.
+
+ Inversely, two connections having different connection names will
+ always either be connected to different buses, or have a different
+ unique name (as returned by baseService()) on that bus.
+
+ \sa connectToBus(), disconnectFromBus()
+*/
+QString QDBusConnection::name() const
+{
+ return d ? d->name : QString();
+}
+
+/*!
+ \since 4.8
+
+ Returns the capabilities of this connection as negotiated with the bus
+ server or peer. If this QDBusConnection is not connected, this function
+ returns no capabilities.
+*/
+QDBusConnection::ConnectionCapabilities QDBusConnection::connectionCapabilities() const
+{
+ return d ? d->capabilities : ConnectionCapabilities(0);
+}
+
+/*!
+ Attempts to register the \a serviceName on the D-Bus server and
+ returns true if the registration succeeded. The registration will
+ fail if the name is already registered by another application.
+
+ \sa unregisterService(), QDBusConnectionInterface::registerService()
+*/
+bool QDBusConnection::registerService(const QString &serviceName)
+{
+ if (interface() && interface()->registerService(serviceName)) {
+ if (d) d->registerService(serviceName);
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Unregisters the service \a serviceName that was previously
+ registered with registerService() and returns true if it
+ succeeded.
+
+ \sa registerService(), QDBusConnectionInterface::unregisterService()
+*/
+bool QDBusConnection::unregisterService(const QString &serviceName)
+{
+ if (interface()->unregisterService(serviceName)) {
+ if (d) d->unregisterService(serviceName);
+ return true;
+ }
+ return false;
+}
+
+static const char _q_sessionBusName[] = "qt_default_session_bus";
+static const char _q_systemBusName[] = "qt_default_system_bus";
+
+class QDBusDefaultConnection: public QDBusConnection
+{
+ const char *ownName;
+public:
+ inline QDBusDefaultConnection(BusType type, const char *name)
+ : QDBusConnection(connectToBus(type, QString::fromLatin1(name))), ownName(name)
+ {
+ // make sure this connection is running on the main thread
+ QCoreApplication *instance = QCoreApplication::instance();
+ if (!instance) {
+ qWarning("QDBusConnection: %s D-Bus connection created before QCoreApplication. Application may misbehave.",
+ type == SessionBus ? "session" : type == SystemBus ? "system" : "generic");
+ } else {
+ QDBusConnectionPrivate::d(*this)->moveToThread(instance->thread());
+ }
+ }
+
+ inline ~QDBusDefaultConnection()
+ { disconnectFromBus(QString::fromLatin1(ownName)); }
+};
+
+Q_GLOBAL_STATIC_WITH_ARGS(QDBusDefaultConnection, _q_sessionBus,
+ (QDBusConnection::SessionBus, _q_sessionBusName))
+Q_GLOBAL_STATIC_WITH_ARGS(QDBusDefaultConnection, _q_systemBus,
+ (QDBusConnection::SystemBus, _q_systemBusName))
+
+QDBusConnection QDBusConnection::sessionBus()
+{
+ return *_q_sessionBus();
+}
+
+QDBusConnection QDBusConnection::systemBus()
+{
+ return *_q_systemBus();
+}
+
+/*!
+ \nonreentrant
+
+ Returns the connection that sent the signal, if called in a slot activated
+ by QDBus; otherwise it returns 0.
+
+ \note Please avoid this function. This function is not thread-safe, so if
+ there's any other thread delivering a D-Bus call, this function may return
+ the wrong connection. In new code, please use QDBusContext::connection()
+ (see that class for a description on how to use it).
+*/
+QDBusConnection QDBusConnection::sender()
+{
+ return QDBusConnection(_q_manager()->sender());
+}
+
+/*!
+ \internal
+*/
+void QDBusConnectionPrivate::setSender(const QDBusConnectionPrivate *s)
+{
+ _q_manager()->setSender(s);
+}
+
+/*!
+ \internal
+*/
+void QDBusConnectionPrivate::setBusService(const QDBusConnection &connection)
+{
+ busService = new QDBusConnectionInterface(connection, this);
+ ref.deref(); // busService has increased the refcounting to us
+ // avoid cyclic refcounting
+
+ QObject::connect(this, SIGNAL(callWithCallbackFailed(QDBusError,QDBusMessage)),
+ busService, SIGNAL(callWithCallbackFailed(QDBusError,QDBusMessage)),
+ Qt::QueuedConnection);
+}
+
+/*!
+ \namespace QDBus
+ \inmodule QtDBus
+
+ \brief The QDBus namespace contains miscellaneous identifiers used
+ throughout the QtDBus library.
+*/
+
+/*!
+ \enum QDBus::CallMode
+
+ This enum describes the various ways of placing a function call. The valid modes are:
+
+ \value NoBlock Place the call but don't wait for the reply (the reply's contents
+ will be discarded).
+ \value Block Don't use an event loop to wait for a reply, but instead block on
+ network operations while waiting. This means the
+ user-interface may not be updated until the function returns.
+ \value BlockWithGui Use the Qt event loop to wait for a reply. This means that the
+ user-interface will stay responsive (processing input events),
+ but it also means other events may happen, like signal delivery
+ and other D-Bus method calls.
+ \value AutoDetect Automatically detect if the called function has a reply.
+
+ When using BlockWithGui, applications must be prepared for reentrancy in any function.
+*/
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusconnection.h b/src/dbus/qdbusconnection.h
new file mode 100644
index 0000000000..15e08a780b
--- /dev/null
+++ b/src/dbus/qdbusconnection.h
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSCONNECTION_H
+#define QDBUSCONNECTION_H
+
+#include <QtDBus/qdbusmacros.h>
+#include <QtCore/qstring.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(DBus)
+
+namespace QDBus
+{
+ enum CallMode {
+ NoBlock,
+ Block,
+ BlockWithGui,
+ AutoDetect
+ };
+}
+
+class QDBusAbstractInterfacePrivate;
+class QDBusInterface;
+class QDBusError;
+class QDBusMessage;
+class QDBusPendingCall;
+class QDBusConnectionInterface;
+class QObject;
+
+class QDBusConnectionPrivate;
+class Q_DBUS_EXPORT QDBusConnection
+{
+ Q_GADGET
+ Q_ENUMS(BusType UnregisterMode)
+ Q_FLAGS(RegisterOptions)
+public:
+ enum BusType { SessionBus, SystemBus, ActivationBus };
+ enum RegisterOption {
+ ExportAdaptors = 0x01,
+
+ ExportScriptableSlots = 0x10,
+ ExportScriptableSignals = 0x20,
+ ExportScriptableProperties = 0x40,
+ ExportScriptableInvokables = 0x80,
+ ExportScriptableContents = 0xf0,
+
+ ExportNonScriptableSlots = 0x100,
+ ExportNonScriptableSignals = 0x200,
+ ExportNonScriptableProperties = 0x400,
+ ExportNonScriptableInvokables = 0x800,
+ ExportNonScriptableContents = 0xf00,
+
+ ExportAllSlots = ExportScriptableSlots|ExportNonScriptableSlots,
+ ExportAllSignals = ExportScriptableSignals|ExportNonScriptableSignals,
+ ExportAllProperties = ExportScriptableProperties|ExportNonScriptableProperties,
+ ExportAllInvokables = ExportScriptableInvokables|ExportNonScriptableInvokables,
+ ExportAllContents = ExportScriptableContents|ExportNonScriptableContents,
+
+#ifndef Q_QDOC
+ // Qt 4.2 had a misspelling here
+ ExportAllSignal = ExportAllSignals,
+#endif
+
+ ExportChildObjects = 0x1000
+ };
+ enum UnregisterMode {
+ UnregisterNode,
+ UnregisterTree
+ };
+ Q_DECLARE_FLAGS(RegisterOptions, RegisterOption)
+
+ enum ConnectionCapability {
+ UnixFileDescriptorPassing = 0x0001
+ };
+ Q_DECLARE_FLAGS(ConnectionCapabilities, ConnectionCapability)
+
+ QDBusConnection(const QString &name);
+ QDBusConnection(const QDBusConnection &other);
+ ~QDBusConnection();
+
+ QDBusConnection &operator=(const QDBusConnection &other);
+
+ bool isConnected() const;
+ QString baseService() const;
+ QDBusError lastError() const;
+ QString name() const;
+ ConnectionCapabilities connectionCapabilities() const;
+
+ bool send(const QDBusMessage &message) const;
+ bool callWithCallback(const QDBusMessage &message, QObject *receiver,
+ const char *returnMethod, const char *errorMethod,
+ int timeout = -1) const;
+ bool callWithCallback(const QDBusMessage &message, QObject *receiver,
+ const char *slot, int timeout = -1) const;
+ QDBusMessage call(const QDBusMessage &message, QDBus::CallMode mode = QDBus::Block,
+ int timeout = -1) const;
+ QDBusPendingCall asyncCall(const QDBusMessage &message, int timeout = -1) const;
+
+ bool connect(const QString &service, const QString &path, const QString &interface,
+ const QString &name, QObject *receiver, const char *slot);
+ bool connect(const QString &service, const QString &path, const QString &interface,
+ const QString &name, const QString& signature,
+ QObject *receiver, const char *slot);
+ bool connect(const QString &service, const QString &path, const QString &interface,
+ const QString &name, const QStringList &argumentMatch, const QString& signature,
+ QObject *receiver, const char *slot);
+
+ bool disconnect(const QString &service, const QString &path, const QString &interface,
+ const QString &name, QObject *receiver, const char *slot);
+ bool disconnect(const QString &service, const QString &path, const QString &interface,
+ const QString &name, const QString& signature,
+ QObject *receiver, const char *slot);
+ bool disconnect(const QString &service, const QString &path, const QString &interface,
+ const QString &name, const QStringList &argumentMatch, const QString& signature,
+ QObject *receiver, const char *slot);
+
+ bool registerObject(const QString &path, QObject *object,
+ RegisterOptions options = ExportAdaptors);
+ void unregisterObject(const QString &path, UnregisterMode mode = UnregisterNode);
+ QObject *objectRegisteredAt(const QString &path) const;
+
+ bool registerService(const QString &serviceName);
+ bool unregisterService(const QString &serviceName);
+
+ QDBusConnectionInterface *interface() const;
+
+ void *internalPointer() const;
+
+ static QDBusConnection connectToBus(BusType type, const QString &name);
+ static QDBusConnection connectToBus(const QString &address, const QString &name);
+ static QDBusConnection connectToPeer(const QString &address, const QString &name);
+ static void disconnectFromBus(const QString &name);
+ static void disconnectFromPeer(const QString &name);
+
+ static QDBusConnection sessionBus();
+ static QDBusConnection systemBus();
+
+ static QDBusConnection sender();
+
+protected:
+ explicit QDBusConnection(QDBusConnectionPrivate *dd);
+
+private:
+ friend class QDBusConnectionPrivate;
+ QDBusConnectionPrivate *d;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDBusConnection::RegisterOptions)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h
new file mode 100644
index 0000000000..355a6e6d94
--- /dev/null
+++ b/src/dbus/qdbusconnection_p.h
@@ -0,0 +1,347 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+//
+
+#ifndef QDBUSCONNECTION_P_H
+#define QDBUSCONNECTION_P_H
+
+#include <qdbuserror.h>
+#include <qdbusconnection.h>
+
+#include <QtCore/qatomic.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qreadwritelock.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qvector.h>
+
+#include "qdbus_symbols_p.h"
+
+#include <qdbusmessage.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+class QDBusMessage;
+class QSocketNotifier;
+class QTimerEvent;
+class QDBusObjectPrivate;
+class QDBusCallDeliveryEvent;
+class QDBusActivateObjectEvent;
+class QMetaMethod;
+class QDBusInterfacePrivate;
+struct QDBusMetaObject;
+class QDBusAbstractInterface;
+class QDBusConnectionInterface;
+class QDBusPendingCallPrivate;
+
+class QDBusErrorInternal
+{
+ mutable DBusError error;
+ Q_DISABLE_COPY(QDBusErrorInternal)
+public:
+ inline QDBusErrorInternal() { q_dbus_error_init(&error); }
+ inline ~QDBusErrorInternal() { q_dbus_error_free(&error); }
+ inline bool operator !() const { return !q_dbus_error_is_set(&error); }
+ inline operator DBusError *() { q_dbus_error_free(&error); return &error; }
+ inline operator QDBusError() const { QDBusError err(&error); q_dbus_error_free(&error); return err; }
+};
+
+// QDBusConnectionPrivate holds the DBusConnection and
+// can have many QDBusConnection objects referring to it
+
+class QDBusConnectionPrivate: public QObject
+{
+ Q_OBJECT
+public:
+ // structs and enums
+ enum ConnectionMode { InvalidMode, ServerMode, ClientMode, PeerMode }; // LocalMode
+
+ struct Watcher
+ {
+ Watcher(): watch(0), read(0), write(0) {}
+ DBusWatch *watch;
+ QSocketNotifier *read;
+ QSocketNotifier *write;
+ };
+
+ struct SignalHook
+ {
+ inline SignalHook() : obj(0), midx(-1) { }
+ QString service, path, signature;
+ QObject* obj;
+ int midx;
+ QList<int> params;
+ QStringList argumentMatch;
+ QByteArray matchRule;
+ };
+
+ struct ObjectTreeNode
+ {
+ typedef QVector<ObjectTreeNode> DataList;
+
+ inline ObjectTreeNode() : obj(0), flags(0) { }
+ inline ObjectTreeNode(const QString &n) // intentionally implicit
+ : name(n), obj(0), flags(0) { }
+ inline ~ObjectTreeNode() { }
+ inline bool operator<(const QString &other) const
+ { return name < other; }
+ inline bool operator<(const QStringRef &other) const
+ { return QStringRef(&name) < other; }
+
+ QString name;
+ QObject* obj;
+ int flags;
+ DataList children;
+ };
+
+public:
+ // typedefs
+ typedef QMultiHash<int, Watcher> WatcherHash;
+ typedef QHash<int, DBusTimeout *> TimeoutHash;
+ typedef QList<QPair<DBusTimeout *, int> > PendingTimeoutList;
+
+ typedef QMultiHash<QString, SignalHook> SignalHookHash;
+ typedef QHash<QString, QDBusMetaObject* > MetaObjectHash;
+ typedef QHash<QByteArray, int> MatchRefCountHash;
+
+ struct WatchedServiceData {
+ WatchedServiceData() : refcount(0) {}
+ WatchedServiceData(const QString &owner, int refcount = 0)
+ : owner(owner), refcount(refcount)
+ {}
+ QString owner;
+ int refcount;
+ };
+ typedef QHash<QString, WatchedServiceData> WatchedServicesHash;
+
+public:
+ // public methods are entry points from other objects
+ explicit QDBusConnectionPrivate(QObject *parent = 0);
+ ~QDBusConnectionPrivate();
+ void deleteYourself();
+
+ void setBusService(const QDBusConnection &connection);
+ void setPeer(DBusConnection *connection, const QDBusErrorInternal &error);
+ void setConnection(DBusConnection *connection, const QDBusErrorInternal &error);
+ void setServer(DBusServer *server, const QDBusErrorInternal &error);
+ void closeConnection();
+
+ QString getNameOwner(const QString &service);
+
+ int send(const QDBusMessage &message);
+ QDBusMessage sendWithReply(const QDBusMessage &message, int mode, int timeout = -1);
+ QDBusMessage sendWithReplyLocal(const QDBusMessage &message);
+ QDBusPendingCallPrivate *sendWithReplyAsync(const QDBusMessage &message, int timeout = -1);
+ int sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
+ const char *returnMethod, const char *errorMethod, int timeout = -1);
+ bool connectSignal(const QString &service, const QString &path, const QString& interface,
+ const QString &name, const QStringList &argumentMatch, const QString &signature,
+ QObject *receiver, const char *slot);
+ void connectSignal(const QString &key, const SignalHook &hook);
+ SignalHookHash::Iterator disconnectSignal(SignalHookHash::Iterator &it);
+ bool disconnectSignal(const QString &service, const QString &path, const QString& interface,
+ const QString &name, const QStringList &argumentMatch, const QString &signature,
+ QObject *receiver, const char *slot);
+ void registerObject(const ObjectTreeNode *node);
+ void connectRelay(const QString &service,
+ const QString &path, const QString &interface,
+ QDBusAbstractInterface *receiver, const char *signal);
+ void disconnectRelay(const QString &service,
+ const QString &path, const QString &interface,
+ QDBusAbstractInterface *receiver, const char *signal);
+ void registerService(const QString &serviceName);
+ void unregisterService(const QString &serviceName);
+
+ bool handleMessage(const QDBusMessage &msg);
+ void waitForFinished(QDBusPendingCallPrivate *pcall);
+
+ QDBusMetaObject *findMetaObject(const QString &service, const QString &path,
+ const QString &interface, QDBusError &error);
+
+ void postEventToThread(int action, QObject *target, QEvent *event);
+
+ inline void serverConnection(const QDBusConnection &connection)
+ { emit newServerConnection(connection); }
+
+private:
+ void checkThread();
+ bool handleError(const QDBusErrorInternal &error);
+
+ void handleSignal(const QString &key, const QDBusMessage &msg);
+ void handleSignal(const QDBusMessage &msg);
+ void handleObjectCall(const QDBusMessage &message);
+
+ void activateSignal(const SignalHook& hook, const QDBusMessage &msg);
+ void activateObject(ObjectTreeNode &node, const QDBusMessage &msg, int pathStartPos);
+ bool activateInternalFilters(const ObjectTreeNode &node, const QDBusMessage &msg);
+ bool activateCall(QObject *object, int flags, const QDBusMessage &msg);
+
+ void sendError(const QDBusMessage &msg, QDBusError::ErrorType code);
+ void deliverCall(QObject *object, int flags, const QDBusMessage &msg,
+ const QList<int> &metaTypes, int slotIdx);
+
+ bool isServiceRegisteredByThread(const QString &serviceName) const;
+
+ QString getNameOwnerNoCache(const QString &service);
+
+protected:
+ void customEvent(QEvent *e);
+ void timerEvent(QTimerEvent *e);
+
+public slots:
+ // public slots
+ void doDispatch();
+ void socketRead(int);
+ void socketWrite(int);
+ void objectDestroyed(QObject *o);
+ void relaySignal(QObject *obj, const QMetaObject *, int signalId, const QVariantList &args);
+
+private slots:
+ void serviceOwnerChangedNoLock(const QString &name, const QString &oldOwner, const QString &newOwner);
+ void registerServiceNoLock(const QString &serviceName);
+ void unregisterServiceNoLock(const QString &serviceName);
+
+signals:
+ void serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
+ void callWithCallbackFailed(const QDBusError &error, const QDBusMessage &message);
+ void newServerConnection(const QDBusConnection &connection);
+
+public:
+ QAtomicInt ref;
+ QDBusConnection::ConnectionCapabilities capabilities;
+ QString name; // this connection's name
+ QString baseService; // this connection's base service
+
+ ConnectionMode mode;
+
+ // members accessed in unlocked mode (except for deletion)
+ // connection and server provide their own locking mechanisms
+ // busService doesn't have state to be changed
+ DBusConnection *connection;
+ DBusServer *server;
+ QDBusConnectionInterface *busService;
+
+ // watchers and timeouts are accessed from any thread
+ // but the corresponding timer and QSocketNotifier must be handled
+ // only in the object's thread
+ QMutex watchAndTimeoutLock;
+ WatcherHash watchers;
+ TimeoutHash timeouts;
+ PendingTimeoutList timeoutsPendingAdd;
+
+ // members accessed through a lock
+ QMutex dispatchLock;
+ QReadWriteLock lock;
+ QDBusError lastError;
+
+ QStringList serviceNames;
+ WatchedServicesHash watchedServices;
+ SignalHookHash signalHooks;
+ MatchRefCountHash matchRefCounts;
+ ObjectTreeNode rootNode;
+ MetaObjectHash cachedMetaObjects;
+
+ QMutex callDeliveryMutex;
+ QDBusCallDeliveryEvent *callDeliveryState; // protected by the callDeliveryMutex mutex
+
+public:
+ // static methods
+ static int findSlot(QObject *obj, const QByteArray &normalizedName, QList<int>& params);
+ static bool prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
+ const QString &service,
+ const QString &path, const QString &interface, const QString &name,
+ const QStringList &argMatch,
+ QObject *receiver, const char *signal, int minMIdx,
+ bool buildSignature);
+ static DBusHandlerResult messageFilter(DBusConnection *, DBusMessage *, void *);
+ static bool checkReplyForDelivery(QDBusConnectionPrivate *target, QObject *object,
+ int idx, const QList<int> &metaTypes,
+ const QDBusMessage &msg);
+ static QDBusCallDeliveryEvent *prepareReply(QDBusConnectionPrivate *target, QObject *object,
+ int idx, const QList<int> &metaTypes,
+ const QDBusMessage &msg);
+ static void processFinishedCall(QDBusPendingCallPrivate *call);
+
+ static QDBusConnectionPrivate *d(const QDBusConnection& q) { return q.d; }
+ static QDBusConnection q(QDBusConnectionPrivate *connection) { return QDBusConnection(connection); }
+
+ static void setSender(const QDBusConnectionPrivate *s);
+
+ friend class QDBusActivateObjectEvent;
+ friend class QDBusCallDeliveryEvent;
+};
+
+// in qdbusmisc.cpp
+extern int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes);
+extern int qDBusNameToTypeId(const char *name);
+extern bool qDBusCheckAsyncTag(const char *tag);
+extern bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name);
+extern QString qDBusInterfaceFromMetaObject(const QMetaObject *mo);
+
+// in qdbusinternalfilters.cpp
+extern QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode &node);
+extern QDBusMessage qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode &node,
+ const QDBusMessage &msg);
+extern QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode &node,
+ const QDBusMessage &msg);
+extern QDBusMessage qDBusPropertyGetAll(const QDBusConnectionPrivate::ObjectTreeNode &node,
+ const QDBusMessage &msg);
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusconnectioninterface.cpp b/src/dbus/qdbusconnectioninterface.cpp
new file mode 100644
index 0000000000..92263356c3
--- /dev/null
+++ b/src/dbus/qdbusconnectioninterface.cpp
@@ -0,0 +1,419 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusconnectioninterface.h"
+
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+#include <QtCore/QDebug>
+
+#include "qdbus_symbols_p.h" // for the DBUS_* constants
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+/*
+ * Implementation of interface class QDBusConnectionInterface
+ */
+
+/*!
+ \class QDBusConnectionInterface
+ \inmodule QtDBus
+ \since 4.2
+
+ \brief The QDBusConnectionInterface class provides access to the D-Bus bus daemon service.
+
+ The D-Bus bus server daemon provides one special interface \c
+ org.freedesktop.DBus that allows clients to access certain
+ properties of the bus, such as the current list of clients
+ connected. The QDBusConnectionInterface class provides access to that
+ interface.
+
+ The most common uses of this class are to register and unregister
+ service names on the bus using the registerService() and
+ unregisterService() functions, query about existing names using
+ the isServiceRegistered(), registeredServiceNames() and
+ serviceOwner() functions, and to receive notification that a
+ client has registered or de-registered through the
+ serviceRegistered(), serviceUnregistered() and serviceOwnerChanged()
+ signals.
+*/
+
+/*!
+ \enum QDBusConnectionInterface::ServiceQueueOptions
+
+ Flags for determining how a service registration should behave, in
+ case the service name is already registered.
+
+ \value DontQueueService If an application requests a name that
+ is already owned, no queueing will be
+ performed. The registeredService()
+ call will simply fail.
+ This is the default.
+
+ \value QueueService Attempts to register the requested
+ service, but do not try to replace it
+ if another application already has it
+ registered. Instead, simply put this
+ application in queue, until it is
+ given up. The serviceRegistered()
+ signal will be emitted when that
+ happens.
+
+ \value ReplaceExistingService If another application already has
+ the service name registered, attempt
+ to replace it.
+
+ \sa ServiceReplacementOptions
+*/
+
+/*!
+ \enum QDBusConnectionInterface::ServiceReplacementOptions
+
+ Flags for determining if the D-Bus server should allow another
+ application to replace a name that this application has registered
+ with the ReplaceExistingService option.
+
+ The possible values are:
+
+ \value DontAllowReplacement Do not allow another application to
+ replace us. The service must be
+ explicitly unregistered with
+ unregisterService() for another
+ application to acquire it.
+ This is the default.
+
+ \value AllowReplacement Allow other applications to replace us
+ with the ReplaceExistingService option
+ to registerService() without
+ intervention. If that happens, the
+ serviceUnregistered() signal will be
+ emitted.
+
+ \sa ServiceQueueOptions
+*/
+
+/*!
+ \enum QDBusConnectionInterface::RegisterServiceReply
+
+ The possible return values from registerService():
+
+ \value ServiceNotRegistered The call failed and the service name was not registered.
+ \value ServiceRegistered The caller is now the owner of the service name.
+ \value ServiceQueued The caller specified the QueueService flag and the
+ service was already registered, so we are in queue.
+
+ The serviceRegistered() signal will be emitted when the service is
+ acquired by this application.
+*/
+
+/*!
+ \internal
+*/
+const char *QDBusConnectionInterface::staticInterfaceName()
+{ return "org.freedesktop.DBus"; }
+
+/*!
+ \internal
+*/
+QDBusConnectionInterface::QDBusConnectionInterface(const QDBusConnection &connection,
+ QObject *parent)
+ : QDBusAbstractInterface(QLatin1String(DBUS_SERVICE_DBUS),
+ QLatin1String(DBUS_PATH_DBUS),
+ DBUS_INTERFACE_DBUS, connection, parent)
+{
+ connect(this, SIGNAL(NameAcquired(QString)), this, SIGNAL(serviceRegistered(QString)));
+ connect(this, SIGNAL(NameLost(QString)), this, SIGNAL(serviceUnregistered(QString)));
+ connect(this, SIGNAL(NameOwnerChanged(QString,QString,QString)),
+ this, SIGNAL(serviceOwnerChanged(QString,QString,QString)));
+}
+
+/*!
+ \internal
+*/
+QDBusConnectionInterface::~QDBusConnectionInterface()
+{
+}
+
+/*!
+ Returns the unique connection name of the primary owner of the
+ name \a name. If the requested name doesn't have an owner, returns
+ a \c org.freedesktop.DBus.Error.NameHasNoOwner error.
+*/
+QDBusReply<QString> QDBusConnectionInterface::serviceOwner(const QString &name) const
+{
+ return internalConstCall(QDBus::AutoDetect, QLatin1String("GetNameOwner"), QList<QVariant>() << name);
+}
+
+/*!
+ \property QDBusConnectionInterface::registeredServiceNames
+ \brief holds the registered service names
+
+ Lists all names currently registered on the bus.
+*/
+QDBusReply<QStringList> QDBusConnectionInterface::registeredServiceNames() const
+{
+ return internalConstCall(QDBus::AutoDetect, QLatin1String("ListNames"));
+}
+
+/*!
+ Returns true if the service name \a serviceName has is currently
+ registered.
+*/
+QDBusReply<bool> QDBusConnectionInterface::isServiceRegistered(const QString &serviceName) const
+{
+ return internalConstCall(QDBus::AutoDetect, QLatin1String("NameHasOwner"),
+ QList<QVariant>() << serviceName);
+}
+
+/*!
+ Returns the Unix Process ID (PID) for the process currently
+ holding the bus service \a serviceName.
+*/
+QDBusReply<uint> QDBusConnectionInterface::servicePid(const QString &serviceName) const
+{
+ return internalConstCall(QDBus::AutoDetect, QLatin1String("GetConnectionUnixProcessID"),
+ QList<QVariant>() << serviceName);
+}
+
+/*!
+ Returns the Unix User ID (UID) for the process currently holding
+ the bus service \a serviceName.
+*/
+QDBusReply<uint> QDBusConnectionInterface::serviceUid(const QString &serviceName) const
+{
+ return internalConstCall(QDBus::AutoDetect, QLatin1String("GetConnectionUnixUser"),
+ QList<QVariant>() << serviceName);
+}
+
+/*!
+ Requests that the bus start the service given by the name \a name.
+*/
+QDBusReply<void> QDBusConnectionInterface::startService(const QString &name)
+{
+ return call(QLatin1String("StartServiceByName"), name, uint(0));
+}
+
+/*!
+ Requests to register the service name \a serviceName on the
+ bus. The \a qoption flag specifies how the D-Bus server should behave
+ if \a serviceName is already registered. The \a roption flag
+ specifies if the server should allow another application to
+ replace our registered name.
+
+ If the service registration succeeds, the serviceRegistered()
+ signal will be emitted. If we are placed in queue, the signal will
+ be emitted when we obtain the name. If \a roption is
+ AllowReplacement, the serviceUnregistered() signal will be emitted
+ if another application replaces this one.
+
+ \sa unregisterService()
+*/
+QDBusReply<QDBusConnectionInterface::RegisterServiceReply>
+QDBusConnectionInterface::registerService(const QString &serviceName,
+ ServiceQueueOptions qoption,
+ ServiceReplacementOptions roption)
+{
+ // reconstruct the low-level flags
+ uint flags = 0;
+ switch (qoption) {
+ case DontQueueService:
+ flags = DBUS_NAME_FLAG_DO_NOT_QUEUE;
+ break;
+ case QueueService:
+ flags = 0;
+ break;
+ case ReplaceExistingService:
+ flags = DBUS_NAME_FLAG_DO_NOT_QUEUE | DBUS_NAME_FLAG_REPLACE_EXISTING;
+ break;
+ }
+
+ switch (roption) {
+ case DontAllowReplacement:
+ break;
+ case AllowReplacement:
+ flags |= DBUS_NAME_FLAG_ALLOW_REPLACEMENT;
+ break;
+ }
+
+ QDBusMessage reply = call(QLatin1String("RequestName"), serviceName, flags);
+// qDebug() << "QDBusConnectionInterface::registerService" << serviceName << "Reply:" << reply;
+
+ // convert the low-level flags to something that we can use
+ if (reply.type() == QDBusMessage::ReplyMessage) {
+ uint code = 0;
+
+ switch (reply.arguments().at(0).toUInt()) {
+ case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
+ case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
+ code = uint(ServiceRegistered);
+ break;
+
+ case DBUS_REQUEST_NAME_REPLY_EXISTS:
+ code = uint(ServiceNotRegistered);
+ break;
+
+ case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
+ code = uint(ServiceQueued);
+ break;
+ }
+
+ reply.setArguments(QVariantList() << code);
+ }
+
+ return reply;
+}
+
+/*!
+ Releases the claim on the bus service name \a serviceName, that
+ had been previously registered with registerService(). If this
+ application had ownership of the name, it will be released for
+ other applications to claim. If it only had the name queued, it
+ gives up its position in the queue.
+*/
+QDBusReply<bool>
+QDBusConnectionInterface::unregisterService(const QString &serviceName)
+{
+ QDBusMessage reply = call(QLatin1String("ReleaseName"), serviceName);
+ if (reply.type() == QDBusMessage::ReplyMessage) {
+ bool success = reply.arguments().at(0).toUInt() == DBUS_RELEASE_NAME_REPLY_RELEASED;
+ reply.setArguments(QVariantList() << success);
+ }
+ return reply;
+}
+
+/*!
+ \internal
+*/
+void QDBusConnectionInterface::connectNotify(const char *signalName)
+{
+ // translate the signal names to what we really want
+ // this avoids setting hooks for signals that don't exist on the bus
+ if (qstrcmp(signalName, SIGNAL(serviceRegistered(QString))) == 0)
+ QDBusAbstractInterface::connectNotify(SIGNAL(NameAcquired(QString)));
+
+ else if (qstrcmp(signalName, SIGNAL(serviceUnregistered(QString))) == 0)
+ QDBusAbstractInterface::connectNotify(SIGNAL(NameLost(QString)));
+
+ else if (qstrcmp(signalName, SIGNAL(serviceOwnerChanged(QString,QString,QString))) == 0) {
+ static bool warningPrinted = false;
+ if (!warningPrinted) {
+ qWarning("Connecting to deprecated signal QDBusConnectionInterface::serviceOwnerChanged(QString,QString,QString)");
+ warningPrinted = true;
+ }
+ QDBusAbstractInterface::connectNotify(SIGNAL(NameOwnerChanged(QString,QString,QString)));
+ }
+}
+
+/*!
+ \internal
+*/
+void QDBusConnectionInterface::disconnectNotify(const char *signalName)
+{
+ // translate the signal names to what we really want
+ // this avoids setting hooks for signals that don't exist on the bus
+ if (qstrcmp(signalName, SIGNAL(serviceRegistered(QString))) == 0)
+ QDBusAbstractInterface::disconnectNotify(SIGNAL(NameAcquired(QString)));
+
+ else if (qstrcmp(signalName, SIGNAL(serviceUnregistered(QString))) == 0)
+ QDBusAbstractInterface::disconnectNotify(SIGNAL(NameLost(QString)));
+
+ else if (qstrcmp(signalName, SIGNAL(serviceOwnerChanged(QString,QString,QString))) == 0)
+ QDBusAbstractInterface::disconnectNotify(SIGNAL(NameOwnerChanged(QString,QString,QString)));
+}
+
+// signals
+/*!
+ \fn QDBusConnectionInterface::serviceRegistered(const QString &serviceName)
+
+ This signal is emitted by the D-Bus server when the bus service
+ name (unique connection name or well-known service name) given by
+ \a serviceName is acquired by this application.
+
+ Acquisition happens after this application has requested a name using
+ registerService().
+*/
+
+/*!
+ \fn QDBusConnectionInterface::serviceUnregistered(const QString &serviceName)
+
+ This signal is emitted by the D-Bus server when this application
+ loses ownership of the bus service name given by \a serviceName.
+*/
+
+/*!
+ \fn QDBusConnectionInterface::serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner)
+
+ This signal is emitted by the D-Bus server whenever a service
+ ownership change happens in the bus, including apparition and
+ disparition of names.
+
+ This signal means the application \a oldOwner lost ownership of
+ bus name \a name to application \a newOwner. If \a oldOwner is an
+ empty string, it means the name \a name has just been created; if
+ \a newOwner is empty, the name \a name has no current owner and is
+ no longer available.
+
+ \note connecting to this signal will make the application listen for and
+ receive every single service ownership change on the bus. Depending on
+ how many services are running, this make the application be activated to
+ receive more signals than it needs. To avoid this problem, use the
+ QDBusServiceWatcher class, which can listen for specific changes.
+*/
+
+/*!
+ \fn void QDBusConnectionInterface::callWithCallbackFailed(const QDBusError &error, const QDBusMessage &call)
+
+ This signal is emitted when there is an error during a
+ QDBusConnection::callWithCallback(). \a error specifies the error.
+ \a call is the message that couldn't be delivered.
+
+ \sa QDBusConnection::callWithCallback()
+ */
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusconnectioninterface.h b/src/dbus/qdbusconnectioninterface.h
new file mode 100644
index 0000000000..3e94500ef5
--- /dev/null
+++ b/src/dbus/qdbusconnectioninterface.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSBUS_H
+#define QDBUSBUS_H
+
+#include <QtCore/qstringlist.h>
+
+#include <QtDBus/qdbusabstractinterface.h>
+#include <QtDBus/qdbusreply.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(DBus)
+
+class QDBusConnection;
+class QString;
+class QByteArray;
+
+/*
+ * Proxy class for interface org.freedesktop.DBus
+ */
+class Q_DBUS_EXPORT QDBusConnectionInterface: public QDBusAbstractInterface
+{
+ Q_OBJECT
+ Q_ENUMS(ServiceQueueOptions ServiceReplacementOptions RegisterServiceReply)
+ friend class QDBusConnectionPrivate;
+ static inline const char *staticInterfaceName();
+
+ explicit QDBusConnectionInterface(const QDBusConnection &connection, QObject *parent);
+ ~QDBusConnectionInterface();
+
+ Q_PROPERTY(QDBusReply<QStringList> registeredServiceNames READ registeredServiceNames)
+
+public:
+ enum ServiceQueueOptions {
+ DontQueueService,
+ QueueService,
+ ReplaceExistingService
+ };
+ enum ServiceReplacementOptions {
+ DontAllowReplacement,
+ AllowReplacement
+ };
+ enum RegisterServiceReply {
+ ServiceNotRegistered = 0,
+ ServiceRegistered,
+ ServiceQueued
+ };
+
+public Q_SLOTS:
+ QDBusReply<QStringList> registeredServiceNames() const;
+ QDBusReply<bool> isServiceRegistered(const QString &serviceName) const;
+ QDBusReply<QString> serviceOwner(const QString &name) const;
+ QDBusReply<bool> unregisterService(const QString &serviceName);
+ QDBusReply<QDBusConnectionInterface::RegisterServiceReply> registerService(const QString &serviceName,
+ ServiceQueueOptions qoption = DontQueueService,
+ ServiceReplacementOptions roption = DontAllowReplacement);
+
+ QDBusReply<uint> servicePid(const QString &serviceName) const;
+ QDBusReply<uint> serviceUid(const QString &serviceName) const;
+
+ QDBusReply<void> startService(const QString &name);
+
+Q_SIGNALS:
+ void serviceRegistered(const QString &service);
+ void serviceUnregistered(const QString &service);
+ void serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
+ void callWithCallbackFailed(const QDBusError &error, const QDBusMessage &call);
+
+#ifndef Q_QDOC
+ // internal signals
+ // do not use
+ void NameAcquired(const QString &);
+ void NameLost(const QString &);
+ void NameOwnerChanged(const QString &, const QString &, const QString &);
+protected:
+ void connectNotify(const char *);
+ void disconnectNotify(const char *);
+#endif
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_BUILTIN_METATYPE(QDBusConnectionInterface::RegisterServiceReply, UInt)
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusconnectionmanager_p.h b/src/dbus/qdbusconnectionmanager_p.h
new file mode 100644
index 0000000000..dd8b4aad64
--- /dev/null
+++ b/src/dbus/qdbusconnectionmanager_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+//
+
+#ifndef QDBUSCONNECTIONMANAGER_P_H
+#define QDBUSCONNECTIONMANAGER_P_H
+
+#include "qdbusconnection_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+class QDBusConnectionManager
+{
+public:
+ QDBusConnectionManager() {}
+ ~QDBusConnectionManager();
+ static QDBusConnectionManager* instance();
+
+ QDBusConnectionPrivate *connection(const QString &name) const;
+ void removeConnection(const QString &name);
+ void setConnection(const QString &name, QDBusConnectionPrivate *c);
+
+ QDBusConnectionPrivate *sender() const;
+ void setSender(const QDBusConnectionPrivate *s);
+
+ mutable QMutex mutex;
+private:
+ QHash<QString, QDBusConnectionPrivate *> connectionHash;
+
+ mutable QMutex senderMutex;
+ QString senderName; // internal; will probably change
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbuscontext.cpp b/src/dbus/qdbuscontext.cpp
new file mode 100644
index 0000000000..f3f3e69caf
--- /dev/null
+++ b/src/dbus/qdbuscontext.cpp
@@ -0,0 +1,208 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusmessage.h"
+#include "qdbusconnection.h"
+#include "qdbusabstractadaptor.h"
+
+#include "qdbuscontext.h"
+#include "qdbuscontext_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+QDBusContextPrivate *QDBusContextPrivate::set(QObject *obj, QDBusContextPrivate *newContext)
+{
+ // determine if this is an adaptor or not
+ if (qobject_cast<QDBusAbstractAdaptor *>(obj))
+ obj = obj->parent();
+
+ Q_ASSERT(obj);
+
+ void *ptr = obj->qt_metacast("QDBusContext");
+ QDBusContext *q_ptr = reinterpret_cast<QDBusContext *>(ptr);
+ if (q_ptr) {
+ QDBusContextPrivate *old = q_ptr->d_ptr;
+ q_ptr->d_ptr = newContext;
+ return old;
+ }
+
+ return 0;
+}
+
+/*!
+ \since 4.3
+ \class QDBusContext
+ \inmodule QtDBus
+
+ \brief The QDBusContext class allows slots to determine the D-Bus context of the calls.
+
+ When a slot is called in an object due to a signal delivery or due
+ to a remote method call, it is sometimes necessary to know the
+ context in which that happened. In particular, if the slot
+ determines that it wants to send the reply at a later opportunity
+ or if it wants to reply with an error, the context is needed.
+
+ The QDBusContext class is an alternative to accessing the context
+ that doesn't involve modifying the code generated by the \l
+ {QtDBus XML Compiler (qdbusxml2cpp)}.
+
+ QDBusContext is used by subclassing it from the objects being
+ exported using QDBusConnection::registerObject(). The following
+ example illustrates the usage:
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbuscontext.cpp 0
+
+ The example illustrates the two typical uses, that of sending
+ error replies and that of delayed replies.
+
+ Note: do not subclass QDBusContext and QDBusAbstractAdaptor at the
+ same time. QDBusContext should appear in the real object, not the
+ adaptor. If it's necessary from the adaptor code to determine the
+ context, use a public inheritance and access the functions via
+ QObject::parent().
+*/
+
+/*!
+ Constructs an empty QDBusContext.
+ */
+QDBusContext::QDBusContext()
+ : d_ptr(0)
+{
+}
+
+/*!
+ An empty destructor.
+ */
+QDBusContext::~QDBusContext()
+{
+}
+
+/*!
+ Returns true if we are processing a D-Bus call. If this function
+ returns true, the rest of the functions in this class are
+ available.
+
+ Accessing those functions when this function returns false is
+ undefined and may lead to crashes.
+*/
+bool QDBusContext::calledFromDBus() const
+{
+ return d_ptr;
+}
+
+/*!
+ Returns the connection from which this call was received.
+*/
+QDBusConnection QDBusContext::connection() const
+{
+ return d_ptr->connection;
+}
+
+/*!
+ Returns the message that generated this call.
+*/
+const QDBusMessage &QDBusContext::message() const
+{
+ return d_ptr->message;
+}
+
+/*!
+ Returns true if this call will have a delayed reply.
+
+ \sa setDelayedReply()
+*/
+bool QDBusContext::isDelayedReply() const
+{
+ return message().isDelayedReply();
+}
+
+/*!
+ Sets whether this call will have a delayed reply or not.
+
+ If \a enable is false, QtDBus will automatically generate a reply
+ back to the caller, if needed, as soon as the called slot returns.
+
+ If \a enable is true, QtDBus will not generate automatic
+ replies. It will also ignore the return value from the slot and
+ any output parameters. Instead, the called object is responsible
+ for storing the incoming message and send a reply or error at a
+ later time.
+
+ Failing to send a reply will result in an automatic timeout error
+ being generated by D-Bus.
+*/
+void QDBusContext::setDelayedReply(bool enable) const
+{
+ message().setDelayedReply(enable);
+}
+
+/*!
+ Sends an error \a name as a reply to the caller. The optional \a
+ msg parameter is a human-readable text explaining the failure.
+
+ If an error is sent, the return value and any output parameters
+ from the called slot will be ignored by QtDBus.
+*/
+void QDBusContext::sendErrorReply(const QString &name, const QString &msg) const
+{
+ setDelayedReply(true);
+ connection().send(message().createErrorReply(name, msg));
+}
+
+/*!
+ \overload
+ Sends an error \a type as a reply to the caller. The optional \a
+ msg parameter is a human-readable text explaining the failure.
+
+ If an error is sent, the return value and any output parameters
+ from the called slot will be ignored by QtDBus.
+*/
+void QDBusContext::sendErrorReply(QDBusError::ErrorType type, const QString &msg) const
+{
+ setDelayedReply(true);
+ connection().send(message().createErrorReply(type, msg));
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbuscontext.h b/src/dbus/qdbuscontext.h
new file mode 100644
index 0000000000..d7777488ed
--- /dev/null
+++ b/src/dbus/qdbuscontext.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSCONTEXT_H
+#define QDBUSCONTEXT_H
+
+#include <QtCore/qstring.h>
+#include <QtDBus/qdbuserror.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(DBus)
+
+class QDBusConnection;
+class QDBusMessage;
+
+class QDBusContextPrivate;
+class Q_DBUS_EXPORT QDBusContext
+{
+public:
+ QDBusContext();
+ ~QDBusContext();
+
+ bool calledFromDBus() const;
+ QDBusConnection connection() const;
+ const QDBusMessage &message() const;
+
+ // convenience methods
+ bool isDelayedReply() const;
+ // yes, they are const, so that you can use them even from const methods
+ void setDelayedReply(bool enable) const;
+ void sendErrorReply(const QString &name, const QString &msg = QString()) const;
+ void sendErrorReply(QDBusError::ErrorType type, const QString &msg = QString()) const;
+
+private:
+ QDBusContextPrivate *d_ptr;
+ friend class QDBusContextPrivate;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbuscontext_p.h b/src/dbus/qdbuscontext_p.h
new file mode 100644
index 0000000000..53ff9d08d1
--- /dev/null
+++ b/src/dbus/qdbuscontext_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+//
+
+#ifndef QDBUSCONTEXT_P_H
+#define QDBUSCONTEXT_P_H
+
+#include <QtCore/qglobal.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+class QDBusMessage;
+class QDBusConnection;
+
+class QDBusContext;
+class QDBusContextPrivate
+{
+public:
+ inline QDBusContextPrivate(const QDBusConnection &conn, const QDBusMessage &msg)
+ : connection(conn), message(msg) {}
+
+ QDBusConnection connection;
+ const QDBusMessage &message;
+
+ static QDBusContextPrivate *set(QObject *obj, QDBusContextPrivate *newContext);
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
+#endif
+
diff --git a/src/dbus/qdbusdemarshaller.cpp b/src/dbus/qdbusdemarshaller.cpp
new file mode 100644
index 0000000000..3910381284
--- /dev/null
+++ b/src/dbus/qdbusdemarshaller.cpp
@@ -0,0 +1,364 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusargument_p.h"
+#include "qdbusconnection.h"
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+template <typename T>
+static inline T qIterGet(DBusMessageIter *it)
+{
+ T t;
+ q_dbus_message_iter_get_basic(it, &t);
+ q_dbus_message_iter_next(it);
+ return t;
+}
+
+QDBusDemarshaller::~QDBusDemarshaller()
+{
+}
+
+inline QString QDBusDemarshaller::currentSignature()
+{
+ char *sig = q_dbus_message_iter_get_signature(&iterator);
+ QString retval = QString::fromUtf8(sig);
+ q_dbus_free(sig);
+
+ return retval;
+}
+
+inline uchar QDBusDemarshaller::toByte()
+{
+ return qIterGet<uchar>(&iterator);
+}
+
+inline bool QDBusDemarshaller::toBool()
+{
+ return bool(qIterGet<dbus_bool_t>(&iterator));
+}
+
+inline ushort QDBusDemarshaller::toUShort()
+{
+ return qIterGet<dbus_uint16_t>(&iterator);
+}
+
+inline short QDBusDemarshaller::toShort()
+{
+ return qIterGet<dbus_int16_t>(&iterator);
+}
+
+inline int QDBusDemarshaller::toInt()
+{
+ return qIterGet<dbus_int32_t>(&iterator);
+}
+
+inline uint QDBusDemarshaller::toUInt()
+{
+ return qIterGet<dbus_uint32_t>(&iterator);
+}
+
+inline qlonglong QDBusDemarshaller::toLongLong()
+{
+ return qIterGet<qlonglong>(&iterator);
+}
+
+inline qulonglong QDBusDemarshaller::toULongLong()
+{
+ return qIterGet<qulonglong>(&iterator);
+}
+
+inline double QDBusDemarshaller::toDouble()
+{
+ return qIterGet<double>(&iterator);
+}
+
+inline QString QDBusDemarshaller::toString()
+{
+ return QString::fromUtf8(qIterGet<char *>(&iterator));
+}
+
+inline QDBusObjectPath QDBusDemarshaller::toObjectPath()
+{
+ return QDBusObjectPath(QString::fromUtf8(qIterGet<char *>(&iterator)));
+}
+
+inline QDBusSignature QDBusDemarshaller::toSignature()
+{
+ return QDBusSignature(QString::fromUtf8(qIterGet<char *>(&iterator)));
+}
+
+inline QDBusUnixFileDescriptor QDBusDemarshaller::toUnixFileDescriptor()
+{
+ QDBusUnixFileDescriptor fd;
+ fd.giveFileDescriptor(qIterGet<dbus_int32_t>(&iterator));
+ return fd;
+}
+
+inline QDBusVariant QDBusDemarshaller::toVariant()
+{
+ QDBusDemarshaller sub(capabilities);
+ sub.message = q_dbus_message_ref(message);
+ q_dbus_message_iter_recurse(&iterator, &sub.iterator);
+ q_dbus_message_iter_next(&iterator);
+
+ return QDBusVariant( sub.toVariantInternal() );
+}
+
+QDBusArgument::ElementType QDBusDemarshaller::currentType()
+{
+ switch (q_dbus_message_iter_get_arg_type(&iterator)) {
+ case DBUS_TYPE_BYTE:
+ case DBUS_TYPE_INT16:
+ case DBUS_TYPE_UINT16:
+ case DBUS_TYPE_INT32:
+ case DBUS_TYPE_UINT32:
+ case DBUS_TYPE_INT64:
+ case DBUS_TYPE_UINT64:
+ case DBUS_TYPE_BOOLEAN:
+ case DBUS_TYPE_DOUBLE:
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ return QDBusArgument::BasicType;
+
+ case DBUS_TYPE_VARIANT:
+ return QDBusArgument::VariantType;
+
+ case DBUS_TYPE_ARRAY:
+ switch (q_dbus_message_iter_get_element_type(&iterator)) {
+ case DBUS_TYPE_BYTE:
+ case DBUS_TYPE_STRING:
+ // QByteArray and QStringList
+ return QDBusArgument::BasicType;
+ case DBUS_TYPE_DICT_ENTRY:
+ return QDBusArgument::MapType;
+ default:
+ return QDBusArgument::ArrayType;
+ }
+
+ case DBUS_TYPE_STRUCT:
+ return QDBusArgument::StructureType;
+ case DBUS_TYPE_DICT_ENTRY:
+ return QDBusArgument::MapEntryType;
+
+ case DBUS_TYPE_UNIX_FD:
+ return capabilities & QDBusConnection::UnixFileDescriptorPassing ?
+ QDBusArgument::BasicType : QDBusArgument::UnknownType;
+
+ case DBUS_TYPE_INVALID:
+ return QDBusArgument::UnknownType;
+
+// default:
+// qWarning("QDBusDemarshaller: Found unknown D-Bus type %d '%c'",
+// q_dbus_message_iter_get_arg_type(&iterator),
+// q_dbus_message_iter_get_arg_type(&iterator));
+ }
+ return QDBusArgument::UnknownType;
+}
+
+QVariant QDBusDemarshaller::toVariantInternal()
+{
+ switch (q_dbus_message_iter_get_arg_type(&iterator)) {
+ case DBUS_TYPE_BYTE:
+ return QVariant::fromValue(toByte());
+ case DBUS_TYPE_INT16:
+ return QVariant::fromValue(toShort());
+ case DBUS_TYPE_UINT16:
+ return QVariant::fromValue(toUShort());
+ case DBUS_TYPE_INT32:
+ return toInt();
+ case DBUS_TYPE_UINT32:
+ return toUInt();
+ case DBUS_TYPE_DOUBLE:
+ return toDouble();
+ case DBUS_TYPE_BOOLEAN:
+ return toBool();
+ case DBUS_TYPE_INT64:
+ return toLongLong();
+ case DBUS_TYPE_UINT64:
+ return toULongLong();
+ case DBUS_TYPE_STRING:
+ return toString();
+ case DBUS_TYPE_OBJECT_PATH:
+ return QVariant::fromValue(toObjectPath());
+ case DBUS_TYPE_SIGNATURE:
+ return QVariant::fromValue(toSignature());
+ case DBUS_TYPE_VARIANT:
+ return QVariant::fromValue(toVariant());
+
+ case DBUS_TYPE_ARRAY:
+ switch (q_dbus_message_iter_get_element_type(&iterator)) {
+ case DBUS_TYPE_BYTE:
+ // QByteArray
+ return toByteArray();
+ case DBUS_TYPE_STRING:
+ return toStringList();
+ case DBUS_TYPE_DICT_ENTRY:
+ return QVariant::fromValue(duplicate());
+
+ default:
+ return QVariant::fromValue(duplicate());
+ }
+
+ case DBUS_TYPE_STRUCT:
+ return QVariant::fromValue(duplicate());
+
+ case DBUS_TYPE_UNIX_FD:
+ if (capabilities & QDBusConnection::UnixFileDescriptorPassing)
+ return qVariantFromValue(toUnixFileDescriptor());
+ // fall through
+
+ default:
+// qWarning("QDBusDemarshaller: Found unknown D-Bus type %d '%c'",
+// q_dbus_message_iter_get_arg_type(&iterator),
+// q_dbus_message_iter_get_arg_type(&iterator));
+ char *ptr = 0;
+ ptr += q_dbus_message_iter_get_arg_type(&iterator);
+ q_dbus_message_iter_next(&iterator);
+
+ // I hope you never dereference this pointer!
+ return QVariant::fromValue<void *>(ptr);
+ break;
+ };
+}
+
+QStringList QDBusDemarshaller::toStringList()
+{
+ QStringList list;
+
+ QDBusDemarshaller sub(capabilities);
+ q_dbus_message_iter_recurse(&iterator, &sub.iterator);
+ q_dbus_message_iter_next(&iterator);
+ while (!sub.atEnd())
+ list.append(sub.toString());
+
+ return list;
+}
+
+QByteArray QDBusDemarshaller::toByteArray()
+{
+ DBusMessageIter sub;
+ q_dbus_message_iter_recurse(&iterator, &sub);
+ q_dbus_message_iter_next(&iterator);
+ int len;
+ char* data;
+ q_dbus_message_iter_get_fixed_array(&sub,&data,&len);
+ return QByteArray(data,len);
+}
+
+bool QDBusDemarshaller::atEnd()
+{
+ // dbus_message_iter_has_next is broken if the list has one single element
+ return q_dbus_message_iter_get_arg_type(&iterator) == DBUS_TYPE_INVALID;
+}
+
+inline QDBusDemarshaller *QDBusDemarshaller::beginStructure()
+{
+ return beginCommon();
+}
+
+inline QDBusDemarshaller *QDBusDemarshaller::beginArray()
+{
+ return beginCommon();
+}
+
+inline QDBusDemarshaller *QDBusDemarshaller::beginMap()
+{
+ return beginCommon();
+}
+
+inline QDBusDemarshaller *QDBusDemarshaller::beginMapEntry()
+{
+ return beginCommon();
+}
+
+QDBusDemarshaller *QDBusDemarshaller::beginCommon()
+{
+ QDBusDemarshaller *d = new QDBusDemarshaller(capabilities);
+ d->parent = this;
+ d->message = q_dbus_message_ref(message);
+
+ // recurse
+ q_dbus_message_iter_recurse(&iterator, &d->iterator);
+ q_dbus_message_iter_next(&iterator);
+ return d;
+}
+
+inline QDBusDemarshaller *QDBusDemarshaller::endStructure()
+{
+ return endCommon();
+}
+
+inline QDBusDemarshaller *QDBusDemarshaller::endArray()
+{
+ return endCommon();
+}
+
+inline QDBusDemarshaller *QDBusDemarshaller::endMap()
+{
+ return endCommon();
+}
+
+inline QDBusDemarshaller *QDBusDemarshaller::endMapEntry()
+{
+ return endCommon();
+}
+
+QDBusDemarshaller *QDBusDemarshaller::endCommon()
+{
+ QDBusDemarshaller *retval = parent;
+ delete this;
+ return retval;
+}
+
+QDBusArgument QDBusDemarshaller::duplicate()
+{
+ QDBusDemarshaller *d = new QDBusDemarshaller(capabilities);
+ d->iterator = iterator;
+ d->message = q_dbus_message_ref(message);
+
+ q_dbus_message_iter_next(&iterator);
+ return QDBusArgumentPrivate::create(d);
+}
+
+QT_END_NAMESPACE
diff --git a/src/dbus/qdbuserror.cpp b/src/dbus/qdbuserror.cpp
new file mode 100644
index 0000000000..7b314fd661
--- /dev/null
+++ b/src/dbus/qdbuserror.cpp
@@ -0,0 +1,368 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbuserror.h"
+
+#include <qdebug.h>
+#include <qvarlengtharray.h>
+
+#include "qdbus_symbols_p.h"
+#include "qdbusmessage.h"
+#include "qdbusmessage_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+/*
+ * Use the following Perl script to generate the error string index list:
+===== PERL SCRIPT ====
+print "static const char errorMessages_string[] =\n";
+$counter = 0;
+$i = 0;
+while (<STDIN>) {
+ chomp;
+ print " \"$_\\0\"\n";
+ $sizes[$i++] = $counter;
+ $counter += 1 + length $_;
+}
+print " \"\\0\";\n\nstatic const int errorMessages_indices[] = {\n ";
+for ($j = 0; $j < $i; ++$j) {
+ printf "$sizes[$j], ";
+}
+print "0\n};\n";
+===== PERL SCRIPT ====
+
+ * The input data is as follows:
+other
+org.freedesktop.DBus.Error.Failed
+org.freedesktop.DBus.Error.NoMemory
+org.freedesktop.DBus.Error.ServiceUnknown
+org.freedesktop.DBus.Error.NoReply
+org.freedesktop.DBus.Error.BadAddress
+org.freedesktop.DBus.Error.NotSupported
+org.freedesktop.DBus.Error.LimitsExceeded
+org.freedesktop.DBus.Error.AccessDenied
+org.freedesktop.DBus.Error.NoServer
+org.freedesktop.DBus.Error.Timeout
+org.freedesktop.DBus.Error.NoNetwork
+org.freedesktop.DBus.Error.AddressInUse
+org.freedesktop.DBus.Error.Disconnected
+org.freedesktop.DBus.Error.InvalidArgs
+org.freedesktop.DBus.Error.UnknownMethod
+org.freedesktop.DBus.Error.TimedOut
+org.freedesktop.DBus.Error.InvalidSignature
+org.freedesktop.DBus.Error.UnknownInterface
+com.trolltech.QtDBus.Error.InternalError
+org.freedesktop.DBus.Error.UnknownObject
+com.trolltech.QtDBus.Error.InvalidService
+com.trolltech.QtDBus.Error.InvalidObjectPath
+com.trolltech.QtDBus.Error.InvalidInterface
+com.trolltech.QtDBus.Error.InvalidMember
+*/
+
+// in the same order as KnownErrors!
+static const char errorMessages_string[] =
+ "other\0"
+ "org.freedesktop.DBus.Error.Failed\0"
+ "org.freedesktop.DBus.Error.NoMemory\0"
+ "org.freedesktop.DBus.Error.ServiceUnknown\0"
+ "org.freedesktop.DBus.Error.NoReply\0"
+ "org.freedesktop.DBus.Error.BadAddress\0"
+ "org.freedesktop.DBus.Error.NotSupported\0"
+ "org.freedesktop.DBus.Error.LimitsExceeded\0"
+ "org.freedesktop.DBus.Error.AccessDenied\0"
+ "org.freedesktop.DBus.Error.NoServer\0"
+ "org.freedesktop.DBus.Error.Timeout\0"
+ "org.freedesktop.DBus.Error.NoNetwork\0"
+ "org.freedesktop.DBus.Error.AddressInUse\0"
+ "org.freedesktop.DBus.Error.Disconnected\0"
+ "org.freedesktop.DBus.Error.InvalidArgs\0"
+ "org.freedesktop.DBus.Error.UnknownMethod\0"
+ "org.freedesktop.DBus.Error.TimedOut\0"
+ "org.freedesktop.DBus.Error.InvalidSignature\0"
+ "org.freedesktop.DBus.Error.UnknownInterface\0"
+ "com.trolltech.QtDBus.Error.InternalError\0"
+ "org.freedesktop.DBus.Error.UnknownObject\0"
+ "com.trolltech.QtDBus.Error.InvalidService\0"
+ "com.trolltech.QtDBus.Error.InvalidObjectPath\0"
+ "com.trolltech.QtDBus.Error.InvalidInterface\0"
+ "com.trolltech.QtDBus.Error.InvalidMember\0"
+ "\0";
+
+static const int errorMessages_indices[] = {
+ 0, 6, 40, 76, 118, 153, 191, 231,
+ 273, 313, 349, 384, 421, 461, 501, 540,
+ 581, 617, 661, 705, 746, 787, 829, 874,
+ 918, 0
+};
+
+static const int errorMessages_count = sizeof errorMessages_indices /
+ sizeof errorMessages_indices[0];
+
+static inline const char *get(QDBusError::ErrorType code)
+{
+ int intcode = qBound(0, int(code) - int(QDBusError::Other), errorMessages_count);
+ return errorMessages_string + errorMessages_indices[intcode];
+}
+
+static inline QDBusError::ErrorType get(const char *name)
+{
+ if (!name || !*name)
+ return QDBusError::NoError;
+ for (int i = 0; i < errorMessages_count; ++i)
+ if (strcmp(name, errorMessages_string + errorMessages_indices[i]) == 0)
+ return QDBusError::ErrorType(i + int(QDBusError::Other));
+ return QDBusError::Other;
+}
+
+/*!
+ \class QDBusError
+ \inmodule QtDBus
+ \since 4.2
+
+ \brief The QDBusError class represents an error received from the
+ D-Bus bus or from remote applications found in the bus.
+
+ When dealing with the D-Bus bus service or with remote
+ applications over D-Bus, a number of error conditions can
+ happen. This error conditions are sometimes signalled by a
+ returned error value or by a QDBusError.
+
+ C++ and Java exceptions are a valid analogy for D-Bus errors:
+ instead of returning normally with a return value, remote
+ applications and the bus may decide to throw an error
+ condition. However, the QtDBus implementation does not use the C++
+ exception-throwing mechanism, so you will receive QDBusErrors in
+ the return reply (see QDBusReply::error()).
+
+ QDBusError objects are used to inspect the error name and message
+ as received from the bus and remote applications. You should not
+ create such objects yourself to signal error conditions when
+ called from D-Bus: instead, use QDBusMessage::createError() and
+ QDBusConnection::send().
+
+ \sa QDBusConnection::send(), QDBusMessage, QDBusReply
+*/
+
+/*!
+ \enum QDBusError::ErrorType
+
+ In order to facilitate verification of the most common D-Bus errors generated by the D-Bus
+ implementation and by the bus daemon itself, QDBusError can be compared to a set of pre-defined
+ values:
+
+ \value NoError QDBusError is invalid (i.e., the call succeeded)
+ \value Other QDBusError contains an error that is one of the well-known ones
+ \value Failed The call failed (\c org.freedesktop.DBus.Error.Failed)
+ \value NoMemory Out of memory (\c org.freedesktop.DBus.Error.NoMemory)
+ \value ServiceUnknown The called service is not known
+ (\c org.freedesktop.DBus.Error.ServiceUnknown)
+ \value NoReply The called method did not reply within the specified timeout
+ (\c org.freedesktop.DBus.Error.NoReply)
+ \value BadAddress The address given is not valid
+ (\c org.freedesktop.DBus.Error.BadAddress)
+ \value NotSupported The call/operation is not supported
+ (\c org.freedesktop.DBus.Error.NotSupported)
+ \value LimitsExceeded The limits allocated to this process/call/connection exceeded the
+ pre-defined values (\c org.freedesktop.DBus.Error.LimitsExceeded)
+ \value AccessDenied The call/operation tried to access a resource it isn't allowed to
+ (\c org.freedesktop.DBus.Error.AccessDenied)
+ \value NoServer \e {Documentation doesn't say what this is for}
+ (\c org.freedesktop.DBus.Error.NoServer)
+ \value Timeout \e {Documentation doesn't say what this is for or how it's used}
+ (\c org.freedesktop.DBus.Error.Timeout)
+ \value NoNetwork \e {Documentation doesn't say what this is for}
+ (\c org.freedesktop.DBus.Error.NoNetwork)
+ \value AddressInUse QDBusServer tried to bind to an address that is already in use
+ (\c org.freedesktop.DBus.Error.AddressInUse)
+ \value Disconnected The call/process/message was sent after QDBusConnection disconnected
+ (\c org.freedesktop.DBus.Error.Disconnected)
+ \value InvalidArgs The arguments passed to this call/operation are not valid
+ (\c org.freedesktop.DBus.Error.InvalidArgs)
+ \value UnknownMethod The method called was not found in this object/interface with the
+ given parameters (\c org.freedesktop.DBus.Error.UnknownMethod)
+ \value TimedOut \e {Documentation doesn't say...}
+ (\c org.freedesktop.DBus.Error.TimedOut)
+ \value InvalidSignature The type signature is not valid or compatible
+ (\c org.freedesktop.DBus.Error.InvalidSignature)
+ \value UnknownInterface The interface is not known
+ \value InternalError An internal error occurred
+ (\c com.trolltech.QtDBus.Error.InternalError)
+
+ \value InvalidObjectPath The object path provided is invalid.
+
+ \value InvalidService The service requested is invalid.
+
+ \value InvalidMember The member is invalid.
+
+ \value InvalidInterface The interface is invalid.
+
+ \value UnknownObject The remote object could not be found.
+*/
+
+/*!
+ \internal
+ Constructs a QDBusError from a DBusError structure.
+*/
+QDBusError::QDBusError(const DBusError *error)
+ : code(NoError)
+{
+ if (!error || !q_dbus_error_is_set(error))
+ return;
+
+ code = ::get(error->name);
+ msg = QString::fromUtf8(error->message);
+ nm = QString::fromUtf8(error->name);
+}
+
+/*!
+ \internal
+ Constructs a QDBusError from a QDBusMessage.
+*/
+QDBusError::QDBusError(const QDBusMessage &qdmsg)
+ : code(NoError)
+{
+ if (qdmsg.type() != QDBusMessage::ErrorMessage)
+ return;
+
+ code = ::get(qdmsg.errorName().toUtf8().constData());
+ nm = qdmsg.errorName();
+ msg = qdmsg.errorMessage();
+}
+
+/*!
+ \internal
+ Constructs a QDBusError from a well-known error code
+*/
+QDBusError::QDBusError(ErrorType error, const QString &mess)
+ : code(error)
+{
+ nm = QLatin1String(::get(error));
+ msg = mess;
+}
+
+/*!
+ \internal
+ Constructs a QDBusError from another QDBusError object
+*/
+QDBusError::QDBusError(const QDBusError &other)
+ : code(other.code), msg(other.msg), nm(other.nm)
+{
+}
+
+/*!
+ \internal
+ Assignment operator
+*/
+
+QDBusError &QDBusError::operator=(const QDBusError &other)
+{
+ code = other.code;
+ msg = other.msg;
+ nm = other.nm;
+ return *this;
+}
+
+/*!
+ Returns this error's ErrorType.
+
+ \sa ErrorType
+*/
+
+QDBusError::ErrorType QDBusError::type() const
+{
+ return code;
+}
+
+/*!
+ Returns this error's name. Error names are similar to D-Bus Interface names, like
+ \c org.freedesktop.DBus.InvalidArgs.
+
+ \sa type()
+*/
+
+QString QDBusError::name() const
+{
+ return nm;
+}
+
+/*!
+ Returns the message that the callee associated with this error. Error messages are
+ implementation defined and usually contain a human-readable error code, though this does not
+ mean it is suitable for your end-users.
+*/
+
+QString QDBusError::message() const
+{
+ return msg;
+}
+
+/*!
+ Returns true if this is a valid error condition (i.e., if there was an error),
+ otherwise false.
+*/
+
+bool QDBusError::isValid() const
+{
+ return (code != NoError);
+}
+
+/*!
+ \since 4.3
+ Returns the error name associated with error condition \a error.
+*/
+QString QDBusError::errorString(ErrorType error)
+{
+ return QLatin1String(::get(error));
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QDBusError &msg)
+{
+ dbg.nospace() << "QDBusError(" << msg.name() << ", " << msg.message() << ')';
+ return dbg.space();
+}
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbuserror.h b/src/dbus/qdbuserror.h
new file mode 100644
index 0000000000..cd11d66932
--- /dev/null
+++ b/src/dbus/qdbuserror.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSERROR_H
+#define QDBUSERROR_H
+
+#include <QtDBus/qdbusmacros.h>
+#include <QtCore/qstring.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+
+struct DBusError;
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(DBus)
+
+class QDBusMessage;
+
+class Q_DBUS_EXPORT QDBusError
+{
+public:
+ enum ErrorType {
+ NoError = 0,
+ Other = 1,
+ Failed,
+ NoMemory,
+ ServiceUnknown,
+ NoReply,
+ BadAddress,
+ NotSupported,
+ LimitsExceeded,
+ AccessDenied,
+ NoServer,
+ Timeout,
+ NoNetwork,
+ AddressInUse,
+ Disconnected,
+ InvalidArgs,
+ UnknownMethod,
+ TimedOut,
+ InvalidSignature,
+ UnknownInterface,
+ InternalError,
+ UnknownObject,
+ InvalidService,
+ InvalidObjectPath,
+ InvalidInterface,
+ InvalidMember,
+
+#ifndef Q_QDOC
+ // don't use this one!
+ LastErrorType = InvalidMember
+#endif
+ };
+
+ QDBusError(const DBusError *error = 0);
+ QDBusError(const QDBusMessage& msg);
+ QDBusError(ErrorType error, const QString &message);
+ QDBusError(const QDBusError &other);
+ QDBusError &operator=(const QDBusError &other);
+
+ ErrorType type() const;
+ QString name() const;
+ QString message() const;
+ bool isValid() const;
+
+ static QString errorString(ErrorType error);
+
+private:
+ ErrorType code;
+ QString msg;
+ QString nm;
+ void *unused;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_DBUS_EXPORT QDebug operator<<(QDebug, const QDBusError &);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusextratypes.cpp b/src/dbus/qdbusextratypes.cpp
new file mode 100644
index 0000000000..bd7d506d34
--- /dev/null
+++ b/src/dbus/qdbusextratypes.cpp
@@ -0,0 +1,242 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusextratypes.h"
+#include "qdbusutil_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+void QDBusObjectPath::check()
+{
+ if (!QDBusUtil::isValidObjectPath(*this)) {
+ qWarning("QDBusObjectPath: invalid path \"%s\"", qPrintable(*this));
+ clear();
+ }
+}
+
+void QDBusSignature::check()
+{
+ if (!QDBusUtil::isValidSignature(*this)) {
+ qWarning("QDBusSignature: invalid signature \"%s\"", qPrintable(*this));
+ clear();
+ }
+}
+
+/*!
+ \class QDBusVariant
+ \inmodule QtDBus
+ \since 4.2
+
+ \brief The QDBusVariant class enables the programmer to identify
+ the variant type provided by the D-Bus typesystem.
+
+ A D-Bus function that takes an integer, a D-Bus variant and a string as parameters
+ can be called with the following argument list (see QDBusMessage::setArguments()):
+
+ \snippet doc/src/snippets/qdbusextratypes/qdbusextratypes.cpp 0
+
+ When a D-Bus function returns a D-Bus variant, it can be retrieved as follows:
+
+ \snippet doc/src/snippets/qdbusextratypes/qdbusextratypes.cpp 1
+
+ The QVariant within a QDBusVariant is required to distinguish between a normal
+ D-Bus value and a value within a D-Bus variant.
+
+ \sa {The QtDBus type system}
+*/
+
+/*!
+ \fn QDBusVariant::QDBusVariant()
+
+ Constructs a new D-Bus variant.
+*/
+
+/*!
+ \fn QDBusVariant::QDBusVariant(const QVariant &variant)
+
+ Constructs a new D-Bus variant from the given Qt \a variant.
+
+ \sa setVariant()
+*/
+
+/*!
+ \fn QVariant QDBusVariant::variant() const
+
+ Returns this D-Bus variant as a QVariant object.
+
+ \sa setVariant()
+*/
+
+/*!
+ \fn void QDBusVariant::setVariant(const QVariant &variant)
+
+ Assigns the value of the given Qt \a variant to this D-Bus variant.
+
+ \sa variant()
+*/
+
+/*!
+ \class QDBusObjectPath
+ \inmodule QtDBus
+ \since 4.2
+
+ \brief The QDBusObjectPath class enables the programmer to
+ identify the OBJECT_PATH type provided by the D-Bus typesystem.
+
+ \sa {The QtDBus type system}
+*/
+
+/*!
+ \fn QDBusObjectPath::QDBusObjectPath()
+
+ Constructs a new object path.
+*/
+
+/*!
+ \fn QDBusObjectPath::QDBusObjectPath(const char *path)
+
+ Constructs a new object path from the given \a path.
+
+ \sa setPath()
+*/
+
+/*!
+ \fn QDBusObjectPath::QDBusObjectPath(const QLatin1String &path)
+
+ Constructs a new object path from the given \a path.
+*/
+
+/*!
+ \fn QDBusObjectPath::QDBusObjectPath(const QString &path)
+
+ Constructs a new object path from the given \a path.
+*/
+
+/*!
+ \fn QString QDBusObjectPath::path() const
+
+ Returns this object path.
+
+ \sa setPath()
+*/
+
+/*!
+ \fn void QDBusObjectPath::setPath(const QString &path)
+
+ Assigns the value of the given \a path to this object path.
+
+ \sa path()
+*/
+
+/*!
+ \fn QDBusObjectPath &QDBusObjectPath::operator=(const QDBusObjectPath &path)
+
+ Assigns the value of the given \a path to this object path.
+
+ \sa setPath()
+*/
+
+
+/*!
+ \class QDBusSignature
+ \inmodule QtDBus
+ \since 4.2
+
+ \brief The QDBusSignature class enables the programmer to
+ identify the SIGNATURE type provided by the D-Bus typesystem.
+
+ \sa {The QtDBus type system}
+*/
+
+/*!
+ \fn QDBusSignature::QDBusSignature()
+
+ Constructs a new signature.
+
+ \sa setSignature()
+*/
+
+/*!
+ \fn QDBusSignature::QDBusSignature(const char *signature)
+
+ Constructs a new signature from the given \a signature.
+*/
+
+/*!
+ \fn QDBusSignature::QDBusSignature(const QLatin1String &signature)
+
+ Constructs a new signature from the given \a signature.
+*/
+
+/*!
+ \fn QDBusSignature::QDBusSignature(const QString &signature)
+
+ Constructs a new signature from the given \a signature.
+*/
+
+/*!
+ \fn QString QDBusSignature::signature() const
+
+ Returns this signature.
+
+ \sa setSignature()
+*/
+
+/*!
+ \fn void QDBusSignature::setSignature(const QString &signature)
+
+ Assigns the value of the given \a signature to this signature.
+ \sa signature()
+*/
+
+/*!
+ \fn QDBusSignature &QDBusSignature::operator=(const QDBusSignature &signature)
+
+ Assigns the value of the given \a signature to this signature.
+
+ \sa setSignature()
+*/
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusextratypes.h b/src/dbus/qdbusextratypes.h
new file mode 100644
index 0000000000..f800062781
--- /dev/null
+++ b/src/dbus/qdbusextratypes.h
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSEXTRATYPES_H
+#define QDBUSEXTRATYPES_H
+
+// define some useful types for D-BUS
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qstring.h>
+#include <QtDBus/qdbusmacros.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(DBus)
+
+// defined in qhash.cpp
+Q_CORE_EXPORT uint qHash(const QString &key);
+
+class Q_DBUS_EXPORT QDBusObjectPath : private QString
+{
+public:
+ inline QDBusObjectPath() { }
+
+ inline explicit QDBusObjectPath(const char *path);
+ inline explicit QDBusObjectPath(const QLatin1String &path);
+ inline explicit QDBusObjectPath(const QString &path);
+ inline QDBusObjectPath &operator=(const QDBusObjectPath &path);
+
+ inline void setPath(const QString &path);
+
+ inline QString path() const
+ { return *this; }
+
+private:
+ void check();
+};
+
+inline QDBusObjectPath::QDBusObjectPath(const char *objectPath)
+ : QString(QString::fromLatin1(objectPath))
+{ check(); }
+
+inline QDBusObjectPath::QDBusObjectPath(const QLatin1String &objectPath)
+ : QString(objectPath)
+{ check(); }
+
+inline QDBusObjectPath::QDBusObjectPath(const QString &objectPath)
+ : QString(objectPath)
+{ check(); }
+
+inline QDBusObjectPath &QDBusObjectPath::operator=(const QDBusObjectPath &_path)
+{ QString::operator=(_path); check(); return *this; }
+
+inline void QDBusObjectPath::setPath(const QString &objectPath)
+{ QString::operator=(objectPath); check(); }
+
+inline bool operator==(const QDBusObjectPath &lhs, const QDBusObjectPath &rhs)
+{ return lhs.path() == rhs.path(); }
+
+inline bool operator!=(const QDBusObjectPath &lhs, const QDBusObjectPath &rhs)
+{ return lhs.path() != rhs.path(); }
+
+inline bool operator<(const QDBusObjectPath &lhs, const QDBusObjectPath &rhs)
+{ return lhs.path() < rhs.path(); }
+
+inline uint qHash(const QDBusObjectPath &objectPath)
+{ return qHash(objectPath.path()); }
+
+
+class Q_DBUS_EXPORT QDBusSignature : private QString
+{
+public:
+ inline QDBusSignature() { }
+
+ inline explicit QDBusSignature(const char *signature);
+ inline explicit QDBusSignature(const QLatin1String &signature);
+ inline explicit QDBusSignature(const QString &signature);
+ inline QDBusSignature &operator=(const QDBusSignature &signature);
+
+ inline void setSignature(const QString &signature);
+
+ inline QString signature() const
+ { return *this; }
+
+private:
+ void check();
+};
+
+inline QDBusSignature::QDBusSignature(const char *dBusSignature)
+ : QString(QString::fromAscii(dBusSignature))
+{ check(); }
+
+inline QDBusSignature::QDBusSignature(const QLatin1String &dBusSignature)
+ : QString(dBusSignature)
+{ check(); }
+
+inline QDBusSignature::QDBusSignature(const QString &dBusSignature)
+ : QString(dBusSignature)
+{ check(); }
+
+inline QDBusSignature &QDBusSignature::operator=(const QDBusSignature &dbusSignature)
+{ QString::operator=(dbusSignature); check(); return *this; }
+
+inline void QDBusSignature::setSignature(const QString &dBusSignature)
+{ QString::operator=(dBusSignature); check(); }
+
+inline bool operator==(const QDBusSignature &lhs, const QDBusSignature &rhs)
+{ return lhs.signature() == rhs.signature(); }
+
+inline bool operator!=(const QDBusSignature &lhs, const QDBusSignature &rhs)
+{ return lhs.signature() != rhs.signature(); }
+
+inline bool operator<(const QDBusSignature &lhs, const QDBusSignature &rhs)
+{ return lhs.signature() < rhs.signature(); }
+
+inline uint qHash(const QDBusSignature &signature)
+{ return qHash(signature.signature()); }
+
+class QDBusVariant : private QVariant
+{
+public:
+ inline QDBusVariant() { }
+ inline explicit QDBusVariant(const QVariant &variant);
+
+ inline void setVariant(const QVariant &variant);
+
+ inline QVariant variant() const
+ { return *this; }
+};
+
+inline QDBusVariant::QDBusVariant(const QVariant &dBusVariant)
+ : QVariant(dBusVariant) { }
+
+inline void QDBusVariant::setVariant(const QVariant &dBusVariant)
+{ QVariant::operator=(dBusVariant); }
+
+inline bool operator==(const QDBusVariant &v1, const QDBusVariant &v2)
+{ return v1.variant() == v2.variant(); }
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QDBusVariant)
+Q_DECLARE_METATYPE(QDBusObjectPath)
+Q_DECLARE_METATYPE(QList<QDBusObjectPath>)
+Q_DECLARE_METATYPE(QDBusSignature)
+Q_DECLARE_METATYPE(QList<QDBusSignature>)
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp
new file mode 100644
index 0000000000..b2095c747e
--- /dev/null
+++ b/src/dbus/qdbusintegrator.cpp
@@ -0,0 +1,2411 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qcoreapplication.h>
+#include <qdebug.h>
+#include <qmetaobject.h>
+#include <qobject.h>
+#include <qsocketnotifier.h>
+#include <qstringlist.h>
+#include <qtimer.h>
+#include <qthread.h>
+
+#include "qdbusargument.h"
+#include "qdbusconnection_p.h"
+#include "qdbusinterface_p.h"
+#include "qdbusmessage.h"
+#include "qdbusmetatype.h"
+#include "qdbusmetatype_p.h"
+#include "qdbusabstractadaptor.h"
+#include "qdbusabstractadaptor_p.h"
+#include "qdbusutil_p.h"
+#include "qdbusmessage_p.h"
+#include "qdbuscontext_p.h"
+#include "qdbuspendingcall_p.h"
+#include "qdbusintegrator_p.h"
+
+#include "qdbusthreaddebug_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+static bool isDebugging;
+#define qDBusDebug if (!::isDebugging); else qDebug
+
+Q_GLOBAL_STATIC_WITH_ARGS(const QString, orgFreedesktopDBusString, (QLatin1String(DBUS_SERVICE_DBUS)))
+
+static inline QString dbusServiceString()
+{ return *orgFreedesktopDBusString(); }
+static inline QString dbusInterfaceString()
+{
+ // it's the same string, but just be sure
+ Q_ASSERT(*orgFreedesktopDBusString() == QLatin1String(DBUS_INTERFACE_DBUS));
+ return *orgFreedesktopDBusString();
+}
+
+static inline QDebug operator<<(QDebug dbg, const QThread *th)
+{
+ dbg.nospace() << "QThread(ptr=" << (void*)th;
+ if (th && !th->objectName().isEmpty())
+ dbg.nospace() << ", name=" << th->objectName();
+ dbg.nospace() << ')';
+ return dbg.space();
+}
+
+#if QDBUS_THREAD_DEBUG
+static inline QDebug operator<<(QDebug dbg, const QDBusConnectionPrivate *conn)
+{
+ dbg.nospace() << "QDBusConnection("
+ << "ptr=" << (void*)conn
+ << ", name=" << conn->name
+ << ", baseService=" << conn->baseService
+ << ", thread=";
+ if (conn->thread() == QThread::currentThread())
+ dbg.nospace() << "same thread";
+ else
+ dbg.nospace() << conn->thread();
+ dbg.nospace() << ')';
+ return dbg.space();
+}
+
+Q_AUTOTEST_EXPORT void qdbusDefaultThreadDebug(int action, int condition, QDBusConnectionPrivate *conn)
+{
+ qDBusDebug() << QThread::currentThread()
+ << "QtDBus threading action" << action
+ << (condition == QDBusLockerBase::BeforeLock ? "before lock" :
+ condition == QDBusLockerBase::AfterLock ? "after lock" :
+ condition == QDBusLockerBase::BeforeUnlock ? "before unlock" :
+ condition == QDBusLockerBase::AfterUnlock ? "after unlock" :
+ condition == QDBusLockerBase::BeforePost ? "before event posting" :
+ condition == QDBusLockerBase::AfterPost ? "after event posting" :
+ condition == QDBusLockerBase::BeforeDeliver ? "before event delivery" :
+ condition == QDBusLockerBase::AfterDeliver ? "after event delivery" :
+ condition == QDBusLockerBase::BeforeAcquire ? "before acquire" :
+ condition == QDBusLockerBase::AfterAcquire ? "after acquire" :
+ condition == QDBusLockerBase::BeforeRelease ? "before release" :
+ condition == QDBusLockerBase::AfterRelease ? "after release" :
+ "condition unknown")
+ << "in connection" << conn;
+}
+Q_AUTOTEST_EXPORT qdbusThreadDebugFunc qdbusThreadDebug = 0;
+#endif
+
+typedef void (*QDBusSpyHook)(const QDBusMessage&);
+typedef QVarLengthArray<QDBusSpyHook, 4> QDBusSpyHookList;
+Q_GLOBAL_STATIC(QDBusSpyHookList, qDBusSpyHookList)
+
+extern "C" {
+
+ // libdbus-1 callbacks
+
+static bool qDBusRealAddTimeout(QDBusConnectionPrivate *d, DBusTimeout *timeout, int ms);
+static dbus_bool_t qDBusAddTimeout(DBusTimeout *timeout, void *data)
+{
+ Q_ASSERT(timeout);
+ Q_ASSERT(data);
+
+ // qDebug("addTimeout %d", q_dbus_timeout_get_interval(timeout));
+
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+
+ if (!q_dbus_timeout_get_enabled(timeout))
+ return true;
+
+ QDBusWatchAndTimeoutLocker locker(AddTimeoutAction, d);
+ if (QCoreApplication::instance() && QThread::currentThread() == d->thread()) {
+ // correct thread
+ return qDBusRealAddTimeout(d, timeout, q_dbus_timeout_get_interval(timeout));
+ } else {
+ // wrong thread: sync back
+ QDBusConnectionCallbackEvent *ev = new QDBusConnectionCallbackEvent;
+ ev->subtype = QDBusConnectionCallbackEvent::AddTimeout;
+ d->timeoutsPendingAdd.append(qMakePair(timeout, q_dbus_timeout_get_interval(timeout)));
+ d->postEventToThread(AddTimeoutAction, d, ev);
+ return true;
+ }
+}
+
+static bool qDBusRealAddTimeout(QDBusConnectionPrivate *d, DBusTimeout *timeout, int ms)
+{
+ Q_ASSERT(d->timeouts.keys(timeout).isEmpty());
+
+ int timerId = d->startTimer(ms);
+ 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);
+
+ QDBusWatchAndTimeoutLocker locker(RemoveTimeoutAction, d);
+
+ // is it pending addition?
+ QDBusConnectionPrivate::PendingTimeoutList::iterator pit = d->timeoutsPendingAdd.begin();
+ while (pit != d->timeoutsPendingAdd.end()) {
+ if (pit->first == timeout)
+ pit = d->timeoutsPendingAdd.erase(pit);
+ else
+ ++pit;
+ }
+
+ // is it a running timer?
+ bool correctThread = QCoreApplication::instance() && QThread::currentThread() == d->thread();
+ QDBusConnectionPrivate::TimeoutHash::iterator it = d->timeouts.begin();
+ while (it != d->timeouts.end()) {
+ if (it.value() == timeout) {
+ if (correctThread) {
+ // correct thread
+ d->killTimer(it.key());
+ } else {
+ // incorrect thread or no application, post an event for later
+ QDBusConnectionCallbackEvent *ev = new QDBusConnectionCallbackEvent;
+ ev->subtype = QDBusConnectionCallbackEvent::KillTimer;
+ ev->timerId = it.key();
+ d->postEventToThread(KillTimerAction, d, ev);
+ }
+ it = d->timeouts.erase(it);
+ break;
+ } else {
+ ++it;
+ }
+ }
+}
+
+static void qDBusToggleTimeout(DBusTimeout *timeout, void *data)
+{
+ Q_ASSERT(timeout);
+ Q_ASSERT(data);
+
+ //qDebug("ToggleTimeout");
+
+ qDBusRemoveTimeout(timeout, data);
+ qDBusAddTimeout(timeout, data);
+}
+
+static bool qDBusRealAddWatch(QDBusConnectionPrivate *d, DBusWatch *watch, int flags, int fd);
+static dbus_bool_t qDBusAddWatch(DBusWatch *watch, void *data)
+{
+ Q_ASSERT(watch);
+ Q_ASSERT(data);
+
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+
+ int flags = q_dbus_watch_get_flags(watch);
+ int fd = q_dbus_watch_get_fd(watch);
+
+ if (QCoreApplication::instance() && QThread::currentThread() == d->thread()) {
+ return qDBusRealAddWatch(d, watch, flags, fd);
+ } else {
+ QDBusConnectionCallbackEvent *ev = new QDBusConnectionCallbackEvent;
+ ev->subtype = QDBusConnectionCallbackEvent::AddWatch;
+ ev->watch = watch;
+ ev->fd = fd;
+ ev->extra = flags;
+ d->postEventToThread(AddWatchAction, d, ev);
+ return true;
+ }
+}
+
+static bool qDBusRealAddWatch(QDBusConnectionPrivate *d, DBusWatch *watch, int flags, int fd)
+{
+ QDBusConnectionPrivate::Watcher watcher;
+
+ QDBusWatchAndTimeoutLocker locker(AddWatchAction, d);
+ if (flags & DBUS_WATCH_READABLE) {
+ //qDebug("addReadWatch %d", fd);
+ watcher.watch = watch;
+ if (QCoreApplication::instance()) {
+ watcher.read = new QSocketNotifier(fd, QSocketNotifier::Read, d);
+ watcher.read->setEnabled(q_dbus_watch_get_enabled(watch));
+ 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);
+ watcher.write->setEnabled(q_dbus_watch_get_enabled(watch));
+ 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 = q_dbus_watch_get_fd(watch);
+
+ QDBusWatchAndTimeoutLocker locker(RemoveWatchAction, d);
+ QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd);
+ while (i != d->watchers.end() && i.key() == fd) {
+ if (i.value().watch == watch) {
+ if (QCoreApplication::instance() && QThread::currentThread() == d->thread()) {
+ // correct thread, delete the socket notifiers
+ delete i.value().read;
+ delete i.value().write;
+ } else {
+ // incorrect thread or no application, use delete later
+ if (i->read)
+ i->read->deleteLater();
+ if (i->write)
+ i->write->deleteLater();
+ }
+ i = d->watchers.erase(i);
+ } else {
+ ++i;
+ }
+ }
+}
+
+static void qDBusRealToggleWatch(QDBusConnectionPrivate *d, DBusWatch *watch, int fd);
+static void qDBusToggleWatch(DBusWatch *watch, void *data)
+{
+ Q_ASSERT(watch);
+ Q_ASSERT(data);
+
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+ int fd = q_dbus_watch_get_fd(watch);
+
+ if (QCoreApplication::instance() && QThread::currentThread() == d->thread()) {
+ qDBusRealToggleWatch(d, watch, fd);
+ } else {
+ QDBusConnectionCallbackEvent *ev = new QDBusConnectionCallbackEvent;
+ ev->subtype = QDBusConnectionCallbackEvent::ToggleWatch;
+ ev->watch = watch;
+ ev->fd = fd;
+ d->postEventToThread(ToggleWatchAction, d, ev);
+ }
+}
+
+static void qDBusRealToggleWatch(QDBusConnectionPrivate *d, DBusWatch *watch, int fd)
+{
+ QDBusWatchAndTimeoutLocker locker(ToggleWatchAction, d);
+
+ QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd);
+ while (i != d->watchers.end() && i.key() == fd) {
+ if (i.value().watch == watch) {
+ bool enabled = q_dbus_watch_get_enabled(watch);
+ int flags = q_dbus_watch_get_flags(watch);
+
+ //qDebug("toggle watch %d to %d (write: %d, read: %d)", q_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 qDBusUpdateDispatchStatus(DBusConnection *connection, DBusDispatchStatus new_status, void *data)
+{
+ Q_ASSERT(connection);
+ Q_UNUSED(connection);
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+
+ static int slotId; // 0 is QObject::deleteLater()
+ if (!slotId) {
+ // it's ok to do this: there's no race condition because the store is atomic
+ // and we always set to the same value
+ slotId = QDBusConnectionPrivate::staticMetaObject.indexOfSlot("doDispatch()");
+ }
+
+ //qDBusDebug() << "Updating dispatcher status" << slotId;
+ if (new_status == DBUS_DISPATCH_DATA_REMAINS)
+ QDBusConnectionPrivate::staticMetaObject.method(slotId).
+ invoke(d, Qt::QueuedConnection);
+}
+
+static void qDBusNewConnection(DBusServer *server, DBusConnection *connection, void *data)
+{
+ // ### We may want to separate the server from the QDBusConnectionPrivate
+ Q_ASSERT(server); Q_UNUSED(server);
+ Q_ASSERT(connection);
+ Q_ASSERT(data);
+
+ // keep the connection alive
+ q_dbus_connection_ref(connection);
+ QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
+
+ // setPeer does the error handling for us
+ QDBusErrorInternal error;
+ d->setPeer(connection, error);
+
+ QDBusConnection retval = QDBusConnectionPrivate::q(d);
+
+ // make QDBusServer emit the newConnection signal
+ d->serverConnection(retval);
+}
+
+} // extern "C"
+
+static QByteArray buildMatchRule(const QString &service,
+ const QString &objectPath, const QString &interface,
+ const QString &member, const QStringList &argMatch, const QString & /*signature*/)
+{
+ QString result = QLatin1String("type='signal',");
+ QString keyValue = QLatin1String("%1='%2',");
+
+ if (!service.isEmpty())
+ result += keyValue.arg(QLatin1String("sender"), service);
+ if (!objectPath.isEmpty())
+ result += keyValue.arg(QLatin1String("path"), objectPath);
+ if (!interface.isEmpty())
+ result += keyValue.arg(QLatin1String("interface"), interface);
+ if (!member.isEmpty())
+ result += keyValue.arg(QLatin1String("member"), member);
+
+ // add the argument string-matching now
+ if (!argMatch.isEmpty()) {
+ keyValue = QLatin1String("arg%1='%2',");
+ for (int i = 0; i < argMatch.count(); ++i)
+ if (!argMatch.at(i).isNull())
+ result += keyValue.arg(i).arg(argMatch.at(i));
+ }
+
+ result.chop(1); // remove ending comma
+ return result.toLatin1();
+}
+
+static bool findObject(const QDBusConnectionPrivate::ObjectTreeNode *root,
+ const QString &fullpath, int &usedLength,
+ QDBusConnectionPrivate::ObjectTreeNode &result)
+{
+ if (!fullpath.compare(QLatin1String("/")) && root->obj) {
+ usedLength = 1;
+ result = *root;
+ return root;
+ }
+ int start = 0;
+ int length = fullpath.length();
+ if (fullpath.at(0) == QLatin1Char('/'))
+ start = 1;
+
+ // walk the object tree
+ const QDBusConnectionPrivate::ObjectTreeNode *node = root;
+ while (start < length && node && !(node->flags & QDBusConnection::ExportChildObjects)) {
+ int end = fullpath.indexOf(QLatin1Char('/'), start);
+ end = (end == -1 ? length : end);
+ QStringRef pathComponent(&fullpath, start, end - start);
+
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it =
+ qLowerBound(node->children.constBegin(), node->children.constEnd(), pathComponent);
+ if (it != node->children.constEnd() && it->name == pathComponent)
+ // match
+ node = it;
+ else
+ node = 0;
+
+ start = end + 1;
+ }
+
+ // found our object
+ usedLength = (start > length ? length : start);
+ if (node) {
+ if (node->obj || !node->children.isEmpty())
+ result = *node;
+ else
+ // there really is no object here
+ // we're just looking at an unused space in the QVector
+ node = 0;
+ }
+ return node;
+}
+
+static QObject *findChildObject(const QDBusConnectionPrivate::ObjectTreeNode *root,
+ const QString &fullpath, int start)
+{
+ int length = fullpath.length();
+
+ // any object in the tree can tell us to switch to its own object tree:
+ const QDBusConnectionPrivate::ObjectTreeNode *node = root;
+ if (node && node->flags & QDBusConnection::ExportChildObjects) {
+ QObject *obj = node->obj;
+
+ while (obj) {
+ if (start >= length)
+ // we're at the correct level
+ return obj;
+
+ int pos = fullpath.indexOf(QLatin1Char('/'), start);
+ pos = (pos == -1 ? length : pos);
+ QStringRef pathComponent(&fullpath, start, pos - start);
+
+ const QObjectList children = obj->children();
+
+ // find a child with the proper name
+ QObject *next = 0;
+ QObjectList::ConstIterator it = children.constBegin();
+ QObjectList::ConstIterator end = children.constEnd();
+ for ( ; it != end; ++it)
+ if ((*it)->objectName() == pathComponent) {
+ next = *it;
+ break;
+ }
+
+ if (!next)
+ break;
+
+ obj = next;
+ start = pos + 1;
+ }
+ }
+
+ // object not found
+ return 0;
+}
+
+static bool shouldWatchService(const QString &service)
+{
+ return !service.isEmpty() && !service.startsWith(QLatin1Char(':'));
+}
+
+extern Q_DBUS_EXPORT void qDBusAddSpyHook(QDBusSpyHook);
+void qDBusAddSpyHook(QDBusSpyHook hook)
+{
+ qDBusSpyHookList()->append(hook);
+}
+
+extern "C" {
+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;
+
+ QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(message, d->capabilities);
+ qDBusDebug() << d << "got message (signal):" << amsg;
+
+ return d->handleMessage(amsg) ?
+ DBUS_HANDLER_RESULT_HANDLED :
+ DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+}
+
+bool QDBusConnectionPrivate::handleMessage(const QDBusMessage &amsg)
+{
+ const QDBusSpyHookList *list = qDBusSpyHookList();
+ for (int i = 0; i < list->size(); ++i) {
+ qDBusDebug() << "calling the message spy hook";
+ (*(*list)[i])(amsg);
+ }
+
+ if (!ref)
+ return false;
+
+ switch (amsg.type()) {
+ case QDBusMessage::SignalMessage:
+ handleSignal(amsg);
+ // if there are any other filters in this DBusConnection,
+ // let them see the signal too
+ return false;
+ case QDBusMessage::MethodCallMessage:
+ handleObjectCall(amsg);
+ return true;
+ case QDBusMessage::ReplyMessage:
+ case QDBusMessage::ErrorMessage:
+ case QDBusMessage::InvalidMessage:
+ return false; // we don't handle those here
+ }
+
+ return false;
+}
+
+static void huntAndDestroy(QObject *needle, QDBusConnectionPrivate::ObjectTreeNode &haystack)
+{
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = haystack.children.begin();
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator end = haystack.children.end();
+ for ( ; it != end; ++it)
+ huntAndDestroy(needle, *it);
+
+ if (needle == haystack.obj) {
+ haystack.obj = 0;
+ haystack.flags = 0;
+ }
+}
+
+static void huntAndEmit(DBusConnection *connection, DBusMessage *msg,
+ QObject *needle, const QDBusConnectionPrivate::ObjectTreeNode &haystack,
+ bool isScriptable, bool isAdaptor, const QString &path = QString())
+{
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it = haystack.children.constBegin();
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator end = haystack.children.constEnd();
+ for ( ; it != end; ++it)
+ huntAndEmit(connection, msg, needle, *it, isScriptable, isAdaptor, path + QLatin1Char('/') + it->name);
+
+ if (needle == haystack.obj) {
+ // is this a signal we should relay?
+ if (isAdaptor && (haystack.flags & QDBusConnection::ExportAdaptors) == 0)
+ return; // no: it comes from an adaptor and we're not exporting adaptors
+ else if (!isAdaptor) {
+ int mask = isScriptable
+ ? QDBusConnection::ExportScriptableSignals
+ : QDBusConnection::ExportNonScriptableSignals;
+ if ((haystack.flags & mask) == 0)
+ return; // signal was not exported
+ }
+
+ QByteArray p = path.toLatin1();
+ if (p.isEmpty())
+ p = "/";
+ qDBusDebug() << QThread::currentThread() << "emitting signal at" << p;
+ DBusMessage *msg2 = q_dbus_message_copy(msg);
+ q_dbus_message_set_path(msg2, p);
+ q_dbus_connection_send(connection, msg2, 0);
+ q_dbus_message_unref(msg2);
+ }
+}
+
+static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags,
+ const QString &signature_, QList<int>& metaTypes)
+{
+ QByteArray msgSignature = signature_.toLatin1();
+
+ for (int idx = mo->methodCount() - 1 ; idx >= QObject::staticMetaObject.methodCount(); --idx) {
+ QMetaMethod mm = mo->method(idx);
+
+ // check access:
+ if (mm.access() != QMetaMethod::Public)
+ continue;
+
+ // check type:
+ if (mm.methodType() != QMetaMethod::Slot && mm.methodType() != QMetaMethod::Method)
+ continue;
+
+ // check name:
+ QByteArray slotname = mm.signature();
+ int paren = slotname.indexOf('(');
+ if (paren != name.length() || !slotname.startsWith(name))
+ continue;
+
+ int returnType = qDBusNameToTypeId(mm.typeName());
+ bool isAsync = qDBusCheckAsyncTag(mm.tag());
+ bool isScriptable = mm.attributes() & QMetaMethod::Scriptable;
+
+ // consistency check:
+ if (isAsync && returnType != QMetaType::Void)
+ continue;
+
+ int inputCount = qDBusParametersForMethod(mm, metaTypes);
+ if (inputCount == -1)
+ continue; // problem parsing
+
+ metaTypes[0] = returnType;
+ bool hasMessage = false;
+ if (inputCount > 0 &&
+ metaTypes.at(inputCount) == QDBusMetaTypeId::message) {
+ // "no input parameters" is allowed as long as the message meta type is there
+ hasMessage = true;
+ --inputCount;
+ }
+
+ // try to match the parameters
+ int i;
+ QByteArray reconstructedSignature;
+ for (i = 1; i <= inputCount; ++i) {
+ const char *typeSignature = QDBusMetaType::typeToSignature( metaTypes.at(i) );
+ if (!typeSignature)
+ break; // invalid
+
+ reconstructedSignature += typeSignature;
+ if (!msgSignature.startsWith(reconstructedSignature))
+ break;
+ }
+
+ if (reconstructedSignature != msgSignature)
+ continue; // we didn't match them all
+
+ if (hasMessage)
+ ++i;
+
+ // make sure that the output parameters have signatures too
+ if (returnType != 0 && QDBusMetaType::typeToSignature(returnType) == 0)
+ continue;
+
+ bool ok = true;
+ for (int j = i; ok && j < metaTypes.count(); ++j)
+ if (QDBusMetaType::typeToSignature(metaTypes.at(i)) == 0)
+ ok = false;
+ if (!ok)
+ continue;
+
+ // consistency check:
+ if (isAsync && metaTypes.count() > i + 1)
+ continue;
+
+ if (mm.methodType() == QMetaMethod::Slot) {
+ if (isScriptable && (flags & QDBusConnection::ExportScriptableSlots) == 0)
+ continue; // scriptable slots not exported
+ if (!isScriptable && (flags & QDBusConnection::ExportNonScriptableSlots) == 0)
+ continue; // non-scriptable slots not exported
+ } else {
+ if (isScriptable && (flags & QDBusConnection::ExportScriptableInvokables) == 0)
+ continue; // scriptable invokables not exported
+ if (!isScriptable && (flags & QDBusConnection::ExportNonScriptableInvokables) == 0)
+ continue; // non-scriptable invokables not exported
+ }
+
+ // if we got here, this slot matched
+ return idx;
+ }
+
+ // no slot matched
+ return -1;
+}
+
+static QDBusCallDeliveryEvent * const DIRECT_DELIVERY = (QDBusCallDeliveryEvent *)1;
+
+QDBusCallDeliveryEvent* QDBusConnectionPrivate::prepareReply(QDBusConnectionPrivate *target,
+ QObject *object, int idx,
+ const QList<int> &metaTypes,
+ const QDBusMessage &msg)
+{
+ Q_ASSERT(object);
+ Q_UNUSED(object);
+
+ int n = metaTypes.count() - 1;
+ if (metaTypes[n] == QDBusMetaTypeId::message)
+ --n;
+
+ if (msg.arguments().count() < n)
+ return 0; // too few arguments
+
+ // check that types match
+ for (int i = 0; i < n; ++i)
+ if (metaTypes.at(i + 1) != msg.arguments().at(i).userType() &&
+ msg.arguments().at(i).userType() != qMetaTypeId<QDBusArgument>())
+ return 0; // no match
+
+ // we can deliver
+ // prepare for the call
+ if (target == object)
+ return DIRECT_DELIVERY;
+ return new QDBusCallDeliveryEvent(QDBusConnection(target), idx, target, msg, metaTypes);
+}
+
+void QDBusConnectionPrivate::activateSignal(const QDBusConnectionPrivate::SignalHook& hook,
+ const QDBusMessage &msg)
+{
+ // This is called by QDBusConnectionPrivate::handleSignal to deliver a signal
+ // that was received from D-Bus
+ //
+ // Signals are delivered to slots if the parameters match
+ // Slots can have less parameters than there are on the message
+ // Slots can optionally have one final parameter that is a QDBusMessage
+ // Slots receive read-only copies of the message (i.e., pass by value or by const-ref)
+ QDBusCallDeliveryEvent *call = prepareReply(this, hook.obj, hook.midx, hook.params, msg);
+ if (call == DIRECT_DELIVERY) {
+ // short-circuit delivery
+ Q_ASSERT(this == hook.obj);
+ deliverCall(this, 0, msg, hook.params, hook.midx);
+ return;
+ }
+ if (call)
+ postEventToThread(ActivateSignalAction, hook.obj, call);
+}
+
+bool QDBusConnectionPrivate::activateCall(QObject* object, int flags, const QDBusMessage &msg)
+{
+ // This is called by QDBusConnectionPrivate::handleObjectCall to place a call
+ // to a slot on the object.
+ //
+ // The call is delivered to the first slot that matches the following conditions:
+ // - has the same name as the message's target member
+ // - ALL of the message's types are found in slot's parameter list
+ // - optionally has one more parameter of type QDBusMessage
+ // If none match, then the slot of the same name as the message target and with
+ // the first type of QDBusMessage is delivered.
+ //
+ // The D-Bus specification requires that all MethodCall messages be replied to, unless the
+ // caller specifically waived this requirement. This means that we inspect if the user slot
+ // generated a reply and, if it didn't, we will. Obviously, if the user slot doesn't take a
+ // QDBusMessage parameter, it cannot generate a reply.
+ //
+ // When a return message is generated, the slot's return type, if any, will be placed
+ // in the message's first position. If there are non-const reference parameters to the
+ // slot, they must appear at the end and will be placed in the subsequent message
+ // positions.
+
+ static const char cachePropertyName[] = "_qdbus_slotCache";
+
+ if (!object)
+ return false;
+
+#ifndef QT_NO_PROPERTIES
+ Q_ASSERT_X(QThread::currentThread() == object->thread(),
+ "QDBusConnection: internal threading error",
+ "function called for an object that is in another thread!!");
+
+ QDBusSlotCache slotCache =
+ qvariant_cast<QDBusSlotCache>(object->property(cachePropertyName));
+ QString cacheKey = msg.member(), signature = msg.signature();
+ if (!signature.isEmpty()) {
+ cacheKey.reserve(cacheKey.length() + 1 + signature.length());
+ cacheKey += QLatin1Char('.');
+ cacheKey += signature;
+ }
+
+ QDBusSlotCache::Hash::ConstIterator cacheIt = slotCache.hash.constFind(cacheKey);
+ while (cacheIt != slotCache.hash.constEnd() && cacheIt->flags != flags &&
+ cacheIt.key() == cacheKey)
+ ++cacheIt;
+ if (cacheIt == slotCache.hash.constEnd() || cacheIt.key() != cacheKey)
+ {
+ // not cached, analyze the meta object
+ const QMetaObject *mo = object->metaObject();
+ QByteArray memberName = msg.member().toUtf8();
+
+ // find a slot that matches according to the rules above
+ QDBusSlotCache::Data slotData;
+ slotData.flags = flags;
+ slotData.slotIdx = ::findSlot(mo, memberName, flags, msg.signature(), slotData.metaTypes);
+ if (slotData.slotIdx == -1) {
+ // ### this is where we want to add the connection as an arg too
+ // try with no parameters, but with a QDBusMessage
+ slotData.slotIdx = ::findSlot(mo, memberName, flags, QString(), slotData.metaTypes);
+ if (slotData.metaTypes.count() != 2 ||
+ slotData.metaTypes.at(1) != QDBusMetaTypeId::message) {
+ // not found
+ // save the negative lookup
+ slotData.slotIdx = -1;
+ slotData.metaTypes.clear();
+ slotCache.hash.insert(cacheKey, slotData);
+ object->setProperty(cachePropertyName, QVariant::fromValue(slotCache));
+ return false;
+ }
+ }
+
+ // save to the cache
+ slotCache.hash.insert(cacheKey, slotData);
+ object->setProperty(cachePropertyName, QVariant::fromValue(slotCache));
+
+ // found the slot to be called
+ deliverCall(object, flags, msg, slotData.metaTypes, slotData.slotIdx);
+ return true;
+ } else if (cacheIt->slotIdx == -1) {
+ // negative cache
+ return false;
+ } else {
+ // use the cache
+ deliverCall(object, flags, msg, cacheIt->metaTypes, cacheIt->slotIdx);
+ return true;
+ }
+#endif // QT_NO_PROPERTIES
+ return false;
+}
+
+void QDBusConnectionPrivate::deliverCall(QObject *object, int /*flags*/, const QDBusMessage &msg,
+ const QList<int> &metaTypes, int slotIdx)
+{
+ Q_ASSERT_X(!object || QThread::currentThread() == object->thread(),
+ "QDBusConnection: internal threading error",
+ "function called for an object that is in another thread!!");
+
+ QVarLengthArray<void *, 10> params;
+ params.reserve(metaTypes.count());
+
+ QVariantList auxParameters;
+ // let's create the parameter list
+
+ // first one is the return type -- add it below
+ params.append(0);
+
+ // add the input parameters
+ int i;
+ int pCount = qMin(msg.arguments().count(), metaTypes.count() - 1);
+ for (i = 1; i <= pCount; ++i) {
+ int id = metaTypes[i];
+ if (id == QDBusMetaTypeId::message)
+ break;
+
+ const QVariant &arg = msg.arguments().at(i - 1);
+ if (arg.userType() == id)
+ // no conversion needed
+ params.append(const_cast<void *>(arg.constData()));
+ else if (arg.userType() == qMetaTypeId<QDBusArgument>()) {
+ // convert to what the function expects
+ void *null = 0;
+ auxParameters.append(QVariant(id, null));
+
+ const QDBusArgument &in =
+ *reinterpret_cast<const QDBusArgument *>(arg.constData());
+ QVariant &out = auxParameters[auxParameters.count() - 1];
+
+ if (!QDBusMetaType::demarshall(in, out.userType(), out.data()))
+ qFatal("Internal error: demarshalling function for type '%s' (%d) failed!",
+ out.typeName(), out.userType());
+
+ params.append(const_cast<void *>(out.constData()));
+ } else {
+ qFatal("Internal error: got invalid meta type %d (%s) "
+ "when trying to convert to meta type %d (%s)",
+ arg.userType(), QMetaType::typeName(arg.userType()),
+ id, QMetaType::typeName(id));
+ }
+ }
+
+ bool takesMessage = false;
+ if (metaTypes.count() > i && metaTypes[i] == QDBusMetaTypeId::message) {
+ params.append(const_cast<void*>(static_cast<const void*>(&msg)));
+ takesMessage = true;
+ ++i;
+ }
+
+ // output arguments
+ QVariantList outputArgs;
+ void *null = 0;
+ if (metaTypes[0] != QMetaType::Void) {
+ QVariant arg(metaTypes[0], null);
+ outputArgs.append( arg );
+ params[0] = const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData());
+ }
+ for ( ; i < metaTypes.count(); ++i) {
+ QVariant arg(metaTypes[i], null);
+ outputArgs.append( arg );
+ params.append(const_cast<void*>(outputArgs.at( outputArgs.count() - 1 ).constData()));
+ }
+
+ // make call:
+ bool fail;
+ if (!object) {
+ fail = true;
+ } else {
+ // FIXME: save the old sender!
+ QDBusContextPrivate context(QDBusConnection(this), msg);
+ QDBusContextPrivate *old = QDBusContextPrivate::set(object, &context);
+ QDBusConnectionPrivate::setSender(this);
+
+ QPointer<QObject> ptr = object;
+ fail = object->qt_metacall(QMetaObject::InvokeMetaMethod,
+ slotIdx, params.data()) >= 0;
+ QDBusConnectionPrivate::setSender(0);
+ // the object might be deleted in the slot
+ if (!ptr.isNull())
+ QDBusContextPrivate::set(object, old);
+ }
+
+ // do we create a reply? Only if the caller is waiting for a reply and one hasn't been sent
+ // yet.
+ if (msg.isReplyRequired() && !msg.isDelayedReply()) {
+ if (!fail) {
+ // normal reply
+ qDBusDebug() << this << "Automatically sending reply:" << outputArgs;
+ send(msg.createReply(outputArgs));
+ } else {
+ // generate internal error
+ qWarning("Internal error: Failed to deliver message");
+ send(msg.createErrorReply(QDBusError::InternalError,
+ QLatin1String("Failed to deliver message")));
+ }
+ }
+
+ return;
+}
+
+extern bool qDBusInitThreads();
+
+QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *p)
+ : QObject(p), ref(1), capabilities(0), mode(InvalidMode), connection(0), server(0), busService(0),
+ watchAndTimeoutLock(QMutex::Recursive),
+ rootNode(QString(QLatin1Char('/')))
+{
+ static const bool threads = q_dbus_threads_init_default();
+ static const int debugging = qgetenv("QDBUS_DEBUG").toInt();
+ ::isDebugging = debugging;
+ Q_UNUSED(threads)
+ Q_UNUSED(debugging)
+
+#ifdef QDBUS_THREAD_DEBUG
+ if (debugging > 1)
+ qdbusThreadDebug = qdbusDefaultThreadDebug;
+#endif
+
+ QDBusMetaTypeId::init();
+
+ rootNode.flags = 0;
+
+ // prepopulate watchedServices:
+ // we know that the owner of org.freedesktop.DBus is itself
+ watchedServices.insert(dbusServiceString(), WatchedServiceData(dbusServiceString(), 1));
+
+ // prepopulate matchRefCounts:
+ // we know that org.freedesktop.DBus will never change owners
+ matchRefCounts.insert("type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='org.freedesktop.DBus'", 1);
+}
+
+QDBusConnectionPrivate::~QDBusConnectionPrivate()
+{
+ if (thread() && thread() != QThread::currentThread())
+ qWarning("QDBusConnection(name=\"%s\")'s last reference in not in its creation thread! "
+ "Timer and socket errors will follow and the program will probably crash",
+ qPrintable(name));
+
+ closeConnection();
+ rootNode.children.clear(); // free resources
+ qDeleteAll(cachedMetaObjects);
+
+ if (server)
+ q_dbus_server_unref(server);
+ if (connection)
+ q_dbus_connection_unref(connection);
+
+ connection = 0;
+ server = 0;
+}
+
+void QDBusConnectionPrivate::deleteYourself()
+{
+ if (thread() && thread() != QThread::currentThread()) {
+ // last reference dropped while not in the correct thread
+ // ask the correct thread to delete
+
+ // note: since we're posting an event to another thread, we
+ // must consider deleteLater() to take effect immediately
+ deleteLater();
+ } else {
+ delete this;
+ }
+}
+
+void QDBusConnectionPrivate::closeConnection()
+{
+ QDBusWriteLocker locker(CloseConnectionAction, this);
+ ConnectionMode oldMode = mode;
+ mode = InvalidMode; // prevent reentrancy
+ baseService.clear();
+
+ if (server)
+ q_dbus_server_disconnect(server);
+
+ if (oldMode == ClientMode || oldMode == PeerMode) {
+ if (connection) {
+ q_dbus_connection_close(connection);
+ // send the "close" message
+ while (q_dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS)
+ ;
+ }
+ }
+}
+
+void QDBusConnectionPrivate::checkThread()
+{
+ if (!thread()) {
+ if (QCoreApplication::instance())
+ moveToThread(QCoreApplication::instance()->thread());
+ else
+ qWarning("The thread that had QDBusConnection('%s') has died and there is no main thread",
+ qPrintable(name));
+ }
+}
+
+bool QDBusConnectionPrivate::handleError(const QDBusErrorInternal &error)
+{
+ if (!error)
+ return false; // no error
+
+ //lock.lockForWrite();
+ lastError = error;
+ //lock.unlock();
+ return true;
+}
+
+void QDBusConnectionPrivate::timerEvent(QTimerEvent *e)
+{
+ {
+ QDBusWatchAndTimeoutLocker locker(TimerEventAction, this);
+ DBusTimeout *timeout = timeouts.value(e->timerId(), 0);
+ if (timeout)
+ q_dbus_timeout_handle(timeout);
+ }
+
+ doDispatch();
+}
+
+void QDBusConnectionPrivate::customEvent(QEvent *e)
+{
+ Q_ASSERT(e->type() == QEvent::User);
+
+ QDBusConnectionCallbackEvent *ev = static_cast<QDBusConnectionCallbackEvent *>(e);
+ QDBusLockerBase::reportThreadAction(int(AddTimeoutAction) + int(ev->subtype),
+ QDBusLockerBase::BeforeDeliver, this);
+ switch (ev->subtype)
+ {
+ case QDBusConnectionCallbackEvent::AddTimeout: {
+ QDBusWatchAndTimeoutLocker locker(RealAddTimeoutAction, this);
+ while (!timeoutsPendingAdd.isEmpty()) {
+ QPair<DBusTimeout *, int> entry = timeoutsPendingAdd.takeFirst();
+ qDBusRealAddTimeout(this, entry.first, entry.second);
+ }
+ break;
+ }
+
+ case QDBusConnectionCallbackEvent::KillTimer:
+ killTimer(ev->timerId);
+ break;
+
+ case QDBusConnectionCallbackEvent::AddWatch:
+ qDBusRealAddWatch(this, ev->watch, ev->extra, ev->fd);
+ break;
+
+ case QDBusConnectionCallbackEvent::ToggleWatch:
+ qDBusRealToggleWatch(this, ev->watch, ev->fd);
+ break;
+ }
+ QDBusLockerBase::reportThreadAction(int(AddTimeoutAction) + int(ev->subtype),
+ QDBusLockerBase::AfterDeliver, this);
+}
+
+void QDBusConnectionPrivate::doDispatch()
+{
+ QDBusDispatchLocker locker(DoDispatchAction, this);
+ if (mode == ClientMode || mode == PeerMode)
+ while (q_dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS) ;
+}
+
+void QDBusConnectionPrivate::socketRead(int fd)
+{
+ QVarLengthArray<DBusWatch *, 2> pendingWatches;
+
+ {
+ QDBusWatchAndTimeoutLocker locker(SocketReadAction, this);
+ WatcherHash::ConstIterator it = watchers.constFind(fd);
+ while (it != watchers.constEnd() && it.key() == fd) {
+ if (it->watch && it->read && it->read->isEnabled())
+ pendingWatches.append(it.value().watch);
+ ++it;
+ }
+ }
+
+ for (int i = 0; i < pendingWatches.size(); ++i)
+ if (!q_dbus_watch_handle(pendingWatches[i], DBUS_WATCH_READABLE))
+ qDebug("OUT OF MEM");
+ doDispatch();
+}
+
+void QDBusConnectionPrivate::socketWrite(int fd)
+{
+ QVarLengthArray<DBusWatch *, 2> pendingWatches;
+
+ {
+ QDBusWatchAndTimeoutLocker locker(SocketWriteAction, this);
+ WatcherHash::ConstIterator it = watchers.constFind(fd);
+ while (it != watchers.constEnd() && it.key() == fd) {
+ if (it->watch && it->write && it->write->isEnabled())
+ pendingWatches.append(it.value().watch);
+ ++it;
+ }
+ }
+
+ for (int i = 0; i < pendingWatches.size(); ++i)
+ if (!q_dbus_watch_handle(pendingWatches[i], DBUS_WATCH_WRITABLE))
+ qDebug("OUT OF MEM");
+}
+
+void QDBusConnectionPrivate::objectDestroyed(QObject *obj)
+{
+ QDBusWriteLocker locker(ObjectDestroyedAction, this);
+ huntAndDestroy(obj, rootNode);
+
+ SignalHookHash::iterator sit = signalHooks.begin();
+ while (sit != signalHooks.end()) {
+ if (static_cast<QObject *>(sit.value().obj) == obj)
+ sit = disconnectSignal(sit);
+ else
+ ++sit;
+ }
+
+ obj->disconnect(this);
+}
+
+void QDBusConnectionPrivate::relaySignal(QObject *obj, const QMetaObject *mo, int signalId,
+ const QVariantList &args)
+{
+ QString interface = qDBusInterfaceFromMetaObject(mo);
+
+ QMetaMethod mm = mo->method(signalId);
+ QByteArray memberName = mm.signature();
+ memberName.truncate(memberName.indexOf('('));
+
+ // check if it's scriptable
+ bool isScriptable = mm.attributes() & QMetaMethod::Scriptable;
+ bool isAdaptor = false;
+ for ( ; mo; mo = mo->superClass())
+ if (mo == &QDBusAbstractAdaptor::staticMetaObject) {
+ isAdaptor = true;
+ break;
+ }
+
+ QDBusReadLocker locker(RelaySignalAction, this);
+ QDBusMessage message = QDBusMessage::createSignal(QLatin1String("/"), interface,
+ QLatin1String(memberName));
+ QDBusMessagePrivate::setParametersValidated(message, true);
+ message.setArguments(args);
+ QDBusError error;
+ DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, capabilities, &error);
+ if (!msg) {
+ qWarning("QDBusConnection: Could not emit signal %s.%s: %s", qPrintable(interface), memberName.constData(),
+ qPrintable(error.message()));
+ lastError = error;
+ return;
+ }
+
+ //qDBusDebug() << "Emitting signal" << message;
+ //qDBusDebug() << "for paths:";
+ q_dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything
+ huntAndEmit(connection, msg, obj, rootNode, isScriptable, isAdaptor);
+ q_dbus_message_unref(msg);
+}
+
+void QDBusConnectionPrivate::serviceOwnerChangedNoLock(const QString &name,
+ const QString &oldOwner, const QString &newOwner)
+{
+ Q_UNUSED(oldOwner);
+// QDBusWriteLocker locker(UpdateSignalHookOwnerAction, this);
+ WatchedServicesHash::Iterator it = watchedServices.find(name);
+ if (it == watchedServices.end())
+ return;
+ if (oldOwner != it->owner)
+ qWarning("QDBusConnection: name '%s' had owner '%s' but we thought it was '%s'",
+ qPrintable(name), qPrintable(oldOwner), qPrintable(it->owner));
+
+ qDBusDebug() << this << "Updating name" << name << "from" << oldOwner << "to" << newOwner;
+ it->owner = newOwner;
+}
+
+int QDBusConnectionPrivate::findSlot(QObject* obj, const QByteArray &normalizedName,
+ QList<int> &params)
+{
+ int midx = obj->metaObject()->indexOfMethod(normalizedName);
+ if (midx == -1)
+ return -1;
+
+ int inputCount = qDBusParametersForMethod(obj->metaObject()->method(midx), params);
+ if ( inputCount == -1 || inputCount + 1 != params.count() )
+ return -1; // failed to parse or invalid arguments or output arguments
+
+ return midx;
+}
+
+bool QDBusConnectionPrivate::prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
+ const QString &service,
+ const QString &path, const QString &interface, const QString &name,
+ const QStringList &argMatch,
+ QObject *receiver, const char *signal, int minMIdx,
+ bool buildSignature)
+{
+ QByteArray normalizedName = signal + 1;
+ hook.midx = findSlot(receiver, signal + 1, hook.params);
+ if (hook.midx == -1) {
+ normalizedName = QMetaObject::normalizedSignature(signal + 1);
+ hook.midx = findSlot(receiver, normalizedName, hook.params);
+ }
+ if (hook.midx < minMIdx) {
+ if (hook.midx == -1)
+ {}
+ return false;
+ }
+
+ hook.service = service;
+ hook.path = path;
+ hook.obj = receiver;
+ hook.argumentMatch = argMatch;
+
+ // build the D-Bus signal name and signature
+ // This should not happen for QDBusConnection::connect, use buildSignature here, since
+ // QDBusConnection::connect passes false and everything else uses true
+ QString mname = name;
+ if (buildSignature && mname.isNull()) {
+ normalizedName.truncate(normalizedName.indexOf('('));
+ mname = QString::fromUtf8(normalizedName);
+ }
+ key = mname;
+ key.reserve(interface.length() + 1 + mname.length());
+ key += QLatin1Char(':');
+ key += interface;
+
+ if (buildSignature) {
+ hook.signature.clear();
+ for (int i = 1; i < hook.params.count(); ++i)
+ if (hook.params.at(i) != QDBusMetaTypeId::message)
+ hook.signature += QLatin1String( QDBusMetaType::typeToSignature( hook.params.at(i) ) );
+ }
+
+ hook.matchRule = buildMatchRule(service, path, interface, mname, argMatch, hook.signature);
+ return true; // connect to this signal
+}
+
+void QDBusConnectionPrivate::sendError(const QDBusMessage &msg, QDBusError::ErrorType code)
+{
+ if (code == QDBusError::UnknownMethod) {
+ QString interfaceMsg;
+ if (msg.interface().isEmpty())
+ interfaceMsg = QLatin1String("any interface");
+ else
+ interfaceMsg = QString::fromLatin1("interface '%1'").arg(msg.interface());
+
+ send(msg.createErrorReply(code,
+ QString::fromLatin1("No such method '%1' in %2 at object path '%3' "
+ "(signature '%4')")
+ .arg(msg.member(), interfaceMsg, msg.path(), msg.signature())));
+ } else if (code == QDBusError::UnknownInterface) {
+ send(msg.createErrorReply(QDBusError::UnknownInterface,
+ QString::fromLatin1("No such interface '%1' at object path '%2'")
+ .arg(msg.interface(), msg.path())));
+ } else if (code == QDBusError::UnknownObject) {
+ send(msg.createErrorReply(QDBusError::UnknownObject,
+ QString::fromLatin1("No such object path '%1'").arg(msg.path())));
+ }
+}
+
+bool QDBusConnectionPrivate::activateInternalFilters(const ObjectTreeNode &node,
+ const QDBusMessage &msg)
+{
+ // object may be null
+ const QString interface = msg.interface();
+
+ if (interface.isEmpty() || interface == QLatin1String(DBUS_INTERFACE_INTROSPECTABLE)) {
+ if (msg.member() == QLatin1String("Introspect") && msg.signature().isEmpty()) {
+ //qDebug() << "QDBusConnectionPrivate::activateInternalFilters introspect" << msg.d_ptr->msg;
+ QDBusMessage reply = msg.createReply(qDBusIntrospectObject(node));
+ send(reply);
+ return true;
+ }
+
+ if (!interface.isEmpty()) {
+ sendError(msg, QDBusError::UnknownMethod);
+ return true;
+ }
+ }
+
+ if (node.obj && (interface.isEmpty() ||
+ interface == QLatin1String(DBUS_INTERFACE_PROPERTIES))) {
+ //qDebug() << "QDBusConnectionPrivate::activateInternalFilters properties" << msg.d_ptr->msg;
+ if (msg.member() == QLatin1String("Get") && msg.signature() == QLatin1String("ss")) {
+ QDBusMessage reply = qDBusPropertyGet(node, msg);
+ send(reply);
+ return true;
+ } else if (msg.member() == QLatin1String("Set") && msg.signature() == QLatin1String("ssv")) {
+ QDBusMessage reply = qDBusPropertySet(node, msg);
+ send(reply);
+ return true;
+ } else if (msg.member() == QLatin1String("GetAll") && msg.signature() == QLatin1String("s")) {
+ QDBusMessage reply = qDBusPropertyGetAll(node, msg);
+ send(reply);
+ return true;
+ }
+
+ if (!interface.isEmpty()) {
+ sendError(msg, QDBusError::UnknownMethod);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void QDBusConnectionPrivate::activateObject(ObjectTreeNode &node, const QDBusMessage &msg,
+ int pathStartPos)
+{
+ // This is called by QDBusConnectionPrivate::handleObjectCall to place a call to a slot
+ // on the object.
+ //
+ // The call is routed through the adaptor sub-objects if we have any
+
+ // object may be null
+
+ if (pathStartPos != msg.path().length()) {
+ node.flags &= ~QDBusConnection::ExportAllSignals;
+ node.obj = findChildObject(&node, msg.path(), pathStartPos);
+ if (!node.obj) {
+ sendError(msg, QDBusError::UnknownObject);
+ return;
+ }
+ }
+
+ QDBusAdaptorConnector *connector;
+ if (node.flags & QDBusConnection::ExportAdaptors &&
+ (connector = qDBusFindAdaptorConnector(node.obj))) {
+ int newflags = node.flags | QDBusConnection::ExportAllSlots;
+
+ if (msg.interface().isEmpty()) {
+ // place the call in all interfaces
+ // let the first one that handles it to work
+ QDBusAdaptorConnector::AdaptorMap::ConstIterator it =
+ connector->adaptors.constBegin();
+ QDBusAdaptorConnector::AdaptorMap::ConstIterator end =
+ connector->adaptors.constEnd();
+
+ for ( ; it != end; ++it)
+ if (activateCall(it->adaptor, newflags, msg))
+ return;
+ } else {
+ // check if we have an interface matching the name that was asked:
+ QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
+ it = qLowerBound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
+ msg.interface());
+ if (it != connector->adaptors.constEnd() && msg.interface() == QLatin1String(it->interface)) {
+ if (!activateCall(it->adaptor, newflags, msg))
+ sendError(msg, QDBusError::UnknownMethod);
+ return;
+ }
+ }
+ }
+
+ // no adaptors matched or were exported
+ // try our standard filters
+ if (activateInternalFilters(node, msg))
+ return; // internal filters have already run or an error has been sent
+
+ // try the object itself:
+ if (node.flags & (QDBusConnection::ExportScriptableSlots|QDBusConnection::ExportNonScriptableSlots) ||
+ node.flags & (QDBusConnection::ExportScriptableInvokables|QDBusConnection::ExportNonScriptableInvokables)) {
+ bool interfaceFound = true;
+ if (!msg.interface().isEmpty())
+ interfaceFound = qDBusInterfaceInObject(node.obj, msg.interface());
+
+ if (interfaceFound) {
+ if (!activateCall(node.obj, node.flags, msg))
+ sendError(msg, QDBusError::UnknownMethod);
+ return;
+ }
+ }
+
+ // nothing matched, send an error code
+ if (msg.interface().isEmpty())
+ sendError(msg, QDBusError::UnknownMethod);
+ else
+ sendError(msg, QDBusError::UnknownInterface);
+}
+
+void QDBusConnectionPrivate::handleObjectCall(const QDBusMessage &msg)
+{
+ // if the msg is external, we were called from inside doDispatch
+ // that means the dispatchLock mutex is locked
+ // must not call out to user code in that case
+ //
+ // however, if the message is internal, handleMessage was called
+ // directly and no lock is in place. We can therefore call out to
+ // user code, if necessary
+ ObjectTreeNode result;
+ int usedLength;
+ QThread *objThread = 0;
+ QSemaphore sem;
+ bool semWait;
+
+ {
+ QDBusReadLocker locker(HandleObjectCallAction, this);
+ if (!findObject(&rootNode, msg.path(), usedLength, result)) {
+ // qDebug("Call failed: no object found at %s", qPrintable(msg.path()));
+ sendError(msg, QDBusError::UnknownObject);
+ return;
+ }
+
+ if (!result.obj) {
+ // no object -> no threading issues
+ // it's either going to be an error, or an internal filter
+ activateObject(result, msg, usedLength);
+ return;
+ }
+
+ objThread = result.obj->thread();
+ if (!objThread) {
+ send(msg.createErrorReply(QDBusError::InternalError,
+ QString::fromLatin1("Object '%1' (at path '%2')"
+ " has no thread. Cannot deliver message.")
+ .arg(result.obj->objectName(), msg.path())));
+ return;
+ }
+
+ if (!QDBusMessagePrivate::isLocal(msg)) {
+ // external incoming message
+ // post it and forget
+ postEventToThread(HandleObjectCallPostEventAction, result.obj,
+ new QDBusActivateObjectEvent(QDBusConnection(this), this, result,
+ usedLength, msg));
+ return;
+ } else if (objThread != QThread::currentThread()) {
+ // synchronize with other thread
+ postEventToThread(HandleObjectCallPostEventAction, result.obj,
+ new QDBusActivateObjectEvent(QDBusConnection(this), this, result,
+ usedLength, msg, &sem));
+ semWait = true;
+ } else {
+ semWait = false;
+ }
+ } // release the lock
+
+ if (semWait)
+ SEM_ACQUIRE(HandleObjectCallSemaphoreAction, sem);
+ else
+ activateObject(result, msg, usedLength);
+}
+
+QDBusActivateObjectEvent::~QDBusActivateObjectEvent()
+{
+ if (!handled) {
+ // we're being destroyed without delivering
+ // it means the object was deleted between posting and delivering
+ QDBusConnectionPrivate *that = QDBusConnectionPrivate::d(connection);
+ that->sendError(message, QDBusError::UnknownObject);
+ }
+
+ // semaphore releasing happens in ~QMetaCallEvent
+}
+
+void QDBusActivateObjectEvent::placeMetaCall(QObject *)
+{
+ QDBusConnectionPrivate *that = QDBusConnectionPrivate::d(connection);
+
+ QDBusLockerBase::reportThreadAction(HandleObjectCallPostEventAction,
+ QDBusLockerBase::BeforeDeliver, that);
+ that->activateObject(node, message, pathStartPos);
+ QDBusLockerBase::reportThreadAction(HandleObjectCallPostEventAction,
+ QDBusLockerBase::AfterDeliver, that);
+
+ handled = true;
+}
+
+void QDBusConnectionPrivate::handleSignal(const QString &key, const QDBusMessage& msg)
+{
+ SignalHookHash::const_iterator it = signalHooks.find(key);
+ SignalHookHash::const_iterator end = signalHooks.constEnd();
+ //qDebug("looking for: %s", path.toLocal8Bit().constData());
+ //qDBusDebug() << signalHooks.keys();
+ for ( ; it != end && it.key() == key; ++it) {
+ const SignalHook &hook = it.value();
+ if (!hook.service.isEmpty()) {
+ const QString owner =
+ shouldWatchService(hook.service) ?
+ watchedServices.value(hook.service).owner :
+ hook.service;
+ if (owner != msg.service())
+ continue;
+ }
+ if (!hook.path.isEmpty() && hook.path != msg.path())
+ continue;
+ if (!hook.signature.isEmpty() && hook.signature != msg.signature())
+ continue;
+ if (hook.signature.isEmpty() && !hook.signature.isNull() && !msg.signature().isEmpty())
+ continue;
+ if (!hook.argumentMatch.isEmpty()) {
+ const QVariantList arguments = msg.arguments();
+ if (hook.argumentMatch.size() > arguments.size())
+ continue;
+
+ bool matched = true;
+ for (int i = 0; i < hook.argumentMatch.size(); ++i) {
+ const QString &param = hook.argumentMatch.at(i);
+ if (param.isNull())
+ continue; // don't try to match against this
+ if (param == arguments.at(i).toString())
+ continue; // matched
+ matched = false;
+ break;
+ }
+ if (!matched)
+ continue;
+ }
+
+ activateSignal(hook, msg);
+ }
+}
+
+void QDBusConnectionPrivate::handleSignal(const QDBusMessage& msg)
+{
+ // We call handlesignal(QString, QDBusMessage) three times:
+ // one with member:interface
+ // one with member:
+ // one with :interface
+ // This allows us to match signals with wildcards on member or interface
+ // (but not both)
+
+ QString key = msg.member();
+ key.reserve(key.length() + 1 + msg.interface().length());
+ key += QLatin1Char(':');
+ key += msg.interface();
+
+ QDBusReadLocker locker(HandleSignalAction, this);
+ handleSignal(key, msg); // one try
+
+ key.truncate(msg.member().length() + 1); // keep the ':'
+ handleSignal(key, msg); // second try
+
+ key = QLatin1Char(':');
+ key += msg.interface();
+ handleSignal(key, msg); // third try
+}
+
+static dbus_int32_t server_slot = -1;
+
+void QDBusConnectionPrivate::setServer(DBusServer *s, const QDBusErrorInternal &error)
+{
+ if (!s) {
+ handleError(error);
+ return;
+ }
+
+ server = s;
+ mode = ServerMode;
+
+ dbus_bool_t data_allocated = q_dbus_server_allocate_data_slot(&server_slot);
+ if (data_allocated && server_slot < 0)
+ return;
+
+ dbus_bool_t watch_functions_set = q_dbus_server_set_watch_functions(server,
+ qDBusAddWatch,
+ qDBusRemoveWatch,
+ qDBusToggleWatch,
+ this, 0);
+ //qDebug() << "watch_functions_set" << watch_functions_set;
+ Q_UNUSED(watch_functions_set);
+
+ dbus_bool_t time_functions_set = q_dbus_server_set_timeout_functions(server,
+ qDBusAddTimeout,
+ qDBusRemoveTimeout,
+ qDBusToggleTimeout,
+ this, 0);
+ //qDebug() << "time_functions_set" << time_functions_set;
+ Q_UNUSED(time_functions_set);
+
+ q_dbus_server_set_new_connection_function(server, qDBusNewConnection, this, 0);
+
+ dbus_bool_t data_set = q_dbus_server_set_data(server, server_slot, this, 0);
+ //qDebug() << "data_set" << data_set;
+ Q_UNUSED(data_set);
+}
+
+void QDBusConnectionPrivate::setPeer(DBusConnection *c, const QDBusErrorInternal &error)
+{
+ if (!c) {
+ handleError(error);
+ return;
+ }
+
+ connection = c;
+ mode = PeerMode;
+
+ q_dbus_connection_set_exit_on_disconnect(connection, false);
+ q_dbus_connection_set_watch_functions(connection,
+ qDBusAddWatch,
+ qDBusRemoveWatch,
+ qDBusToggleWatch,
+ this, 0);
+ q_dbus_connection_set_timeout_functions(connection,
+ qDBusAddTimeout,
+ qDBusRemoveTimeout,
+ qDBusToggleTimeout,
+ this, 0);
+ q_dbus_connection_set_dispatch_status_function(connection, qDBusUpdateDispatchStatus, this, 0);
+ q_dbus_connection_add_filter(connection,
+ qDBusSignalFilter,
+ this, 0);
+
+ QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
+}
+
+static QDBusConnection::ConnectionCapabilities connectionCapabilies(DBusConnection *connection)
+{
+ QDBusConnection::ConnectionCapabilities result = 0;
+
+#if defined(QT_LINKED_LIBDBUS) && DBUS_VERSION < 0x010400
+ // no capabilities are possible
+#else
+# if !defined(QT_LINKED_LIBDBUS)
+ // run-time check if the next functions are available
+ int major, minor, micro;
+ q_dbus_get_version(&major, &minor, &micro);
+ if (major == 1 && minor < 4)
+ return result;
+# endif
+
+#ifndef DBUS_TYPE_UNIX_FD
+# define DBUS_TYPE_UNIX_FD int('h')
+#endif
+ if (q_dbus_connection_can_send_type(connection, DBUS_TYPE_UNIX_FD))
+ result |= QDBusConnection::UnixFileDescriptorPassing;
+#endif
+
+ return result;
+}
+
+void QDBusConnectionPrivate::setConnection(DBusConnection *dbc, const QDBusErrorInternal &error)
+{
+ if (!dbc) {
+ handleError(error);
+ return;
+ }
+
+ connection = dbc;
+ mode = ClientMode;
+
+ const char *service = q_dbus_bus_get_unique_name(connection);
+ Q_ASSERT(service);
+ baseService = QString::fromUtf8(service);
+ capabilities = connectionCapabilies(connection);
+
+ q_dbus_connection_set_exit_on_disconnect(connection, false);
+ q_dbus_connection_set_watch_functions(connection, qDBusAddWatch, qDBusRemoveWatch,
+ qDBusToggleWatch, this, 0);
+ q_dbus_connection_set_timeout_functions(connection, qDBusAddTimeout, qDBusRemoveTimeout,
+ qDBusToggleTimeout, this, 0);
+ q_dbus_connection_set_dispatch_status_function(connection, qDBusUpdateDispatchStatus, this, 0);
+ q_dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0);
+
+ // Initialize the hooks for the NameAcquired and NameLost signals
+ // we don't use connectSignal here because we don't need the rules to be sent to the bus
+ // the bus will always send us these two signals
+ SignalHook hook;
+ hook.service = dbusServiceString();
+ hook.path.clear(); // no matching
+ hook.obj = this;
+ hook.params << QMetaType::Void << QVariant::String; // both functions take a QString as parameter and return void
+
+ hook.midx = staticMetaObject.indexOfSlot("registerServiceNoLock(QString)");
+ Q_ASSERT(hook.midx != -1);
+ signalHooks.insert(QLatin1String("NameAcquired:" DBUS_INTERFACE_DBUS), hook);
+
+ hook.midx = staticMetaObject.indexOfSlot("unregisterServiceNoLock(QString)");
+ Q_ASSERT(hook.midx != -1);
+ signalHooks.insert(QLatin1String("NameLost:" DBUS_INTERFACE_DBUS), hook);
+
+ qDBusDebug() << this << ": connected successfully";
+
+ // schedule a dispatch:
+ QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
+}
+
+extern "C"{
+static void qDBusResultReceived(DBusPendingCall *pending, void *user_data)
+{
+ QDBusPendingCallPrivate *call = reinterpret_cast<QDBusPendingCallPrivate *>(user_data);
+ Q_ASSERT(call->pending == pending);
+ Q_UNUSED(pending);
+ QDBusConnectionPrivate::processFinishedCall(call);
+}
+}
+
+void QDBusConnectionPrivate::waitForFinished(QDBusPendingCallPrivate *pcall)
+{
+ Q_ASSERT(pcall->pending);
+ Q_ASSERT(!pcall->autoDelete);
+ //Q_ASSERT(pcall->mutex.isLocked()); // there's no such function
+
+ if (pcall->waitingForFinished) {
+ // another thread is already waiting
+ pcall->waitForFinishedCondition.wait(&pcall->mutex);
+ } else {
+ pcall->waitingForFinished = true;
+ pcall->mutex.unlock();
+
+ {
+ QDBusDispatchLocker locker(PendingCallBlockAction, this);
+ q_dbus_pending_call_block(pcall->pending);
+ // QDBusConnectionPrivate::processFinishedCall() is called automatically
+ }
+ pcall->mutex.lock();
+ }
+}
+
+void QDBusConnectionPrivate::processFinishedCall(QDBusPendingCallPrivate *call)
+{
+ QDBusConnectionPrivate *connection = const_cast<QDBusConnectionPrivate *>(call->connection);
+
+ QMutexLocker locker(&call->mutex);
+
+ QDBusMessage &msg = call->replyMessage;
+ if (call->pending) {
+ // decode the message
+ DBusMessage *reply = q_dbus_pending_call_steal_reply(call->pending);
+ msg = QDBusMessagePrivate::fromDBusMessage(reply, connection->capabilities);
+ q_dbus_message_unref(reply);
+ }
+ qDBusDebug() << connection << "got message reply (async):" << msg;
+
+ // Check if the reply has the expected signature
+ call->checkReceivedSignature();
+
+ if (!call->receiver.isNull() && call->methodIdx != -1 && msg.type() == QDBusMessage::ReplyMessage) {
+ // Deliver the return values of a remote function call.
+ //
+ // There is only one connection and it is specified by idx
+ // The slot must have the same parameter types that the message does
+ // The slot may have less parameters than the message
+ // The slot may optionally have one final parameter that is QDBusMessage
+ // The slot receives read-only copies of the message (i.e., pass by value or by const-ref)
+
+ QDBusCallDeliveryEvent *e = prepareReply(connection, call->receiver, call->methodIdx,
+ call->metaTypes, msg);
+ if (e)
+ connection->postEventToThread(MessageResultReceivedAction, call->receiver, e);
+ else
+ qDBusDebug() << "Deliver failed!";
+ }
+
+ if (call->pending)
+ q_dbus_pending_call_unref(call->pending);
+ call->pending = 0;
+
+ locker.unlock();
+
+ // Are there any watchers?
+ if (call->watcherHelper)
+ call->watcherHelper->emitSignals(msg, call->sentMessage);
+
+ if (msg.type() == QDBusMessage::ErrorMessage)
+ emit connection->callWithCallbackFailed(QDBusError(msg), call->sentMessage);
+
+ if (call->autoDelete) {
+ Q_ASSERT(!call->waitingForFinished); // can't wait on a call with autoDelete!
+ delete call;
+ }
+}
+
+int QDBusConnectionPrivate::send(const QDBusMessage& message)
+{
+ if (QDBusMessagePrivate::isLocal(message))
+ return -1; // don't send; the reply will be retrieved by the caller
+ // through the d_ptr->localReply link
+
+ QDBusError error;
+ DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, capabilities, &error);
+ if (!msg) {
+ if (message.type() == QDBusMessage::MethodCallMessage)
+ qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\": %s",
+ qPrintable(message.service()), qPrintable(message.path()),
+ qPrintable(message.interface()), qPrintable(message.member()),
+ qPrintable(error.message()));
+ else if (message.type() == QDBusMessage::SignalMessage)
+ qWarning("QDBusConnection: error: could not send signal path \"%s\" interface \"%s\" member \"%s\": %s",
+ qPrintable(message.path()), qPrintable(message.interface()),
+ qPrintable(message.member()),
+ qPrintable(error.message()));
+ else
+ qWarning("QDBusConnection: error: could not send %s message to service \"%s\": %s",
+ message.type() == QDBusMessage::ReplyMessage ? "reply" :
+ message.type() == QDBusMessage::ErrorMessage ? "error" :
+ "invalid", qPrintable(message.service()),
+ qPrintable(error.message()));
+ lastError = error;
+ return 0;
+ }
+
+ q_dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything
+
+ qDBusDebug() << this << "sending message (no reply):" << message;
+ checkThread();
+ bool isOk = q_dbus_connection_send(connection, msg, 0);
+ int serial = 0;
+ if (isOk)
+ serial = q_dbus_message_get_serial(msg);
+
+ q_dbus_message_unref(msg);
+ return serial;
+}
+
+QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
+ int sendMode, int timeout)
+{
+ checkThread();
+ if ((sendMode == QDBus::BlockWithGui || sendMode == QDBus::Block)
+ && isServiceRegisteredByThread(message.service()))
+ // special case for synchronous local calls
+ return sendWithReplyLocal(message);
+
+ if (!QCoreApplication::instance() || sendMode == QDBus::Block) {
+ QDBusError err;
+ DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, capabilities, &err);
+ if (!msg) {
+ qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\": %s",
+ qPrintable(message.service()), qPrintable(message.path()),
+ qPrintable(message.interface()), qPrintable(message.member()),
+ qPrintable(err.message()));
+ lastError = err;
+ return QDBusMessage::createError(err);
+ }
+
+ qDBusDebug() << this << "sending message (blocking):" << message;
+ QDBusErrorInternal error;
+ DBusMessage *reply = q_dbus_connection_send_with_reply_and_block(connection, msg, timeout, error);
+
+ q_dbus_message_unref(msg);
+
+ if (!!error) {
+ lastError = err = error;
+ return QDBusMessage::createError(err);
+ }
+
+ QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(reply, capabilities);
+ q_dbus_message_unref(reply);
+ qDBusDebug() << this << "got message reply (blocking):" << amsg;
+
+ return amsg;
+ } else { // use the event loop
+ QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout);
+ Q_ASSERT(pcall);
+
+ if (pcall->replyMessage.type() == QDBusMessage::InvalidMessage) {
+ pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
+ QEventLoop loop;
+ loop.connect(pcall->watcherHelper, SIGNAL(reply(QDBusMessage)), SLOT(quit()));
+ loop.connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), SLOT(quit()));
+
+ // enter the event loop and wait for a reply
+ loop.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
+ }
+
+ QDBusMessage reply = pcall->replyMessage;
+ lastError = reply; // set or clear error
+
+ delete pcall;
+ return reply;
+ }
+}
+
+QDBusMessage QDBusConnectionPrivate::sendWithReplyLocal(const QDBusMessage &message)
+{
+ qDBusDebug() << this << "sending message via local-loop:" << message;
+
+ QDBusMessage localCallMsg = QDBusMessagePrivate::makeLocal(*this, message);
+ bool handled = handleMessage(localCallMsg);
+
+ if (!handled) {
+ QString interface = message.interface();
+ if (interface.isEmpty())
+ interface = QLatin1String("<no-interface>");
+ return QDBusMessage::createError(QDBusError::InternalError,
+ QString::fromLatin1("Internal error trying to call %1.%2 at %3 (signature '%4'")
+ .arg(interface, message.member(),
+ message.path(), message.signature()));
+ }
+
+ // if the message was handled, there might be a reply
+ QDBusMessage localReplyMsg = QDBusMessagePrivate::makeLocalReply(*this, localCallMsg);
+ if (localReplyMsg.type() == QDBusMessage::InvalidMessage) {
+ qWarning("QDBusConnection: cannot call local method '%s' at object %s (with signature '%s') "
+ "on blocking mode", qPrintable(message.member()), qPrintable(message.path()),
+ qPrintable(message.signature()));
+ return QDBusMessage::createError(
+ QDBusError(QDBusError::InternalError,
+ QLatin1String("local-loop message cannot have delayed replies")));
+ }
+
+ // there is a reply
+ qDBusDebug() << this << "got message via local-loop:" << localReplyMsg;
+ return localReplyMsg;
+}
+
+QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message,
+ int timeout)
+{
+ if (isServiceRegisteredByThread(message.service())) {
+ // special case for local calls
+ QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate(message, this);
+ pcall->replyMessage = sendWithReplyLocal(message);
+
+ return pcall;
+ }
+
+ checkThread();
+ QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate(message, this);
+ pcall->ref = 0;
+
+ QDBusError error;
+ DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, capabilities, &error);
+ if (!msg) {
+ qWarning("QDBusConnection: error: could not send message to service \"%s\" path \"%s\" interface \"%s\" member \"%s\": %s",
+ qPrintable(message.service()), qPrintable(message.path()),
+ qPrintable(message.interface()), qPrintable(message.member()),
+ qPrintable(error.message()));
+ pcall->replyMessage = QDBusMessage::createError(error);
+ lastError = error;
+ return pcall;
+ }
+
+ qDBusDebug() << this << "sending message (async):" << message;
+ DBusPendingCall *pending = 0;
+
+ QDBusDispatchLocker locker(SendWithReplyAsyncAction, this);
+ if (q_dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
+ if (pending) {
+ q_dbus_message_unref(msg);
+
+ pcall->pending = pending;
+ q_dbus_pending_call_set_notify(pending, qDBusResultReceived, pcall, 0);
+
+ return pcall;
+ } else {
+ // we're probably disconnected at this point
+ lastError = error = QDBusError(QDBusError::Disconnected, QLatin1String("Not connected to server"));
+ }
+ } else {
+ lastError = error = QDBusError(QDBusError::NoMemory, QLatin1String("Out of memory"));
+ }
+
+ q_dbus_message_unref(msg);
+ pcall->replyMessage = QDBusMessage::createError(error);
+ return pcall;
+}
+
+int QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
+ const char *returnMethod, const char *errorMethod,
+ int timeout)
+{
+ QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout);
+ Q_ASSERT(pcall);
+
+ // has it already finished with success (dispatched locally)?
+ if (pcall->replyMessage.type() == QDBusMessage::ReplyMessage) {
+ pcall->setReplyCallback(receiver, returnMethod);
+ processFinishedCall(pcall);
+ delete pcall;
+ return 1;
+ }
+
+ // either it hasn't finished or it has finished with error
+ if (errorMethod) {
+ pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
+ connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod,
+ Qt::QueuedConnection);
+ pcall->watcherHelper->moveToThread(thread());
+ }
+
+ // has it already finished and is an error reply message?
+ if (pcall->replyMessage.type() == QDBusMessage::ErrorMessage) {
+ processFinishedCall(pcall);
+ delete pcall;
+ return 1;
+ }
+
+ pcall->autoDelete = true;
+ pcall->ref.ref();
+ pcall->setReplyCallback(receiver, returnMethod);
+
+ return 1;
+}
+
+bool QDBusConnectionPrivate::connectSignal(const QString &service,
+ const QString &path, const QString &interface, const QString &name,
+ const QStringList &argumentMatch, const QString &signature,
+ QObject *receiver, const char *slot)
+{
+ // check the slot
+ QDBusConnectionPrivate::SignalHook hook;
+ QString key;
+ QString name2 = name;
+ if (name2.isNull())
+ name2.detach();
+
+ hook.signature = signature;
+ if (!prepareHook(hook, key, service, path, interface, name, argumentMatch, receiver, slot, 0, false))
+ return false; // don't connect
+
+ // avoid duplicating:
+ QDBusConnectionPrivate::SignalHookHash::ConstIterator it = signalHooks.find(key);
+ QDBusConnectionPrivate::SignalHookHash::ConstIterator end = signalHooks.constEnd();
+ for ( ; it != end && it.key() == key; ++it) {
+ const QDBusConnectionPrivate::SignalHook &entry = it.value();
+ if (entry.service == hook.service &&
+ entry.path == hook.path &&
+ entry.signature == hook.signature &&
+ entry.obj == hook.obj &&
+ entry.midx == hook.midx &&
+ entry.argumentMatch == hook.argumentMatch) {
+ // no need to compare the parameters if it's the same slot
+ return true; // already there
+ }
+ }
+
+ connectSignal(key, hook);
+ return true;
+}
+
+void QDBusConnectionPrivate::connectSignal(const QString &key, const SignalHook &hook)
+{
+ signalHooks.insertMulti(key, hook);
+ connect(hook.obj, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)),
+ Qt::ConnectionType(Qt::DirectConnection | Qt::UniqueConnection));
+
+ MatchRefCountHash::iterator it = matchRefCounts.find(hook.matchRule);
+
+ if (it != matchRefCounts.end()) { // Match already present
+ it.value() = it.value() + 1;
+ return;
+ }
+
+ matchRefCounts.insert(hook.matchRule, 1);
+
+ if (connection) {
+ if (mode != QDBusConnectionPrivate::PeerMode) {
+ qDBusDebug("Adding rule: %s", hook.matchRule.constData());
+ q_dbus_bus_add_match(connection, hook.matchRule, NULL);
+
+ // Successfully connected the signal
+ // Do we need to watch for this name?
+ if (shouldWatchService(hook.service)) {
+ WatchedServicesHash::mapped_type &data = watchedServices[hook.service];
+ if (++data.refcount == 1) {
+ // we need to watch for this service changing
+ connectSignal(dbusServiceString(), QString(), dbusInterfaceString(),
+ QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
+ this, SLOT(serviceOwnerChangedNoLock(QString,QString,QString)));
+ data.owner = getNameOwnerNoCache(hook.service);
+ qDBusDebug() << this << "Watching service" << hook.service << "for owner changes (current owner:"
+ << data.owner << ")";
+ }
+ }
+ }
+ }
+}
+
+bool QDBusConnectionPrivate::disconnectSignal(const QString &service,
+ const QString &path, const QString &interface, const QString &name,
+ const QStringList &argumentMatch, const QString &signature,
+ QObject *receiver, const char *slot)
+{
+ // check the slot
+ QDBusConnectionPrivate::SignalHook hook;
+ QString key;
+ QString name2 = name;
+ if (name2.isNull())
+ name2.detach();
+
+ hook.signature = signature;
+ if (!prepareHook(hook, key, service, path, interface, name, argumentMatch, receiver, slot, 0, false))
+ return false; // don't disconnect
+
+ // avoid duplicating:
+ QDBusConnectionPrivate::SignalHookHash::Iterator it = signalHooks.find(key);
+ QDBusConnectionPrivate::SignalHookHash::Iterator end = signalHooks.end();
+ for ( ; it != end && it.key() == key; ++it) {
+ const QDBusConnectionPrivate::SignalHook &entry = it.value();
+ if (entry.service == hook.service &&
+ entry.path == hook.path &&
+ entry.signature == hook.signature &&
+ entry.obj == hook.obj &&
+ entry.midx == hook.midx &&
+ entry.argumentMatch == hook.argumentMatch) {
+ // no need to compare the parameters if it's the same slot
+ disconnectSignal(it);
+ return true; // it was there
+ }
+ }
+
+ // the slot was not found
+ return false;
+}
+
+QDBusConnectionPrivate::SignalHookHash::Iterator
+QDBusConnectionPrivate::disconnectSignal(SignalHookHash::Iterator &it)
+{
+ const SignalHook &hook = it.value();
+
+ bool erase = false;
+ MatchRefCountHash::iterator i = matchRefCounts.find(hook.matchRule);
+ if (i == matchRefCounts.end()) {
+ qWarning("QDBusConnectionPrivate::disconnectSignal: MatchRule not found in matchRefCounts!!");
+ } else {
+ if (i.value() == 1) {
+ erase = true;
+ matchRefCounts.erase(i);
+ }
+ else {
+ i.value() = i.value() - 1;
+ }
+ }
+
+ // we don't care about errors here
+ if (connection && erase) {
+ if (mode != QDBusConnectionPrivate::PeerMode) {
+ qDBusDebug("Removing rule: %s", hook.matchRule.constData());
+ q_dbus_bus_remove_match(connection, hook.matchRule, NULL);
+
+ // Successfully disconnected the signal
+ // Were we watching for this name?
+ WatchedServicesHash::Iterator sit = watchedServices.find(hook.service);
+ if (sit != watchedServices.end()) {
+ if (--sit.value().refcount == 0) {
+ watchedServices.erase(sit);
+ disconnectSignal(dbusServiceString(), QString(), dbusInterfaceString(),
+ QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(),
+ this, SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
+ }
+ }
+ }
+
+ }
+
+ return signalHooks.erase(it);
+}
+
+void QDBusConnectionPrivate::registerObject(const ObjectTreeNode *node)
+{
+ connect(node->obj, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)),
+ Qt::DirectConnection);
+
+ if (node->flags & (QDBusConnection::ExportAdaptors
+ | QDBusConnection::ExportScriptableSignals
+ | QDBusConnection::ExportNonScriptableSignals)) {
+ QDBusAdaptorConnector *connector = qDBusCreateAdaptorConnector(node->obj);
+
+ if (node->flags & (QDBusConnection::ExportScriptableSignals
+ | QDBusConnection::ExportNonScriptableSignals)) {
+ connector->disconnectAllSignals(node->obj);
+ connector->connectAllSignals(node->obj);
+ }
+
+ // disconnect and reconnect to avoid duplicates
+ connector->disconnect(SIGNAL(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
+ this, SLOT(relaySignal(QObject*,const QMetaObject*,int,QVariantList)));
+ connect(connector, SIGNAL(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
+ this, SLOT(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
+ Qt::DirectConnection);
+ }
+}
+
+void QDBusConnectionPrivate::connectRelay(const QString &service,
+ const QString &path, const QString &interface,
+ QDBusAbstractInterface *receiver,
+ const char *signal)
+{
+ // this function is called by QDBusAbstractInterface when one of its signals is connected
+ // we set up a relay from D-Bus into it
+ SignalHook hook;
+ QString key;
+
+ if (!prepareHook(hook, key, service, path, interface, QString(), QStringList(), receiver, signal,
+ QDBusAbstractInterface::staticMetaObject.methodCount(), true))
+ return; // don't connect
+
+ // add it to our list:
+ QDBusWriteLocker locker(ConnectRelayAction, this);
+ SignalHookHash::ConstIterator it = signalHooks.find(key);
+ SignalHookHash::ConstIterator end = signalHooks.constEnd();
+ for ( ; it != end && it.key() == key; ++it) {
+ const SignalHook &entry = it.value();
+ if (entry.service == hook.service &&
+ entry.path == hook.path &&
+ entry.signature == hook.signature &&
+ entry.obj == hook.obj &&
+ entry.midx == hook.midx)
+ return; // already there, no need to re-add
+ }
+
+ connectSignal(key, hook);
+}
+
+void QDBusConnectionPrivate::disconnectRelay(const QString &service,
+ const QString &path, const QString &interface,
+ QDBusAbstractInterface *receiver,
+ const char *signal)
+{
+ // this function is called by QDBusAbstractInterface when one of its signals is disconnected
+ // we remove relay from D-Bus into it
+ SignalHook hook;
+ QString key;
+
+ if (!prepareHook(hook, key, service, path, interface, QString(), QStringList(), receiver, signal,
+ QDBusAbstractInterface::staticMetaObject.methodCount(), true))
+ return; // don't connect
+
+ // remove it from our list:
+ QDBusWriteLocker locker(DisconnectRelayAction, this);
+ SignalHookHash::Iterator it = signalHooks.find(key);
+ SignalHookHash::Iterator end = signalHooks.end();
+ for ( ; it != end && it.key() == key; ++it) {
+ const SignalHook &entry = it.value();
+ if (entry.service == hook.service &&
+ entry.path == hook.path &&
+ entry.signature == hook.signature &&
+ entry.obj == hook.obj &&
+ entry.midx == hook.midx) {
+ // found it
+ disconnectSignal(it);
+ return;
+ }
+ }
+
+ qWarning("QDBusConnectionPrivate::disconnectRelay called for a signal that was not found");
+}
+
+QString QDBusConnectionPrivate::getNameOwner(const QString& serviceName)
+{
+ if (QDBusUtil::isValidUniqueConnectionName(serviceName))
+ return serviceName;
+ if (!connection)
+ return QString();
+
+ {
+ // acquire a read lock for the cache
+ QReadLocker locker(&lock);
+ WatchedServicesHash::ConstIterator it = watchedServices.constFind(serviceName);
+ if (it != watchedServices.constEnd())
+ return it->owner;
+ }
+
+ // not cached
+ return getNameOwnerNoCache(serviceName);
+}
+
+QString QDBusConnectionPrivate::getNameOwnerNoCache(const QString &serviceName)
+{
+ QDBusMessage msg = QDBusMessage::createMethodCall(dbusServiceString(),
+ QLatin1String(DBUS_PATH_DBUS), dbusInterfaceString(),
+ QLatin1String("GetNameOwner"));
+ QDBusMessagePrivate::setParametersValidated(msg, true);
+ msg << serviceName;
+ QDBusMessage reply = sendWithReply(msg, QDBus::Block);
+ if (reply.type() == QDBusMessage::ReplyMessage)
+ return reply.arguments().at(0).toString();
+ return QString();
+}
+
+QDBusMetaObject *
+QDBusConnectionPrivate::findMetaObject(const QString &service, const QString &path,
+ const QString &interface, QDBusError &error)
+{
+ // service must be a unique connection name
+ if (!interface.isEmpty()) {
+ QDBusReadLocker locker(FindMetaObject1Action, this);
+ QDBusMetaObject *mo = cachedMetaObjects.value(interface, 0);
+ if (mo)
+ return mo;
+ }
+
+ // introspect the target object
+ QDBusMessage msg = QDBusMessage::createMethodCall(service, path,
+ QLatin1String(DBUS_INTERFACE_INTROSPECTABLE),
+ QLatin1String("Introspect"));
+ QDBusMessagePrivate::setParametersValidated(msg, true);
+
+ QDBusMessage reply = sendWithReply(msg, QDBus::Block);
+
+ // it doesn't exist yet, we have to create it
+ QDBusWriteLocker locker(FindMetaObject2Action, this);
+ QDBusMetaObject *mo = 0;
+ if (!interface.isEmpty())
+ mo = cachedMetaObjects.value(interface, 0);
+ if (mo)
+ // maybe it got created when we switched from read to write lock
+ return mo;
+
+ QString xml;
+ if (reply.type() == QDBusMessage::ReplyMessage) {
+ if (reply.signature() == QLatin1String("s"))
+ // fetch the XML description
+ xml = reply.arguments().at(0).toString();
+ } else {
+ error = reply;
+ lastError = error;
+ if (reply.type() != QDBusMessage::ErrorMessage || error.type() != QDBusError::UnknownMethod)
+ return 0; // error
+ }
+
+ // release the lock and return
+ QDBusMetaObject *result = QDBusMetaObject::createMetaObject(interface, xml,
+ cachedMetaObjects, error);
+ lastError = error;
+ return result;
+}
+
+void QDBusConnectionPrivate::registerService(const QString &serviceName)
+{
+ QDBusWriteLocker locker(RegisterServiceAction, this);
+ registerServiceNoLock(serviceName);
+}
+
+void QDBusConnectionPrivate::registerServiceNoLock(const QString &serviceName)
+{
+ serviceNames.append(serviceName);
+}
+
+void QDBusConnectionPrivate::unregisterService(const QString &serviceName)
+{
+ QDBusWriteLocker locker(UnregisterServiceAction, this);
+ unregisterServiceNoLock(serviceName);
+}
+
+void QDBusConnectionPrivate::unregisterServiceNoLock(const QString &serviceName)
+{
+ serviceNames.removeAll(serviceName);
+}
+
+bool QDBusConnectionPrivate::isServiceRegisteredByThread(const QString &serviceName) const
+{
+ if (!serviceName.isEmpty() && serviceName == baseService)
+ return true;
+ QStringList copy = serviceNames;
+ return copy.contains(serviceName);
+}
+
+void QDBusConnectionPrivate::postEventToThread(int action, QObject *object, QEvent *ev)
+{
+ QDBusLockerBase::reportThreadAction(action, QDBusLockerBase::BeforePost, this);
+ QCoreApplication::postEvent(object, ev);
+ QDBusLockerBase::reportThreadAction(action, QDBusLockerBase::AfterPost, this);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusintegrator_p.h b/src/dbus/qdbusintegrator_p.h
new file mode 100644
index 0000000000..59255f9291
--- /dev/null
+++ b/src/dbus/qdbusintegrator_p.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+//
+
+#ifndef QDBUSINTEGRATOR_P_H
+#define QDBUSINTEGRATOR_P_H
+
+#include "qdbus_symbols_p.h"
+
+#include "qcoreevent.h"
+#include "qeventloop.h"
+#include "qhash.h"
+#include "qobject.h"
+#include "private/qobject_p.h"
+#include "qlist.h"
+#include "qpointer.h"
+#include "qsemaphore.h"
+
+#include "qdbusconnection.h"
+#include "qdbusmessage.h"
+#include "qdbusconnection_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+class QDBusConnectionPrivate;
+
+// Really private structs used by qdbusintegrator.cpp
+// Things that aren't used by any other file
+
+struct QDBusSlotCache
+{
+ struct Data
+ {
+ int flags;
+ int slotIdx;
+ QList<int> metaTypes;
+ };
+ typedef QMultiHash<QString, Data> Hash;
+ Hash hash;
+};
+
+class QDBusCallDeliveryEvent: public QMetaCallEvent
+{
+public:
+ QDBusCallDeliveryEvent(const QDBusConnection &c, int id, QObject *sender,
+ const QDBusMessage &msg, const QList<int> &types, int f = 0)
+ : QMetaCallEvent(0, id, 0, sender, -1), connection(c), message(msg), metaTypes(types), flags(f)
+ { }
+
+ void placeMetaCall(QObject *object)
+ {
+ QDBusConnectionPrivate::d(connection)->deliverCall(object, flags, message, metaTypes, id());
+ }
+
+private:
+ QDBusConnection connection; // just for refcounting
+ QDBusMessage message;
+ QList<int> metaTypes;
+ int flags;
+};
+
+class QDBusActivateObjectEvent: public QMetaCallEvent
+{
+public:
+ QDBusActivateObjectEvent(const QDBusConnection &c, QObject *sender,
+ const QDBusConnectionPrivate::ObjectTreeNode &n,
+ int p, const QDBusMessage &m, QSemaphore *s = 0)
+ : QMetaCallEvent(0, -1, 0, sender, -1, 0, 0, 0, s), connection(c), node(n),
+ pathStartPos(p), message(m), handled(false)
+ { }
+ ~QDBusActivateObjectEvent();
+
+ void placeMetaCall(QObject *);
+
+private:
+ QDBusConnection connection; // just for refcounting
+ QDBusConnectionPrivate::ObjectTreeNode node;
+ int pathStartPos;
+ QDBusMessage message;
+ bool handled;
+};
+
+class QDBusConnectionCallbackEvent : public QEvent
+{
+public:
+ QDBusConnectionCallbackEvent()
+ : QEvent(User), subtype(Subtype(0))
+ { }
+
+ DBusWatch *watch;
+ union {
+ int timerId;
+ int fd;
+ };
+ int extra;
+
+ enum Subtype {
+ AddTimeout = 0,
+ KillTimer,
+ AddWatch,
+ //RemoveWatch,
+ ToggleWatch
+ } subtype;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QDBusSlotCache)
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusinterface.cpp b/src/dbus/qdbusinterface.cpp
new file mode 100644
index 0000000000..e748b8fa7f
--- /dev/null
+++ b/src/dbus/qdbusinterface.cpp
@@ -0,0 +1,328 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusinterface.h"
+
+#include "qdbus_symbols_p.h"
+#include <QtCore/qpointer.h>
+#include <QtCore/qstringlist.h>
+
+#include "qdbusmetatype_p.h"
+#include "qdbusinterface_p.h"
+#include "qdbusconnection_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+static void copyArgument(void *to, int id, const QVariant &arg)
+{
+ if (id == arg.userType()) {
+ switch (id) {
+ case QVariant::Bool:
+ *reinterpret_cast<bool *>(to) = arg.toBool();
+ return;
+
+ case QMetaType::UChar:
+ *reinterpret_cast<uchar *>(to) = arg.value<uchar>();
+ return;
+
+ case QMetaType::Short:
+ *reinterpret_cast<short *>(to) = arg.value<short>();
+ return;
+
+ case QMetaType::UShort:
+ *reinterpret_cast<ushort *>(to) = arg.value<ushort>();
+ return;
+
+ case QVariant::Int:
+ *reinterpret_cast<int *>(to) = arg.toInt();
+ return;
+
+ case QVariant::UInt:
+ *reinterpret_cast<uint *>(to) = arg.toUInt();
+ return;
+
+ case QVariant::LongLong:
+ *reinterpret_cast<qlonglong *>(to) = arg.toLongLong();
+ return;
+
+ case QVariant::ULongLong:
+ *reinterpret_cast<qulonglong *>(to) = arg.toULongLong();
+ return;
+
+ case QVariant::Double:
+ *reinterpret_cast<double *>(to) = arg.toDouble();
+ return;
+
+ case QVariant::String:
+ *reinterpret_cast<QString *>(to) = arg.toString();
+ return;
+
+ case QVariant::ByteArray:
+ *reinterpret_cast<QByteArray *>(to) = arg.toByteArray();
+ return;
+
+ case QVariant::StringList:
+ *reinterpret_cast<QStringList *>(to) = arg.toStringList();
+ return;
+ }
+
+ if (id == QDBusMetaTypeId::variant) {
+ *reinterpret_cast<QDBusVariant *>(to) = arg.value<QDBusVariant>();
+ return;
+ } else if (id == QDBusMetaTypeId::objectpath) {
+ *reinterpret_cast<QDBusObjectPath *>(to) = arg.value<QDBusObjectPath>();
+ return;
+ } else if (id == QDBusMetaTypeId::signature) {
+ *reinterpret_cast<QDBusSignature *>(to) = arg.value<QDBusSignature>();
+ return;
+ }
+
+ // those above are the only types possible
+ // the demarshaller code doesn't demarshall anything else
+ qFatal("Found a decoded basic type in a D-Bus reply that shouldn't be there");
+ }
+
+ // if we got here, it's either an un-dermarshalled type or a mismatch
+ if (arg.userType() != QDBusMetaTypeId::argument) {
+ // it's a mismatch
+ //qWarning?
+ return;
+ }
+
+ // is this type registered?
+ const char *userSignature = QDBusMetaType::typeToSignature(id);
+ if (!userSignature || !*userSignature) {
+ // type not registered
+ //qWarning?
+ return;
+ }
+
+ // is it the same signature?
+ QDBusArgument dbarg = arg.value<QDBusArgument>();
+ if (dbarg.currentSignature() != QLatin1String(userSignature)) {
+ // not the same signature, another mismatch
+ //qWarning?
+ return;
+ }
+
+ // we can demarshall
+ QDBusMetaType::demarshall(dbarg, id, to);
+}
+
+QDBusInterfacePrivate::QDBusInterfacePrivate(const QString &serv, const QString &p,
+ const QString &iface, const QDBusConnection &con)
+ : QDBusAbstractInterfacePrivate(serv, p, iface, con, true), metaObject(0)
+{
+ // QDBusAbstractInterfacePrivate's constructor checked the parameters for us
+ if (connection.isConnected()) {
+ metaObject = connectionPrivate()->findMetaObject(service, path, interface, lastError);
+
+ if (!metaObject) {
+ // creation failed, somehow
+ // most common causes are that the service doesn't exist or doesn't support introspection
+ // those are not fatal errors, so we continue working
+
+ if (!lastError.isValid())
+ lastError = QDBusError(QDBusError::InternalError, QLatin1String("Unknown error"));
+ }
+ }
+}
+
+QDBusInterfacePrivate::~QDBusInterfacePrivate()
+{
+ if (metaObject && !metaObject->cached)
+ delete metaObject;
+}
+
+
+/*!
+ \class QDBusInterface
+ \inmodule QtDBus
+ \since 4.2
+
+ \brief The QDBusInterface class is a proxy for interfaces on remote objects.
+
+ QDBusInterface is a generic accessor class that is used to place calls to remote objects,
+ connect to signals exported by remote objects and get/set the value of remote properties. This
+ class is useful for dynamic access to remote objects: that is, when you do not have a generated
+ code that represents the remote interface.
+
+ Calls are usually placed by using the call() function, which constructs the message, sends it
+ over the bus, waits for the reply and decodes the reply. Signals are connected to by using the
+ normal QObject::connect() function. Finally, properties are accessed using the
+ QObject::property() and QObject::setProperty() functions.
+
+ The following code snippet demonstrates how to perform a
+ mathematical operation of \tt{"2 + 2"} in a remote application
+ called \c com.example.Calculator, accessed via the session bus.
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbusinterface.cpp 0
+
+ \sa {QtDBus XML compiler (qdbusxml2cpp)}
+*/
+
+/*!
+ Creates a dynamic QDBusInterface object associated with the
+ interface \a interface on object at path \a path on service \a
+ service, using the given \a connection. If \a interface is an
+ empty string, the object created will refer to the merging of all
+ interfaces found in that object.
+
+ \a parent is passed to the base class constructor.
+
+ If the remote service \a service is not present or if an error
+ occurs trying to obtain the description of the remote interface
+ \a interface, the object created will not be valid (see
+ isValid()).
+*/
+QDBusInterface::QDBusInterface(const QString &service, const QString &path, const QString &interface,
+ const QDBusConnection &connection, QObject *parent)
+ : QDBusAbstractInterface(*new QDBusInterfacePrivate(service, path, interface, connection),
+ parent)
+{
+}
+
+/*!
+ Destroy the object interface and frees up any resource used.
+*/
+QDBusInterface::~QDBusInterface()
+{
+ // resources are freed in QDBusInterfacePrivate::~QDBusInterfacePrivate()
+}
+
+/*!
+ \internal
+ Overrides QObject::metaObject to return our own copy.
+*/
+const QMetaObject *QDBusInterface::metaObject() const
+{
+ return d_func()->metaObject ? d_func()->metaObject : &QDBusAbstractInterface::staticMetaObject;
+}
+
+/*!
+ \internal
+ Override QObject::qt_metacast to catch the interface name too.
+*/
+void *QDBusInterface::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, "QDBusInterface"))
+ return static_cast<void*>(const_cast<QDBusInterface*>(this));
+ if (d_func()->interface.toLatin1() == _clname)
+ return static_cast<void*>(const_cast<QDBusInterface*>(this));
+ return QDBusAbstractInterface::qt_metacast(_clname);
+}
+
+/*!
+ \internal
+ Dispatch the call through the private.
+*/
+int QDBusInterface::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QDBusAbstractInterface::qt_metacall(_c, _id, _a);
+ if (_id < 0 || !d_func()->isValid || !d_func()->metaObject)
+ return _id;
+ return d_func()->metacall(_c, _id, _a);
+}
+
+int QDBusInterfacePrivate::metacall(QMetaObject::Call c, int id, void **argv)
+{
+ Q_Q(QDBusInterface);
+
+ if (c == QMetaObject::InvokeMetaMethod) {
+ int offset = metaObject->methodOffset();
+ QMetaMethod mm = metaObject->method(id + offset);
+
+ if (mm.methodType() == QMetaMethod::Signal) {
+ // signal relay from D-Bus world to Qt world
+ QMetaObject::activate(q, metaObject, id, argv);
+
+ } else if (mm.methodType() == QMetaMethod::Slot || mm.methodType() == QMetaMethod::Method) {
+ // method call relay from Qt world to D-Bus world
+ // get D-Bus equivalent signature
+ QString methodName = QLatin1String(metaObject->dbusNameForMethod(id));
+ const int *inputTypes = metaObject->inputTypesForMethod(id);
+ int inputTypesCount = *inputTypes;
+
+ // we will assume that the input arguments were passed correctly
+ QVariantList args;
+ int i = 1;
+ for ( ; i <= inputTypesCount; ++i)
+ args << QVariant(inputTypes[i], argv[i]);
+
+ // make the call
+ QDBusMessage reply = q->callWithArgumentList(QDBus::Block, methodName, args);
+
+ if (reply.type() == QDBusMessage::ReplyMessage) {
+ // attempt to demarshall the return values
+ args = reply.arguments();
+ QVariantList::ConstIterator it = args.constBegin();
+ const int *outputTypes = metaObject->outputTypesForMethod(id);
+ int outputTypesCount = *outputTypes++;
+
+ if (*mm.typeName()) {
+ // this method has a return type
+ if (argv[0] && it != args.constEnd())
+ copyArgument(argv[0], *outputTypes++, *it);
+
+ // skip this argument even if we didn't copy it
+ --outputTypesCount;
+ ++it;
+ }
+
+ for (int j = 0; j < outputTypesCount && it != args.constEnd(); ++i, ++j, ++it) {
+ copyArgument(argv[i], outputTypes[j], *it);
+ }
+ }
+
+ // done
+ lastError = reply;
+ return -1;
+ }
+ }
+ return id;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusinterface.h b/src/dbus/qdbusinterface.h
new file mode 100644
index 0000000000..a09999723b
--- /dev/null
+++ b/src/dbus/qdbusinterface.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSINTERFACE_H
+#define QDBUSINTERFACE_H
+
+#include <QtDBus/qdbusabstractinterface.h>
+#include <QtDBus/qdbusconnection.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(DBus)
+
+class QDBusInterfacePrivate;
+class Q_DBUS_EXPORT QDBusInterface: public QDBusAbstractInterface
+{
+ friend class QDBusConnection;
+private:
+ QDBusInterface(QDBusInterfacePrivate *p);
+
+public:
+ QDBusInterface(const QString &service, const QString &path, const QString &interface = QString(),
+ const QDBusConnection &connection = QDBusConnection::sessionBus(),
+ QObject *parent = 0);
+ ~QDBusInterface();
+
+ virtual const QMetaObject *metaObject() const;
+ virtual void *qt_metacast(const char *);
+ virtual int qt_metacall(QMetaObject::Call, int, void **);
+
+private:
+ Q_DECLARE_PRIVATE(QDBusInterface)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusinterface_p.h b/src/dbus/qdbusinterface_p.h
new file mode 100644
index 0000000000..cb2e9f0900
--- /dev/null
+++ b/src/dbus/qdbusinterface_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+//
+
+#ifndef QDBUSINTERFACEPRIVATE_H
+#define QDBUSINTERFACEPRIVATE_H
+
+#include "qdbusabstractinterface_p.h"
+#include "qdbusmetaobject_p.h"
+#include <qdbusinterface.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+class QDBusInterfacePrivate: public QDBusAbstractInterfacePrivate
+{
+public:
+ Q_DECLARE_PUBLIC(QDBusInterface)
+
+ QDBusMetaObject *metaObject;
+
+ QDBusInterfacePrivate(const QString &serv, const QString &p, const QString &iface,
+ const QDBusConnection &con);
+ ~QDBusInterfacePrivate();
+
+ int metacall(QMetaObject::Call c, int id, void **argv);
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusinternalfilters.cpp b/src/dbus/qdbusinternalfilters.cpp
new file mode 100644
index 0000000000..357fa2b675
--- /dev/null
+++ b/src/dbus/qdbusinternalfilters.cpp
@@ -0,0 +1,503 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusconnection_p.h"
+
+#include "qdbus_symbols_p.h"
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qthread.h>
+
+#include "qdbusabstractadaptor.h"
+#include "qdbusabstractadaptor_p.h"
+#include "qdbusconnection.h"
+#include "qdbusextratypes.h"
+#include "qdbusmessage.h"
+#include "qdbusmetatype.h"
+#include "qdbusmetatype_p.h"
+#include "qdbusmessage_p.h"
+#include "qdbusutil_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+// defined in qdbusxmlgenerator.cpp
+extern QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
+ const QMetaObject *base, int flags);
+
+static const char introspectableInterfaceXml[] =
+ " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
+ " <method name=\"Introspect\">\n"
+ " <arg name=\"xml_data\" type=\"s\" direction=\"out\"/>\n"
+ " </method>\n"
+ " </interface>\n";
+
+static const char propertiesInterfaceXml[] =
+ " <interface name=\"org.freedesktop.DBus.Properties\">\n"
+ " <method name=\"Get\">\n"
+ " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
+ " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
+ " <arg name=\"value\" type=\"v\" direction=\"out\"/>\n"
+ " </method>\n"
+ " <method name=\"Set\">\n"
+ " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
+ " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
+ " <arg name=\"value\" type=\"v\" direction=\"in\"/>\n"
+ " </method>\n"
+ " <method name=\"GetAll\">\n"
+ " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
+ " <arg name=\"values\" type=\"a{sv}\" direction=\"out\"/>\n"
+ " <annotation name=\"com.trolltech.QtDBus.QtTypeName.Out0\" value=\"QVariantMap\"/>\n"
+ " </method>\n"
+ " </interface>\n";
+
+static QString generateSubObjectXml(QObject *object)
+{
+ QString retval;
+ const QObjectList &objs = object->children();
+ QObjectList::ConstIterator it = objs.constBegin();
+ QObjectList::ConstIterator end = objs.constEnd();
+ for ( ; it != end; ++it) {
+ QString name = (*it)->objectName();
+ if (!name.isEmpty() && QDBusUtil::isValidPartOfObjectPath(name))
+ retval += QString::fromLatin1(" <node name=\"%1\"/>\n")
+ .arg(name);
+ }
+ return retval;
+}
+
+// declared as extern in qdbusconnection_p.h
+
+QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode &node)
+{
+ // object may be null
+
+ QString xml_data(QLatin1String(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE));
+ xml_data += QLatin1String("<node>\n");
+
+ if (node.obj) {
+ Q_ASSERT_X(QThread::currentThread() == node.obj->thread(),
+ "QDBusConnection: internal threading error",
+ "function called for an object that is in another thread!!");
+
+ if (node.flags & (QDBusConnection::ExportScriptableContents
+ | QDBusConnection::ExportNonScriptableContents)) {
+ // create XML for the object itself
+ const QMetaObject *mo = node.obj->metaObject();
+ for ( ; mo != &QObject::staticMetaObject; mo = mo->superClass())
+ xml_data += qDBusGenerateMetaObjectXml(QString(), mo, mo->superClass(),
+ node.flags);
+ }
+
+ // does this object have adaptors?
+ QDBusAdaptorConnector *connector;
+ if (node.flags & QDBusConnection::ExportAdaptors &&
+ (connector = qDBusFindAdaptorConnector(node.obj))) {
+
+ // trasverse every adaptor in this object
+ QDBusAdaptorConnector::AdaptorMap::ConstIterator it = connector->adaptors.constBegin();
+ QDBusAdaptorConnector::AdaptorMap::ConstIterator end = connector->adaptors.constEnd();
+ for ( ; it != end; ++it) {
+ // add the interface:
+ QString ifaceXml = QDBusAbstractAdaptorPrivate::retrieveIntrospectionXml(it->adaptor);
+ if (ifaceXml.isEmpty()) {
+ // add the interface's contents:
+ ifaceXml += qDBusGenerateMetaObjectXml(QString::fromLatin1(it->interface),
+ it->adaptor->metaObject(),
+ &QDBusAbstractAdaptor::staticMetaObject,
+ QDBusConnection::ExportScriptableContents
+ | QDBusConnection::ExportNonScriptableContents);
+
+ QDBusAbstractAdaptorPrivate::saveIntrospectionXml(it->adaptor, ifaceXml);
+ }
+
+ xml_data += ifaceXml;
+ }
+ }
+
+ xml_data += QLatin1String( propertiesInterfaceXml );
+ }
+
+ xml_data += QLatin1String( introspectableInterfaceXml );
+
+ if (node.flags & QDBusConnection::ExportChildObjects) {
+ xml_data += generateSubObjectXml(node.obj);
+ } else {
+ // generate from the object tree
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it =
+ node.children.constBegin();
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator end =
+ node.children.constEnd();
+ for ( ; it != end; ++it)
+ if (it->obj || !it->children.isEmpty())
+ xml_data += QString::fromLatin1(" <node name=\"%1\"/>\n")
+ .arg(it->name);
+ }
+
+ xml_data += QLatin1String("</node>\n");
+ return xml_data;
+}
+
+// implement the D-Bus interface org.freedesktop.DBus.Properties
+
+static inline QDBusMessage interfaceNotFoundError(const QDBusMessage &msg, const QString &interface_name)
+{
+ return msg.createErrorReply(QDBusError::UnknownInterface,
+ QString::fromLatin1("Interface %1 was not found in object %2")
+ .arg(interface_name)
+ .arg(msg.path()));
+}
+
+static inline QDBusMessage
+propertyNotFoundError(const QDBusMessage &msg, const QString &interface_name, const QByteArray &property_name)
+{
+ return msg.createErrorReply(QDBusError::InvalidArgs,
+ QString::fromLatin1("Property %1%2%3 was not found in object %4")
+ .arg(interface_name,
+ QString::fromLatin1(interface_name.isEmpty() ? "" : "."),
+ QString::fromLatin1(property_name),
+ msg.path()));
+}
+
+QDBusMessage qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode &node,
+ const QDBusMessage &msg)
+{
+ Q_ASSERT(msg.arguments().count() == 2);
+ Q_ASSERT_X(!node.obj || QThread::currentThread() == node.obj->thread(),
+ "QDBusConnection: internal threading error",
+ "function called for an object that is in another thread!!");
+
+ QString interface_name = msg.arguments().at(0).toString();
+ QByteArray property_name = msg.arguments().at(1).toString().toUtf8();
+
+ QDBusAdaptorConnector *connector;
+ QVariant value;
+ bool interfaceFound = false;
+ if (node.flags & QDBusConnection::ExportAdaptors &&
+ (connector = qDBusFindAdaptorConnector(node.obj))) {
+
+ // find the class that implements interface_name or try until we've found the property
+ // in case of an empty interface
+ if (interface_name.isEmpty()) {
+ for (QDBusAdaptorConnector::AdaptorMap::ConstIterator it = connector->adaptors.constBegin(),
+ end = connector->adaptors.constEnd(); it != end; ++it) {
+ const QMetaObject *mo = it->adaptor->metaObject();
+ int pidx = mo->indexOfProperty(property_name);
+ if (pidx != -1) {
+ value = mo->property(pidx).read(it->adaptor);
+ break;
+ }
+ }
+ } else {
+ QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
+ it = qLowerBound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
+ interface_name);
+ if (it != connector->adaptors.constEnd() && interface_name == QLatin1String(it->interface)) {
+ interfaceFound = true;
+ value = it->adaptor->property(property_name);
+ }
+ }
+ }
+
+ if (!interfaceFound && !value.isValid()
+ && node.flags & (QDBusConnection::ExportAllProperties |
+ QDBusConnection::ExportNonScriptableProperties)) {
+ // try the object itself
+ if (!interface_name.isEmpty())
+ interfaceFound = qDBusInterfaceInObject(node.obj, interface_name);
+
+ if (interfaceFound) {
+ int pidx = node.obj->metaObject()->indexOfProperty(property_name);
+ if (pidx != -1) {
+ QMetaProperty mp = node.obj->metaObject()->property(pidx);
+ if ((mp.isScriptable() && (node.flags & QDBusConnection::ExportScriptableProperties)) ||
+ (!mp.isScriptable() && (node.flags & QDBusConnection::ExportNonScriptableProperties)))
+ value = mp.read(node.obj);
+ }
+ }
+ }
+
+ if (!value.isValid()) {
+ // the property was not found
+ if (!interfaceFound)
+ return interfaceNotFoundError(msg, interface_name);
+ return propertyNotFoundError(msg, interface_name, property_name);
+ }
+
+ return msg.createReply(QVariant::fromValue(QDBusVariant(value)));
+}
+
+enum PropertyWriteResult {
+ PropertyWriteSuccess = 0,
+ PropertyNotFound,
+ PropertyTypeMismatch,
+ PropertyWriteFailed
+};
+
+static QDBusMessage propertyWriteReply(const QDBusMessage &msg, const QString &interface_name,
+ const QByteArray &property_name, int status)
+{
+ switch (status) {
+ case PropertyNotFound:
+ return propertyNotFoundError(msg, interface_name, property_name);
+ case PropertyTypeMismatch:
+ return msg.createErrorReply(QDBusError::InvalidArgs,
+ QString::fromLatin1("Invalid arguments for writing to property %1%2%3")
+ .arg(interface_name,
+ QString::fromLatin1(interface_name.isEmpty() ? "" : "."),
+ QString::fromLatin1(property_name)));
+ case PropertyWriteFailed:
+ return msg.createErrorReply(QDBusError::InternalError,
+ QString::fromLatin1("Internal error"));
+
+ case PropertyWriteSuccess:
+ return msg.createReply();
+ }
+ Q_ASSERT_X(false, "", "Should not be reached");
+ return QDBusMessage();
+}
+
+static int writeProperty(QObject *obj, const QByteArray &property_name, QVariant value,
+ int propFlags = QDBusConnection::ExportAllProperties)
+{
+ const QMetaObject *mo = obj->metaObject();
+ int pidx = mo->indexOfProperty(property_name);
+ if (pidx == -1) {
+ // this object has no property by that name
+ return PropertyNotFound;
+ }
+
+ QMetaProperty mp = mo->property(pidx);
+
+ // check if this property is exported
+ bool isScriptable = mp.isScriptable();
+ if (!(propFlags & QDBusConnection::ExportScriptableProperties) && isScriptable)
+ return PropertyNotFound;
+ if (!(propFlags & QDBusConnection::ExportNonScriptableProperties) && !isScriptable)
+ return PropertyNotFound;
+
+ // we found our property
+ // do we have the right type?
+ int id = mp.type();
+ if (id == QVariant::UserType) {
+ // dynamic type
+ id = qDBusNameToTypeId(mp.typeName());
+ if (id == -1) {
+ // type not registered?
+ qWarning("QDBusConnection: Unable to handle unregistered datatype '%s' for property '%s::%s'",
+ mp.typeName(), mo->className(), property_name.constData());
+ return PropertyWriteFailed;
+ }
+ }
+
+ if (id != 0xff && value.userType() == QDBusMetaTypeId::argument) {
+ // we have to demarshall before writing
+ void *null = 0;
+ QVariant other(id, null);
+ if (!QDBusMetaType::demarshall(qvariant_cast<QDBusArgument>(value), id, other.data())) {
+ qWarning("QDBusConnection: type `%s' (%d) is not registered with QtDBus. "
+ "Use qDBusRegisterMetaType to register it",
+ mp.typeName(), id);
+ return PropertyWriteFailed;
+ }
+
+ value = other;
+ }
+
+ // the property type here should match
+ return mp.write(obj, value) ? PropertyWriteSuccess : PropertyWriteFailed;
+}
+
+QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode &node,
+ const QDBusMessage &msg)
+{
+ Q_ASSERT(msg.arguments().count() == 3);
+ Q_ASSERT_X(!node.obj || QThread::currentThread() == node.obj->thread(),
+ "QDBusConnection: internal threading error",
+ "function called for an object that is in another thread!!");
+
+ QString interface_name = msg.arguments().at(0).toString();
+ QByteArray property_name = msg.arguments().at(1).toString().toUtf8();
+ QVariant value = qvariant_cast<QDBusVariant>(msg.arguments().at(2)).variant();
+
+ QDBusAdaptorConnector *connector;
+ if (node.flags & QDBusConnection::ExportAdaptors &&
+ (connector = qDBusFindAdaptorConnector(node.obj))) {
+
+ // find the class that implements interface_name or try until we've found the property
+ // in case of an empty interface
+ if (interface_name.isEmpty()) {
+ for (QDBusAdaptorConnector::AdaptorMap::ConstIterator it = connector->adaptors.constBegin(),
+ end = connector->adaptors.constEnd(); it != end; ++it) {
+ int status = writeProperty(it->adaptor, property_name, value);
+ if (status == PropertyNotFound)
+ continue;
+ return propertyWriteReply(msg, interface_name, property_name, status);
+ }
+ } else {
+ QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
+ it = qLowerBound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
+ interface_name);
+ if (it != connector->adaptors.end() && interface_name == QLatin1String(it->interface)) {
+ return propertyWriteReply(msg, interface_name, property_name,
+ writeProperty(it->adaptor, property_name, value));
+ }
+ }
+ }
+
+ if (node.flags & (QDBusConnection::ExportScriptableProperties |
+ QDBusConnection::ExportNonScriptableProperties)) {
+ // try the object itself
+ bool interfaceFound = true;
+ if (!interface_name.isEmpty())
+ interfaceFound = qDBusInterfaceInObject(node.obj, interface_name);
+
+ if (interfaceFound) {
+ return propertyWriteReply(msg, interface_name, property_name,
+ writeProperty(node.obj, property_name, value, node.flags));
+ }
+ }
+
+ // the property was not found
+ if (!interface_name.isEmpty())
+ return interfaceNotFoundError(msg, interface_name);
+ return propertyWriteReply(msg, interface_name, property_name, PropertyNotFound);
+}
+
+// unite two QVariantMaps, but don't generate duplicate keys
+static QVariantMap &operator+=(QVariantMap &lhs, const QVariantMap &rhs)
+{
+ QVariantMap::ConstIterator it = rhs.constBegin(),
+ end = rhs.constEnd();
+ for ( ; it != end; ++it)
+ lhs.insert(it.key(), it.value());
+ return lhs;
+}
+
+static QVariantMap readAllProperties(QObject *object, int flags)
+{
+ QVariantMap result;
+ const QMetaObject *mo = object->metaObject();
+
+ // QObject has properties, so don't start from 0
+ for (int i = QObject::staticMetaObject.propertyCount(); i < mo->propertyCount(); ++i) {
+ QMetaProperty mp = mo->property(i);
+
+ // is it readable?
+ if (!mp.isReadable())
+ continue;
+
+ // is it a registered property?
+ int typeId = qDBusNameToTypeId(mp.typeName());
+ if (!typeId)
+ continue;
+ const char *signature = QDBusMetaType::typeToSignature(typeId);
+ if (!signature)
+ continue;
+
+ // is this property visible from the outside?
+ if ((mp.isScriptable() && flags & QDBusConnection::ExportScriptableProperties) ||
+ (!mp.isScriptable() && flags & QDBusConnection::ExportNonScriptableProperties)) {
+ // yes, it's visible
+ QVariant value = mp.read(object);
+ if (value.isValid())
+ result.insert(QString::fromLatin1(mp.name()), value);
+ }
+ }
+
+ return result;
+}
+
+QDBusMessage qDBusPropertyGetAll(const QDBusConnectionPrivate::ObjectTreeNode &node,
+ const QDBusMessage &msg)
+{
+ Q_ASSERT(msg.arguments().count() == 1);
+ Q_ASSERT_X(!node.obj || QThread::currentThread() == node.obj->thread(),
+ "QDBusConnection: internal threading error",
+ "function called for an object that is in another thread!!");
+
+ QString interface_name = msg.arguments().at(0).toString();
+
+ bool interfaceFound = false;
+ QVariantMap result;
+
+ QDBusAdaptorConnector *connector;
+ if (node.flags & QDBusConnection::ExportAdaptors &&
+ (connector = qDBusFindAdaptorConnector(node.obj))) {
+
+ if (interface_name.isEmpty()) {
+ // iterate over all interfaces
+ for (QDBusAdaptorConnector::AdaptorMap::ConstIterator it = connector->adaptors.constBegin(),
+ end = connector->adaptors.constEnd(); it != end; ++it) {
+ result += readAllProperties(it->adaptor, QDBusConnection::ExportAllProperties);
+ }
+ } else {
+ // find the class that implements interface_name
+ QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
+ it = qLowerBound(connector->adaptors.constBegin(), connector->adaptors.constEnd(),
+ interface_name);
+ if (it != connector->adaptors.constEnd() && interface_name == QLatin1String(it->interface)) {
+ interfaceFound = true;
+ result = readAllProperties(it->adaptor, QDBusConnection::ExportAllProperties);
+ }
+ }
+ }
+
+ if (node.flags & QDBusConnection::ExportAllProperties &&
+ (!interfaceFound || interface_name.isEmpty())) {
+ // try the object itself
+ result += readAllProperties(node.obj, node.flags);
+ interfaceFound = true;
+ }
+
+ if (!interfaceFound && !interface_name.isEmpty()) {
+ // the interface was not found
+ return interfaceNotFoundError(msg, interface_name);
+ }
+
+ return msg.createReply(QVariant::fromValue(result));
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusintrospection.cpp b/src/dbus/qdbusintrospection.cpp
new file mode 100644
index 0000000000..a93d4bc089
--- /dev/null
+++ b/src/dbus/qdbusintrospection.cpp
@@ -0,0 +1,429 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusintrospection_p.h"
+#include "qdbusxmlparser_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QDBusIntrospection
+ \brief Information about introspected objects and interfaces on D-Bus.
+ \internal
+
+ This class provides structures and methods for parsing the XML introspection data for D-Bus.
+ Normally, you don't have to use the methods provided here: QDBusInterface and QDBusObject will
+ do that for you.
+
+ But they may prove useful if the XML data was obtained through other means (like parsing a file).
+*/
+
+/*!
+ \class QDBusIntrospection::Argument
+ \brief One argument to a D-Bus method or signal.
+
+ This struct represents one argument passed to a method or received from a method or signal in
+ D-Bus. The struct does not contain information on the direction (input or output).
+*/
+
+/*!
+ \variable QDBusIntrospection::Argument::type
+ The argument type.
+*/
+
+/*!
+ \variable QDBusIntrospection::Argument::name
+ The argument name. The argument name is optional, so this may be a null QString.
+*/
+
+/*!
+ \fn QDBusIntrospection::Argument::operator==(const Argument &other) const
+ Compares this object against \a other and return true if they are the same.
+*/
+
+/*!
+ \class QDBusIntrospection::Method
+ \brief Information about one method.
+
+ This struct represents one method discovered through introspection. A method is composed of
+ its \a name, its input arguments, its output arguments, and, optionally, annotations. There are no
+ "in-out" arguments.
+*/
+
+/*!
+ \variable QDBusIntrospection::Method::name
+ The method's name.
+*/
+
+/*!
+ \variable QDBusIntrospection::Method::inputArgs
+ A list of the method's input arguments.
+*/
+
+/*!
+ \variable QDBusIntrospection::Method::outputArgs
+ A list of the method's output arguments (i.e., return values).
+*/
+
+/*!
+ \variable QDBusIntrospection::Method::annotations
+ The annotations associated with the method. Each annotation is a pair of strings, where the key
+ is of the same format as a D-Bus interface name. The value is arbitrary.
+*/
+
+/*!
+ \fn QDBusIntrospection::Method::operator==(const Method &other) const
+ Compares this object against \a other and return true if they are the same.
+*/
+
+/*!
+ \class QDBusIntrospection::Signal
+ \brief Information about one signal.
+
+ This struct represents one signal discovered through introspection. A signal is composed of
+ its \a name, its output arguments, and, optionally, annotations.
+*/
+
+/*!
+ \variable QDBusIntrospection::Signal::name
+ The signal's name.
+*/
+
+/*!
+ \variable QDBusIntrospection::Signal::outputArgs
+ A list of the signal's arguments.
+*/
+
+/*!
+ \variable QDBusIntrospection::Signal::annotations
+ The annotations associated with the signal. Each annotation is a pair of strings, where the key
+ is of the same format as a D-Bus interface name. The value is arbitrary.
+*/
+
+/*!
+ \fn QDBusIntrospection::Signal::operator==(const Signal& other) const
+ Compares this object against \a other and return true if they are the same.
+*/
+
+/*!
+ \class QDBusIntrospection::Property
+ \brief Information about one property.
+
+ This struct represents one property discovered through introspection. A property is composed of
+ its \a name, its \a type, its \a access rights, and, optionally, annotations.
+*/
+
+/*!
+ \variable QDBusIntrospection::Property::name
+ The property's name.
+*/
+
+/*!
+ \variable QDBusIntrospection::Property::type
+ The property's type.
+*/
+
+/*!
+ \enum QDBusIntrospection::Property::Access
+ The possible access rights for a property:
+ \value Read
+ \value Write
+ \value ReadWrite
+*/
+
+/*!
+ \variable QDBusIntrospection::Property::access
+ The property's access rights.
+*/
+
+/*!
+ \variable QDBusIntrospection::Property::annotations
+ The annotations associated with the property. Each annotation is a pair of strings, where the key
+ is of the same format as a D-Bus interface name. The value is arbitrary.
+*/
+
+/*!
+ \fn QDBusIntrospection::Property::operator==(const Property &other) const
+ Compares this object against \a other and return true if they are the same.
+*/
+
+/*!
+ \class QDBusIntrospection::Interface
+ \brief Information about one interface on the bus.
+
+ Each interface on D-Bus has an unique \a name, identifying where that interface was defined.
+ Interfaces may have annotations, methods, signals and properties, but none are mandatory.
+*/
+
+/*!
+ \variable QDBusIntrospection::Interface::name
+ The interface's name.
+*/
+
+/*!
+ \variable QDBusIntrospection::Interface::introspection
+ The XML document fragment describing this interface.
+
+ If parsed again through parseInterface, the object returned should have the same contents as
+ this object.
+*/
+
+/*!
+ \variable QDBusIntrospection::Interface::annotations
+ The annotations associated with the interface. Each annotation is a pair of strings, where the key
+ is of the same format as a D-Bus interface name. The value is arbitrary.
+*/
+
+/*!
+ \variable QDBusIntrospection::Interface::methods
+ The methods available in this interface. Note that method names are not unique (i.e., methods
+ can be overloaded with multiple arguments types).
+*/
+
+/*!
+ \variable QDBusIntrospection::Interface::signals_
+ The signals available in this interface. Note that signal names are not unique (i.e., signals
+ can be overloaded with multiple argument types).
+
+ This member is called "signals_" because "signals" is a reserved keyword in Qt.
+*/
+
+/*!
+ \variable QDBusIntrospection::Interface::properties
+ The properties available in this interface. Property names are unique.
+*/
+
+/*!
+ \fn QDBusIntrospection::Interface::operator==(const Interface &other) const
+ Compares this object against \a other and return true if they are the same.
+
+ Note that two interfaces are considered to be the same if they have the same name. The internal
+ structures in the objects are not compared.
+*/
+
+/*!
+ \class QDBusIntrospection::Object
+ \brief Information about one object on the bus.
+
+ An object on the D-Bus bus is represented by its service and path on the service but, unlike
+ interfaces, objects are mutable. That is, their contents can change with time. Therefore,
+ while the (service, path) pair uniquely identifies an object, the information contained in
+ this struct may no longer represent the object.
+
+ An object can contain interfaces and child (sub) objects.
+*/
+
+/*!
+ \variable QDBusIntrospection::Object::service
+ The object's service name.
+
+ \sa parseObject(), parseObjectTree()
+*/
+
+/*!
+ \variable QDBusIntrospection::Object::path
+ The object's path on the service. This is an absolute path.
+
+ \sa parseObject(), parseObjectTree()
+*/
+
+/*!
+ \variable QDBusIntrospection::Object::introspection
+ The XML document fragment describing this object, its interfaces and sub-objects at the time
+ of the parsing.
+
+ The result of parseObject with this XML data should be the same as the Object struct.
+*/
+
+/*!
+ \variable QDBusIntrospection::Object::interfaces
+ The list of interface names in this object.
+*/
+
+/*!
+ \variable QDBusIntrospection::Object::childObjects
+ The list of child object names in this object. Note that this is a relative name, not an
+ absolute path. To obtain the absolute path, concatenate with \l
+ {QDBusIntrospection::Object::path}{path}.
+*/
+
+/*!
+ \class QDBusIntrospection::ObjectTree
+ \brief Complete information about one object node and its descendency.
+
+ This struct contains the same data as QDBusIntrospection::Object, plus the actual data for the
+ interfaces and child (sub) objects that was available in the XML document.
+*/
+
+/*!
+ \variable QDBusIntrospection::ObjectTree::interfaceData
+ A map of interfaces and their names.
+*/
+
+/*!
+ \variable QDBusIntrospection::ObjectTree::childObjectData
+ A map of object paths and their data. The map key contains the relative path to the object.
+
+ Note this map contains only the child notes that do have information about the sub-object's
+ contents. If the XML data did not contain the information, only the object name will be listed
+ in childObjects, but not in childObjectData.
+*/
+
+/*!
+ \typedef QDBusIntrospection::Annotations
+ Contains a QMap of an annotation pair. The annotation's name is stored in the QMap key and
+ must be unique. The annotation's value is stored in the QMap's value and is arbitrary.
+*/
+
+/*!
+ \typedef QDBusIntrospection::Arguments
+ Contains a list of arguments to either a Method or a Signal. The arguments' order is important.
+*/
+
+/*!
+ \typedef QDBusIntrospection::Methods
+ Contains a QMap of methods and their names. The method's name is stored in the map's key and
+ is not necessarily unique. The order in which multiple methods with the same name are stored
+ in this map is undefined.
+*/
+
+/*!
+ \typedef QDBusIntrospection::Signals
+ Contains a QMap of signals and their names. The signal's name is stored in the map's key and
+ is not necessarily unique. The order in which multiple signals with the same name are stored
+ in this map is undefined.
+*/
+
+/*!
+ \typedef QDBusIntrospection::Properties
+ Contains a QMap of properties and their names. Each property must have a unique name.
+*/
+
+/*!
+ \typedef QDBusIntrospection::Interfaces
+ Contains a QMap of interfaces and their names. Each interface has a unique name.
+*/
+
+/*!
+ \typedef QDBusIntrospection::Objects
+ Contains a QMap of objects and their paths relative to their immediate parent.
+
+ \sa parseObjectTree()
+*/
+
+/*!
+ Parses the XML document fragment (given by \a xml) containing one interface.
+
+ The first element tag in this XML data must be either \<node\> or \<interface\>. If it is
+ \<node\>, then the \<interface\> tag must be a child tag of the \<node\> one.
+
+ If there are multiple interfaces in this XML data, it is undefined which one will be
+ returned.
+*/
+QDBusIntrospection::Interface
+QDBusIntrospection::parseInterface(const QString &xml)
+{
+ // be lazy
+ Interfaces ifs = parseInterfaces(xml);
+ if (ifs.isEmpty())
+ return Interface();
+
+ // return the first in map order (probably alphabetical order)
+ return *ifs.constBegin().value();
+}
+
+/*!
+ Parses the XML document fragment (given by \a xml) containing several interfaces.
+
+ If the first element tag in this document fragment is \<node\>, the interfaces parsed will
+ be those found as child elements of the \<node\> tag.
+*/
+QDBusIntrospection::Interfaces
+QDBusIntrospection::parseInterfaces(const QString &xml)
+{
+ QString null;
+ QDBusXmlParser parser(null, null, xml);
+ return parser.interfaces();
+}
+
+/*!
+ Parses the XML document fragment (given by \a xml) containing one object, found at the service
+ \a service and path \a path.
+
+ The first element tag in this document must be \<node\>. If that tag does not contain
+ a name attribute, the \a path argument will be used to determine the path of this
+ object node.
+
+ This function does not parse the interfaces contained in the node, nor sub-object's contents.
+ It will only list their names. If you need to know their contents, use parseObjectTree.
+*/
+QDBusIntrospection::Object
+QDBusIntrospection::parseObject(const QString &xml, const QString &service, const QString &path)
+{
+ QDBusXmlParser parser(service, path, xml);
+ QSharedDataPointer<QDBusIntrospection::Object> retval = parser.object();
+ if (!retval)
+ return QDBusIntrospection::Object();
+ return *retval;
+}
+
+/*!
+ Parses the XML document fragment (given by \a xml) containing one object node and returns all
+ the information about the interfaces and sub-objects, found at the service \a service and path
+ \a path.
+
+ The Objects map returned will contain the absolute path names in the key.
+*/
+QDBusIntrospection::ObjectTree
+QDBusIntrospection::parseObjectTree(const QString &xml, const QString &service, const QString &path)
+{
+ QDBusXmlParser parser(service, path, xml);
+ QSharedDataPointer<QDBusIntrospection::ObjectTree> retval = parser.objectTree();
+ if (!retval)
+ return QDBusIntrospection::ObjectTree();
+ return *retval;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusintrospection_p.h b/src/dbus/qdbusintrospection_p.h
new file mode 100644
index 0000000000..caf3bece5e
--- /dev/null
+++ b/src/dbus/qdbusintrospection_p.h
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSINTROSPECTION_H
+#define QDBUSINTROSPECTION_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qstring.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qshareddata.h>
+#include <qdbusmacros.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_DBUS_EXPORT QDBusIntrospection
+{
+public:
+ // forward declarations
+ struct Argument;
+ struct Method;
+ struct Signal;
+ struct Property;
+ struct Interface;
+ struct Object;
+ struct ObjectTree;
+
+ // typedefs
+ typedef QMap<QString, QString> Annotations;
+ typedef QList<Argument> Arguments;
+ typedef QMultiMap<QString, Method> Methods;
+ typedef QMultiMap<QString, Signal> Signals;
+ typedef QMap<QString, Property> Properties;
+ typedef QMap<QString, QSharedDataPointer<Interface> > Interfaces;
+ typedef QMap<QString, QSharedDataPointer<ObjectTree> > Objects;
+
+public:
+ // the structs
+
+ struct Argument
+ {
+ QString type;
+ QString name;
+
+ inline bool operator==(const Argument& other) const
+ { return name == other.name && type == other.type; }
+ };
+
+ struct Method
+ {
+ QString name;
+ Arguments inputArgs;
+ Arguments outputArgs;
+ Annotations annotations;
+
+ inline bool operator==(const Method& other) const
+ { return name == other.name && annotations == other.annotations &&
+ inputArgs == other.inputArgs && outputArgs == other.outputArgs; }
+ };
+
+ struct Signal
+ {
+ QString name;
+ Arguments outputArgs;
+ Annotations annotations;
+
+ inline bool operator==(const Signal& other) const
+ { return name == other.name && annotations == other.annotations &&
+ outputArgs == other.outputArgs; }
+ };
+
+ struct Property
+ {
+ enum Access { Read, Write, ReadWrite };
+ QString name;
+ QString type;
+ Access access;
+ Annotations annotations;
+
+ inline bool operator==(const Property& other) const
+ { return access == other.access && name == other.name &&
+ annotations == other.annotations && type == other.type; }
+ };
+
+ struct Interface: public QSharedData
+ {
+ QString name;
+ QString introspection;
+
+ Annotations annotations;
+ Methods methods;
+ Signals signals_;
+ Properties properties;
+
+ inline bool operator==(const Interface &other) const
+ { return !name.isEmpty() && name == other.name; }
+ };
+
+ struct Object: public QSharedData
+ {
+ QString service;
+ QString path;
+ QString introspection;
+
+ QStringList interfaces;
+ QStringList childObjects;
+ };
+
+ struct ObjectTree: public Object
+ {
+ Interfaces interfaceData;
+ Objects childObjectData;
+ };
+
+public:
+ static Interface parseInterface(const QString &xml);
+ static Interfaces parseInterfaces(const QString &xml);
+ static Object parseObject(const QString &xml, const QString &service = QString(),
+ const QString &path = QString());
+ static ObjectTree parseObjectTree(const QString &xml,
+ const QString &service,
+ const QString &path);
+
+private:
+ QDBusIntrospection();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/dbus/qdbusmacros.h b/src/dbus/qdbusmacros.h
new file mode 100644
index 0000000000..09fa2a4e6d
--- /dev/null
+++ b/src/dbus/qdbusmacros.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSMACROS_H
+#define QDBUSMACROS_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qvariant.h>
+
+#ifndef Q_MOC_RUN
+# define Q_NOREPLY
+#endif
+
+#ifdef Q_CC_MSVC
+#include <QtCore/qlist.h>
+#include <QtCore/qset.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qvector.h>
+#endif
+
+// prevent syncqt complaints
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+QT_MODULE(DBus)
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusmarshaller.cpp b/src/dbus/qdbusmarshaller.cpp
new file mode 100644
index 0000000000..6dec359713
--- /dev/null
+++ b/src/dbus/qdbusmarshaller.cpp
@@ -0,0 +1,573 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusargument_p.h"
+#include "qdbusconnection.h"
+#include "qdbusmetatype_p.h"
+#include "qdbusutil_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+static void qIterAppend(DBusMessageIter *it, QByteArray *ba, int type, const void *arg)
+{
+ if (ba)
+ *ba += char(type);
+ else
+ q_dbus_message_iter_append_basic(it, type, arg);
+}
+
+QDBusMarshaller::~QDBusMarshaller()
+{
+ close();
+}
+
+inline QString QDBusMarshaller::currentSignature()
+{
+ if (message)
+ return QString::fromUtf8(q_dbus_message_get_signature(message));
+ return QString();
+}
+
+inline void QDBusMarshaller::append(uchar arg)
+{
+ qIterAppend(&iterator, ba, DBUS_TYPE_BYTE, &arg);
+}
+
+inline void QDBusMarshaller::append(bool arg)
+{
+ dbus_bool_t cast = arg;
+ qIterAppend(&iterator, ba, DBUS_TYPE_BOOLEAN, &cast);
+}
+
+inline void QDBusMarshaller::append(short arg)
+{
+ qIterAppend(&iterator, ba, DBUS_TYPE_INT16, &arg);
+}
+
+inline void QDBusMarshaller::append(ushort arg)
+{
+ qIterAppend(&iterator, ba, DBUS_TYPE_UINT16, &arg);
+}
+
+inline void QDBusMarshaller::append(int arg)
+{
+ qIterAppend(&iterator, ba, DBUS_TYPE_INT32, &arg);
+}
+
+inline void QDBusMarshaller::append(uint arg)
+{
+ qIterAppend(&iterator, ba, DBUS_TYPE_UINT32, &arg);
+}
+
+inline void QDBusMarshaller::append(qlonglong arg)
+{
+ qIterAppend(&iterator, ba, DBUS_TYPE_INT64, &arg);
+}
+
+inline void QDBusMarshaller::append(qulonglong arg)
+{
+ qIterAppend(&iterator, ba, DBUS_TYPE_UINT64, &arg);
+}
+
+inline void QDBusMarshaller::append(double arg)
+{
+ qIterAppend(&iterator, ba, DBUS_TYPE_DOUBLE, &arg);
+}
+
+void QDBusMarshaller::append(const QString &arg)
+{
+ QByteArray data = arg.toUtf8();
+ const char *cdata = data.constData();
+ qIterAppend(&iterator, ba, DBUS_TYPE_STRING, &cdata);
+}
+
+inline void QDBusMarshaller::append(const QDBusObjectPath &arg)
+{
+ QByteArray data = arg.path().toUtf8();
+ if (!ba && data.isEmpty())
+ error(QLatin1String("Invalid object path passed in arguments"));
+ const char *cdata = data.constData();
+ qIterAppend(&iterator, ba, DBUS_TYPE_OBJECT_PATH, &cdata);
+}
+
+inline void QDBusMarshaller::append(const QDBusSignature &arg)
+{
+ QByteArray data = arg.signature().toUtf8();
+ if (!ba && data.isEmpty())
+ error(QLatin1String("Invalid signature passed in arguments"));
+ const char *cdata = data.constData();
+ qIterAppend(&iterator, ba, DBUS_TYPE_SIGNATURE, &cdata);
+}
+
+inline void QDBusMarshaller::append(const QDBusUnixFileDescriptor &arg)
+{
+ int fd = arg.fileDescriptor();
+ if (!ba && fd == -1) {
+ error(QLatin1String("Invalid file descriptor passed in arguments"));
+ } else {
+ qIterAppend(&iterator, ba, DBUS_TYPE_UNIX_FD, &fd);
+ }
+}
+
+inline void QDBusMarshaller::append(const QByteArray &arg)
+{
+ if (ba) {
+ *ba += DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING;
+ return;
+ }
+
+ const char* cdata = arg.constData();
+ DBusMessageIter subiterator;
+ q_dbus_message_iter_open_container(&iterator, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING,
+ &subiterator);
+ q_dbus_message_iter_append_fixed_array(&subiterator, DBUS_TYPE_BYTE, &cdata, arg.length());
+ q_dbus_message_iter_close_container(&iterator, &subiterator);
+}
+
+inline bool QDBusMarshaller::append(const QDBusVariant &arg)
+{
+ if (ba) {
+ *ba += DBUS_TYPE_VARIANT_AS_STRING;
+ return true;
+ }
+
+ const QVariant &value = arg.variant();
+ QVariant::Type id = QVariant::Type(value.userType());
+ if (id == QVariant::Invalid) {
+ qWarning("QDBusMarshaller: cannot add a null QDBusVariant");
+ error(QLatin1String("Variant containing QVariant::Invalid passed in arguments"));
+ return false;
+ }
+
+ QByteArray tmpSignature;
+ const char *signature = 0;
+ if (int(id) == QDBusMetaTypeId::argument) {
+ // take the signature from the QDBusArgument object we're marshalling
+ tmpSignature =
+ qvariant_cast<QDBusArgument>(value).currentSignature().toLatin1();
+ signature = tmpSignature.constData();
+ } else {
+ // take the signatuer from the metatype we're marshalling
+ signature = QDBusMetaType::typeToSignature(id);
+ }
+ if (!signature) {
+ qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
+ "Use qDBusRegisterMetaType to register it",
+ QVariant::typeToName( id ), id);
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(QVariant::typeToName(id))));
+ return false;
+ }
+
+ QDBusMarshaller sub(capabilities);
+ open(sub, DBUS_TYPE_VARIANT, signature);
+ bool isOk = sub.appendVariantInternal(value);
+ // don't call sub.close(): it auto-closes
+
+ return isOk;
+}
+
+inline void QDBusMarshaller::append(const QStringList &arg)
+{
+ if (ba) {
+ *ba += DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING;
+ return;
+ }
+
+ QDBusMarshaller sub(capabilities);
+ open(sub, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING);
+ QStringList::ConstIterator it = arg.constBegin();
+ QStringList::ConstIterator end = arg.constEnd();
+ for ( ; it != end; ++it)
+ sub.append(*it);
+ // don't call sub.close(): it auto-closes
+}
+
+inline QDBusMarshaller *QDBusMarshaller::beginStructure()
+{
+ return beginCommon(DBUS_TYPE_STRUCT, 0);
+}
+
+inline QDBusMarshaller *QDBusMarshaller::beginArray(int id)
+{
+ const char *signature = QDBusMetaType::typeToSignature( QVariant::Type(id) );
+ if (!signature) {
+ qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
+ "Use qDBusRegisterMetaType to register it",
+ QVariant::typeToName( QVariant::Type(id) ), id);
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(QVariant::typeToName(QVariant::Type(id)))));
+ return this;
+ }
+
+ return beginCommon(DBUS_TYPE_ARRAY, signature);
+}
+
+inline QDBusMarshaller *QDBusMarshaller::beginMap(int kid, int vid)
+{
+ const char *ksignature = QDBusMetaType::typeToSignature( QVariant::Type(kid) );
+ if (!ksignature) {
+ qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
+ "Use qDBusRegisterMetaType to register it",
+ QVariant::typeToName( QVariant::Type(kid) ), kid);
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(QVariant::typeToName(QVariant::Type(kid)))));
+ return this;
+ }
+ if (ksignature[1] != 0 || !QDBusUtil::isValidBasicType(*ksignature)) {
+ qWarning("QDBusMarshaller: type '%s' (%d) cannot be used as the key type in a D-BUS map.",
+ QVariant::typeToName( QVariant::Type(kid) ), kid);
+ error(QString::fromLatin1("Type %1 passed in arguments cannot be used as a key in a map")
+ .arg(QLatin1String(QVariant::typeToName(QVariant::Type(kid)))));
+ return this;
+ }
+
+ const char *vsignature = QDBusMetaType::typeToSignature( QVariant::Type(vid) );
+ if (!vsignature) {
+ const char *typeName = QVariant::typeToName(QVariant::Type(vid));
+ qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
+ "Use qDBusRegisterMetaType to register it",
+ typeName, vid);
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(typeName)));
+ return this;
+ }
+
+ QByteArray signature;
+ signature = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING;
+ signature += ksignature;
+ signature += vsignature;
+ signature += DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
+ return beginCommon(DBUS_TYPE_ARRAY, signature);
+}
+
+inline QDBusMarshaller *QDBusMarshaller::beginMapEntry()
+{
+ return beginCommon(DBUS_TYPE_DICT_ENTRY, 0);
+}
+
+void QDBusMarshaller::open(QDBusMarshaller &sub, int code, const char *signature)
+{
+ sub.parent = this;
+ sub.ba = ba;
+ sub.ok = true;
+ sub.capabilities = capabilities;
+
+ if (ba)
+ switch (code) {
+ case DBUS_TYPE_ARRAY:
+ *ba += char(code);
+ *ba += signature;
+ // fall through
+
+ case DBUS_TYPE_DICT_ENTRY:
+ sub.closeCode = 0;
+ break;
+
+ case DBUS_TYPE_STRUCT:
+ *ba += DBUS_STRUCT_BEGIN_CHAR;
+ sub.closeCode = DBUS_STRUCT_END_CHAR;
+ break;
+ }
+ else
+ q_dbus_message_iter_open_container(&iterator, code, signature, &sub.iterator);
+}
+
+QDBusMarshaller *QDBusMarshaller::beginCommon(int code, const char *signature)
+{
+ QDBusMarshaller *d = new QDBusMarshaller(capabilities);
+ open(*d, code, signature);
+ return d;
+}
+
+inline QDBusMarshaller *QDBusMarshaller::endStructure()
+{ return endCommon(); }
+
+inline QDBusMarshaller *QDBusMarshaller::endArray()
+{ return endCommon(); }
+
+inline QDBusMarshaller *QDBusMarshaller::endMap()
+{ return endCommon(); }
+
+inline QDBusMarshaller *QDBusMarshaller::endMapEntry()
+{ return endCommon(); }
+
+QDBusMarshaller *QDBusMarshaller::endCommon()
+{
+ QDBusMarshaller *retval = parent;
+ delete this;
+ return retval;
+}
+
+void QDBusMarshaller::close()
+{
+ if (ba) {
+ if (closeCode)
+ *ba += closeCode;
+ } else if (parent) {
+ q_dbus_message_iter_close_container(&parent->iterator, &iterator);
+ }
+}
+
+void QDBusMarshaller::error(const QString &msg)
+{
+ ok = false;
+ if (parent)
+ parent->error(msg);
+ else
+ errorString = msg;
+}
+
+bool QDBusMarshaller::appendVariantInternal(const QVariant &arg)
+{
+ int id = arg.userType();
+ if (id == QVariant::Invalid) {
+ qWarning("QDBusMarshaller: cannot add an invalid QVariant");
+ error(QLatin1String("Variant containing QVariant::Invalid passed in arguments"));
+ return false;
+ }
+
+ // intercept QDBusArgument parameters here
+ if (id == QDBusMetaTypeId::argument) {
+ QDBusArgument dbusargument = qvariant_cast<QDBusArgument>(arg);
+ QDBusArgumentPrivate *d = QDBusArgumentPrivate::d(dbusargument);
+ if (!d->message)
+ return false; // can't append this one...
+
+ QDBusDemarshaller demarshaller(capabilities);
+ demarshaller.message = q_dbus_message_ref(d->message);
+
+ if (d->direction == Demarshalling) {
+ // it's demarshalling; just copy
+ demarshaller.iterator = static_cast<QDBusDemarshaller *>(d)->iterator;
+ } else {
+ // it's marshalling; start over
+ if (!q_dbus_message_iter_init(demarshaller.message, &demarshaller.iterator))
+ return false; // error!
+ }
+
+ return appendCrossMarshalling(&demarshaller);
+ }
+
+ const char *signature = QDBusMetaType::typeToSignature( QVariant::Type(id) );
+ if (!signature) {
+ qWarning("QDBusMarshaller: type `%s' (%d) is not registered with D-BUS. "
+ "Use qDBusRegisterMetaType to register it",
+ QVariant::typeToName( QVariant::Type(id) ), id);
+ error(QString::fromLatin1("Unregistered type %1 passed in arguments")
+ .arg(QLatin1String(QVariant::typeToName(QVariant::Type(id)))));
+ return false;
+ }
+
+ switch (*signature) {
+#ifdef __OPTIMIZE__
+ case DBUS_TYPE_BYTE:
+ case DBUS_TYPE_INT16:
+ case DBUS_TYPE_UINT16:
+ case DBUS_TYPE_INT32:
+ case DBUS_TYPE_UINT32:
+ case DBUS_TYPE_INT64:
+ case DBUS_TYPE_UINT64:
+ case DBUS_TYPE_DOUBLE:
+ qIterAppend(&iterator, ba, *signature, arg.constData());
+ return true;
+ case DBUS_TYPE_BOOLEAN:
+ append( arg.toBool() );
+ return true;
+#else
+ case DBUS_TYPE_BYTE:
+ append( qvariant_cast<uchar>(arg) );
+ return true;
+ case DBUS_TYPE_BOOLEAN:
+ append( arg.toBool() );
+ return true;
+ case DBUS_TYPE_INT16:
+ append( qvariant_cast<short>(arg) );
+ return true;
+ case DBUS_TYPE_UINT16:
+ append( qvariant_cast<ushort>(arg) );
+ return true;
+ case DBUS_TYPE_INT32:
+ append( static_cast<dbus_int32_t>(arg.toInt()) );
+ return true;
+ case DBUS_TYPE_UINT32:
+ append( static_cast<dbus_uint32_t>(arg.toUInt()) );
+ return true;
+ case DBUS_TYPE_INT64:
+ append( arg.toLongLong() );
+ return true;
+ case DBUS_TYPE_UINT64:
+ append( arg.toULongLong() );
+ return true;
+ case DBUS_TYPE_DOUBLE:
+ append( arg.toDouble() );
+ return true;
+#endif
+
+ case DBUS_TYPE_STRING:
+ append( arg.toString() );
+ return true;
+ case DBUS_TYPE_OBJECT_PATH:
+ append( qvariant_cast<QDBusObjectPath>(arg) );
+ return true;
+ case DBUS_TYPE_SIGNATURE:
+ append( qvariant_cast<QDBusSignature>(arg) );
+ return true;
+
+ // compound types:
+ case DBUS_TYPE_VARIANT:
+ // nested QVariant
+ return append( qvariant_cast<QDBusVariant>(arg) );
+
+ case DBUS_TYPE_ARRAY:
+ // could be many things
+ // find out what kind of array it is
+ switch (arg.type()) {
+ case QVariant::StringList:
+ append( arg.toStringList() );
+ return true;
+
+ case QVariant::ByteArray:
+ append( arg.toByteArray() );
+ return true;
+
+ default:
+ ; // fall through
+ }
+ // fall through
+
+ case DBUS_TYPE_STRUCT:
+ case DBUS_STRUCT_BEGIN_CHAR:
+ return appendRegisteredType( arg );
+
+ case DBUS_TYPE_DICT_ENTRY:
+ case DBUS_DICT_ENTRY_BEGIN_CHAR:
+ qFatal("QDBusMarshaller::appendVariantInternal got a DICT_ENTRY!");
+ return false;
+
+ case DBUS_TYPE_UNIX_FD:
+ if (capabilities & QDBusConnection::UnixFileDescriptorPassing || ba) {
+ append(qvariant_cast<QDBusUnixFileDescriptor>(arg));
+ return true;
+ }
+ // fall through
+
+ default:
+ qWarning("QDBusMarshaller::appendVariantInternal: Found unknown D-BUS type '%s'",
+ signature);
+ return false;
+ }
+
+ return true;
+}
+
+bool QDBusMarshaller::appendRegisteredType(const QVariant &arg)
+{
+ ref.ref(); // reference up
+ QDBusArgument self(QDBusArgumentPrivate::create(this));
+ return QDBusMetaType::marshall(self, arg.userType(), arg.constData());
+}
+
+bool QDBusMarshaller::appendCrossMarshalling(QDBusDemarshaller *demarshaller)
+{
+ int code = q_dbus_message_iter_get_arg_type(&demarshaller->iterator);
+ if (QDBusUtil::isValidBasicType(code)) {
+ // easy: just append
+ // do exactly like the D-BUS docs suggest
+ // (see apidocs for q_dbus_message_iter_get_basic)
+
+ qlonglong value;
+ q_dbus_message_iter_get_basic(&demarshaller->iterator, &value);
+ q_dbus_message_iter_next(&demarshaller->iterator);
+ q_dbus_message_iter_append_basic(&iterator, code, &value);
+ return true;
+ }
+
+ if (code == DBUS_TYPE_ARRAY) {
+ int element = q_dbus_message_iter_get_element_type(&demarshaller->iterator);
+ if (QDBusUtil::isValidFixedType(element) && element != DBUS_TYPE_UNIX_FD) {
+ // another optimization: fixed size arrays
+ // code is exactly like QDBusDemarshaller::toByteArray
+ DBusMessageIter sub;
+ q_dbus_message_iter_recurse(&demarshaller->iterator, &sub);
+ q_dbus_message_iter_next(&demarshaller->iterator);
+ int len;
+ void* data;
+ q_dbus_message_iter_get_fixed_array(&sub,&data,&len);
+
+ char signature[2] = { char(element), 0 };
+ q_dbus_message_iter_open_container(&iterator, DBUS_TYPE_ARRAY, signature, &sub);
+ q_dbus_message_iter_append_fixed_array(&sub, element, &data, len);
+ q_dbus_message_iter_close_container(&iterator, &sub);
+
+ return true;
+ }
+ }
+
+ // We have to recurse
+ QDBusDemarshaller *drecursed = demarshaller->beginCommon();
+
+ QDBusMarshaller mrecursed(capabilities); // create on the stack makes it autoclose
+ QByteArray subSignature;
+ const char *sig = 0;
+ if (code == DBUS_TYPE_VARIANT || code == DBUS_TYPE_ARRAY) {
+ subSignature = drecursed->currentSignature().toLatin1();
+ if (!subSignature.isEmpty())
+ sig = subSignature.constData();
+ }
+ open(mrecursed, code, sig);
+
+ while (!drecursed->atEnd()) {
+ if (!mrecursed.appendCrossMarshalling(drecursed)) {
+ delete drecursed;
+ return false;
+ }
+ }
+
+ delete drecursed;
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusmessage.cpp b/src/dbus/qdbusmessage.cpp
new file mode 100644
index 0000000000..bd77c77921
--- /dev/null
+++ b/src/dbus/qdbusmessage.cpp
@@ -0,0 +1,805 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusmessage.h"
+
+#include <qdebug.h>
+#include <qstringlist.h>
+
+#include "qdbus_symbols_p.h"
+
+#include "qdbusargument_p.h"
+#include "qdbuserror.h"
+#include "qdbusmessage_p.h"
+#include "qdbusmetatype.h"
+#include "qdbusconnection_p.h"
+#include "qdbusutil_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+static inline const char *data(const QByteArray &arr)
+{
+ return arr.isEmpty() ? 0 : arr.constData();
+}
+
+QDBusMessagePrivate::QDBusMessagePrivate()
+ : msg(0), reply(0), type(DBUS_MESSAGE_TYPE_INVALID),
+ timeout(-1), localReply(0), ref(1), delayedReply(false), localMessage(false),
+ parametersValidated(false), autoStartService(true)
+{
+}
+
+QDBusMessagePrivate::~QDBusMessagePrivate()
+{
+ if (msg)
+ q_dbus_message_unref(msg);
+ if (reply)
+ q_dbus_message_unref(reply);
+ delete localReply;
+}
+
+/*!
+ \since 4.3
+ Returns the human-readable message associated with the error that was received.
+*/
+QString QDBusMessage::errorMessage() const
+{
+ if (d_ptr->type == ErrorMessage) {
+ if (!d_ptr->message.isEmpty())
+ return d_ptr->message;
+ if (!d_ptr->arguments.isEmpty())
+ return d_ptr->arguments.at(0).toString();
+ }
+ return QString();
+}
+
+/*!
+ \internal
+ Constructs a DBusMessage object from \a message. The returned value must be de-referenced
+ with q_dbus_message_unref. The \a capabilities flags indicates which capabilities to use.
+
+ The \a error object is set to indicate the error if anything went wrong with the
+ marshalling. Usually, this error message will be placed in the reply, as if the call failed.
+ The \a error pointer must not be null.
+*/
+DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message, QDBusConnection::ConnectionCapabilities capabilities,
+ QDBusError *error)
+{
+ if (!qdbus_loadLibDBus()) {
+ *error = QDBusError(QDBusError::Failed, QLatin1String("Could not open lidbus-1 library"));
+ return 0;
+ }
+
+ DBusMessage *msg = 0;
+ const QDBusMessagePrivate *d_ptr = message.d_ptr;
+
+ switch (d_ptr->type) {
+ case DBUS_MESSAGE_TYPE_INVALID:
+ //qDebug() << "QDBusMessagePrivate::toDBusMessage" << "message is invalid";
+ break;
+ case DBUS_MESSAGE_TYPE_METHOD_CALL:
+ // only service and interface can be empty -> path and name must not be empty
+ if (!d_ptr->parametersValidated) {
+ if (!QDBusUtil::checkBusName(d_ptr->service, QDBusUtil::EmptyAllowed, error))
+ return 0;
+ if (!QDBusUtil::checkObjectPath(d_ptr->path, QDBusUtil::EmptyNotAllowed, error))
+ return 0;
+ if (!QDBusUtil::checkInterfaceName(d_ptr->interface, QDBusUtil::EmptyAllowed, error))
+ return 0;
+ if (!QDBusUtil::checkMemberName(d_ptr->name, QDBusUtil::EmptyNotAllowed, error, "method"))
+ return 0;
+ }
+
+ msg = q_dbus_message_new_method_call(data(d_ptr->service.toUtf8()), d_ptr->path.toUtf8(),
+ data(d_ptr->interface.toUtf8()), d_ptr->name.toUtf8());
+ q_dbus_message_set_auto_start( msg, d_ptr->autoStartService );
+ break;
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
+ if (!d_ptr->localMessage) {
+ q_dbus_message_set_destination(msg, q_dbus_message_get_sender(d_ptr->reply));
+ q_dbus_message_set_reply_serial(msg, q_dbus_message_get_serial(d_ptr->reply));
+ }
+ break;
+ case DBUS_MESSAGE_TYPE_ERROR:
+ // error name can't be empty
+ if (!d_ptr->parametersValidated
+ && !QDBusUtil::checkErrorName(d_ptr->name, QDBusUtil::EmptyNotAllowed, error))
+ return 0;
+
+ msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_ERROR);
+ q_dbus_message_set_error_name(msg, d_ptr->name.toUtf8());
+ if (!d_ptr->localMessage) {
+ q_dbus_message_set_destination(msg, q_dbus_message_get_sender(d_ptr->reply));
+ q_dbus_message_set_reply_serial(msg, q_dbus_message_get_serial(d_ptr->reply));
+ }
+ break;
+ case DBUS_MESSAGE_TYPE_SIGNAL:
+ // nothing can be empty here
+ if (!d_ptr->parametersValidated) {
+ if (!QDBusUtil::checkObjectPath(d_ptr->path, QDBusUtil::EmptyNotAllowed, error))
+ return 0;
+ if (!QDBusUtil::checkInterfaceName(d_ptr->interface, QDBusUtil::EmptyAllowed, error))
+ return 0;
+ if (!QDBusUtil::checkMemberName(d_ptr->name, QDBusUtil::EmptyNotAllowed, error, "method"))
+ return 0;
+ }
+
+ msg = q_dbus_message_new_signal(d_ptr->path.toUtf8(), d_ptr->interface.toUtf8(),
+ d_ptr->name.toUtf8());
+ break;
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+
+ // if we got here, the parameters validated
+ // and since the message parameters cannot be changed once the message is created
+ // we can record this fact
+ d_ptr->parametersValidated = true;
+
+ QDBusMarshaller marshaller(capabilities);
+ QVariantList::ConstIterator it = d_ptr->arguments.constBegin();
+ QVariantList::ConstIterator cend = d_ptr->arguments.constEnd();
+ q_dbus_message_iter_init_append(msg, &marshaller.iterator);
+ if (!d_ptr->message.isEmpty())
+ // prepend the error message
+ marshaller.append(d_ptr->message);
+ for ( ; it != cend; ++it)
+ marshaller.appendVariantInternal(*it);
+
+ // check if everything is ok
+ if (marshaller.ok)
+ return msg;
+
+ // not ok;
+ q_dbus_message_unref(msg);
+ *error = QDBusError(QDBusError::Failed, QLatin1String("Marshalling failed: ") + marshaller.errorString);
+ return 0;
+}
+
+/*
+struct DBusMessage
+{
+ DBusAtomic refcount;
+ DBusHeader header;
+ DBusString body;
+ char byte_order;
+ unsigned int locked : 1;
+DBUS_DISABLE_CHECKS
+ unsigned int in_cache : 1;
+#endif
+ DBusList *size_counters;
+ long size_counter_delta;
+ dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS;
+ DBusDataSlotList slot_list;
+#ifndef DBUS_DISABLE_CHECKS
+ int generation;
+#endif
+};
+*/
+
+/*!
+ \internal
+ Constructs a QDBusMessage by parsing the given DBusMessage object.
+*/
+QDBusMessage QDBusMessagePrivate::fromDBusMessage(DBusMessage *dmsg, QDBusConnection::ConnectionCapabilities capabilities)
+{
+ QDBusMessage message;
+ if (!dmsg)
+ return message;
+
+ message.d_ptr->type = q_dbus_message_get_type(dmsg);
+ message.d_ptr->path = QString::fromUtf8(q_dbus_message_get_path(dmsg));
+ message.d_ptr->interface = QString::fromUtf8(q_dbus_message_get_interface(dmsg));
+ message.d_ptr->name = message.d_ptr->type == DBUS_MESSAGE_TYPE_ERROR ?
+ QString::fromUtf8(q_dbus_message_get_error_name(dmsg)) :
+ QString::fromUtf8(q_dbus_message_get_member(dmsg));
+ message.d_ptr->service = QString::fromUtf8(q_dbus_message_get_sender(dmsg));
+ message.d_ptr->signature = QString::fromUtf8(q_dbus_message_get_signature(dmsg));
+ message.d_ptr->msg = q_dbus_message_ref(dmsg);
+
+ QDBusDemarshaller demarshaller(capabilities);
+ demarshaller.message = q_dbus_message_ref(dmsg);
+ if (q_dbus_message_iter_init(demarshaller.message, &demarshaller.iterator))
+ while (!demarshaller.atEnd())
+ message << demarshaller.toVariantInternal();
+ return message;
+}
+
+bool QDBusMessagePrivate::isLocal(const QDBusMessage &message)
+{
+ return message.d_ptr->localMessage;
+}
+
+QDBusMessage QDBusMessagePrivate::makeLocal(const QDBusConnectionPrivate &conn,
+ const QDBusMessage &asSent)
+{
+ // simulate the message being sent to the bus and then received back
+ // the only field that the bus sets when delivering the message
+ // (as opposed to the message as we send it), is the sender
+ // so we simply set the sender to our unique name
+
+ // determine if we are carrying any complex types
+ QString computedSignature;
+ QVariantList::ConstIterator it = asSent.d_ptr->arguments.constBegin();
+ QVariantList::ConstIterator end = asSent.d_ptr->arguments.constEnd();
+ for ( ; it != end; ++it) {
+ int id = it->userType();
+ const char *signature = QDBusMetaType::typeToSignature(id);
+ if ((id != QVariant::StringList && id != QVariant::ByteArray &&
+ qstrlen(signature) != 1) || id == qMetaTypeId<QDBusVariant>()) {
+ // yes, we are
+ // we must marshall and demarshall again so as to create QDBusArgument
+ // entries for the complex types
+ QDBusError error;
+ DBusMessage *message = toDBusMessage(asSent, conn.capabilities, &error);
+ if (!message) {
+ // failed to marshall, so it's a call error
+ return QDBusMessage::createError(error);
+ }
+
+ q_dbus_message_set_sender(message, conn.baseService.toUtf8());
+
+ QDBusMessage retval = fromDBusMessage(message, conn.capabilities);
+ retval.d_ptr->localMessage = true;
+ q_dbus_message_unref(message);
+ if (retval.d_ptr->service.isEmpty())
+ retval.d_ptr->service = conn.baseService;
+ return retval;
+ } else {
+ computedSignature += QLatin1String(signature);
+ }
+ }
+
+ // no complex types seen
+ // optimize by using the variant list itself
+ QDBusMessage retval;
+ QDBusMessagePrivate *d = retval.d_ptr;
+ d->arguments = asSent.d_ptr->arguments;
+ d->path = asSent.d_ptr->path;
+ d->interface = asSent.d_ptr->interface;
+ d->name = asSent.d_ptr->name;
+ d->message = asSent.d_ptr->message;
+ d->type = asSent.d_ptr->type;
+
+ d->service = conn.baseService;
+ d->signature = computedSignature;
+ d->localMessage = true;
+ return retval;
+}
+
+QDBusMessage QDBusMessagePrivate::makeLocalReply(const QDBusConnectionPrivate &conn,
+ const QDBusMessage &callMsg)
+{
+ // simulate the reply (return or error) message being sent to the bus and
+ // then received back.
+ if (callMsg.d_ptr->localReply)
+ return makeLocal(conn, *callMsg.d_ptr->localReply);
+ return QDBusMessage(); // failed
+}
+
+/*!
+ \class QDBusMessage
+ \inmodule QtDBus
+ \since 4.2
+
+ \brief The QDBusMessage class represents one message sent or
+ received over the D-Bus bus.
+
+ This object can represent any of the four different types of
+ messages (MessageType) that can occur on the bus:
+
+ \list
+ \o Method calls
+ \o Method return values
+ \o Signal emissions
+ \o Error codes
+ \endlist
+
+ Objects of this type are created with the static createError(),
+ createMethodCall() and createSignal() functions. Use the
+ QDBusConnection::send() function to send the messages.
+*/
+
+/*!
+ \enum QDBusMessage::MessageType
+ The possible message types:
+
+ \value MethodCallMessage a message representing an outgoing or incoming method call
+ \value SignalMessage a message representing an outgoing or incoming signal emission
+ \value ReplyMessage a message representing the return values of a method call
+ \value ErrorMessage a message representing an error condition in response to a method call
+ \value InvalidMessage an invalid message: this is never set on messages received from D-Bus
+*/
+
+/*!
+ Constructs a new DBus message with the given \a path, \a interface
+ and \a name, representing a signal emission.
+
+ A DBus signal is emitted from one application and is received by
+ all applications that are listening for that signal from that
+ interface.
+
+ The QDBusMessage object that is returned can be sent using the
+ QDBusConnection::send() function.
+*/
+QDBusMessage QDBusMessage::createSignal(const QString &path, const QString &interface,
+ const QString &name)
+{
+ QDBusMessage message;
+ message.d_ptr->type = DBUS_MESSAGE_TYPE_SIGNAL;
+ message.d_ptr->path = path;
+ message.d_ptr->interface = interface;
+ message.d_ptr->name = name;
+
+ return message;
+}
+
+/*!
+ Constructs a new DBus message representing a method call.
+ A method call always informs its destination address
+ (\a service, \a path, \a interface and \a method).
+
+ The DBus bus allows calling a method on a given remote object without specifying the
+ destination interface, if the method name is unique. However, if two interfaces on the
+ remote object export the same method name, the result is undefined (one of the two may be
+ called or an error may be returned).
+
+ When using DBus in a peer-to-peer context (i.e., not on a bus), the \a service parameter is
+ optional.
+
+ The QDBusObject and QDBusInterface classes provide a simpler abstraction to synchronous
+ method calling.
+
+ This function returns a QDBusMessage object that can be sent with
+ QDBusConnection::call().
+*/
+QDBusMessage QDBusMessage::createMethodCall(const QString &service, const QString &path,
+ const QString &interface, const QString &method)
+{
+ QDBusMessage message;
+ message.d_ptr->type = DBUS_MESSAGE_TYPE_METHOD_CALL;
+ message.d_ptr->service = service;
+ message.d_ptr->path = path;
+ message.d_ptr->interface = interface;
+ message.d_ptr->name = method;
+
+ return message;
+}
+
+/*!
+ Constructs a new DBus message representing an error,
+ with the given \a name and \a msg.
+*/
+QDBusMessage QDBusMessage::createError(const QString &name, const QString &msg)
+{
+ QDBusMessage error;
+ error.d_ptr->type = DBUS_MESSAGE_TYPE_ERROR;
+ error.d_ptr->name = name;
+ error.d_ptr->message = msg;
+
+ return error;
+}
+
+/*!
+ \fn QDBusMessage QDBusMessage::createError(const QDBusError &error)
+
+ Constructs a new DBus message representing the given \a error.
+*/
+
+/*!
+ \fn QDBusMessage QDBusMessage::createError(QDBusError::ErrorType type, const QString &msg)
+
+ Constructs a new DBus message for the error type \a type using
+ the message \a msg. Returns the DBus message.
+*/
+
+/*!
+ \fn QDBusMessage QDBusMessage::createReply(const QList<QVariant> &arguments) const
+
+ Constructs a new DBus message representing a reply, with the given
+ \a arguments.
+*/
+QDBusMessage QDBusMessage::createReply(const QVariantList &arguments) const
+{
+ QDBusMessage reply;
+ reply.setArguments(arguments);
+ reply.d_ptr->type = DBUS_MESSAGE_TYPE_METHOD_RETURN;
+ if (d_ptr->msg)
+ reply.d_ptr->reply = q_dbus_message_ref(d_ptr->msg);
+ if (d_ptr->localMessage) {
+ reply.d_ptr->localMessage = true;
+ d_ptr->localReply = new QDBusMessage(reply); // keep an internal copy
+ }
+
+ // the reply must have a msg or be a local-loop optimization
+ Q_ASSERT(reply.d_ptr->reply || reply.d_ptr->localMessage);
+ return reply;
+}
+
+/*!
+ Constructs a new DBus message representing an error reply message,
+ with the given \a name and \a msg.
+*/
+QDBusMessage QDBusMessage::createErrorReply(const QString name, const QString &msg) const
+{
+ QDBusMessage reply = QDBusMessage::createError(name, msg);
+ if (d_ptr->msg)
+ reply.d_ptr->reply = q_dbus_message_ref(d_ptr->msg);
+ if (d_ptr->localMessage) {
+ reply.d_ptr->localMessage = true;
+ d_ptr->localReply = new QDBusMessage(reply); // keep an internal copy
+ }
+
+ // the reply must have a msg or be a local-loop optimization
+ Q_ASSERT(reply.d_ptr->reply || reply.d_ptr->localMessage);
+ return reply;
+}
+
+/*!
+ \fn QDBusMessage QDBusMessage::createReply(const QVariant &argument) const
+
+ Constructs a new DBus message representing a reply, with the
+ given \a argument.
+*/
+
+/*!
+ \fn QDBusMessage QDBusMessage::createErrorReply(const QDBusError &error) const
+
+ Constructs a new DBus message representing an error reply message,
+ from the given \a error object.
+*/
+
+/*!
+ \fn QDBusMessage QDBusMessage::createErrorReply(QDBusError::ErrorType type, const QString &msg) const
+
+ Constructs a new DBus reply message for the error type \a type using
+ the message \a msg. Returns the DBus message.
+*/
+QDBusMessage QDBusMessage::createErrorReply(QDBusError::ErrorType atype, const QString &amsg) const
+{
+ QDBusMessage msg = createErrorReply(QDBusError::errorString(atype), amsg);
+ msg.d_ptr->parametersValidated = true;
+ return msg;
+}
+
+
+/*!
+ Constructs an empty, invalid QDBusMessage object.
+
+ \sa createError(), createMethodCall(), createSignal()
+*/
+QDBusMessage::QDBusMessage()
+{
+ d_ptr = new QDBusMessagePrivate;
+}
+
+/*!
+ Constructs a copy of the object given by \a other.
+
+ Note: QDBusMessage objects are shared. Modifications made to the
+ copy will affect the original one as well. See setDelayedReply()
+ for more information.
+*/
+QDBusMessage::QDBusMessage(const QDBusMessage &other)
+{
+ d_ptr = other.d_ptr;
+ d_ptr->ref.ref();
+}
+
+/*!
+ Disposes of the object and frees any resources that were being held.
+*/
+QDBusMessage::~QDBusMessage()
+{
+ if (!d_ptr->ref.deref())
+ delete d_ptr;
+}
+
+/*!
+ Copies the contents of the object given by \a other.
+
+ Note: QDBusMessage objects are shared. Modifications made to the
+ copy will affect the original one as well. See setDelayedReply()
+ for more information.
+*/
+QDBusMessage &QDBusMessage::operator=(const QDBusMessage &other)
+{
+ qAtomicAssign(d_ptr, other.d_ptr);
+ return *this;
+}
+
+/*!
+ Returns the name of the service or the bus address of the remote method call.
+*/
+QString QDBusMessage::service() const
+{
+ return d_ptr->service;
+}
+
+/*!
+ Returns the path of the object that this message is being sent to (in the case of a
+ method call) or being received from (for a signal).
+*/
+QString QDBusMessage::path() const
+{
+ return d_ptr->path;
+}
+
+/*!
+ Returns the interface of the method being called (in the case of a method call) or of
+ the signal being received from.
+*/
+QString QDBusMessage::interface() const
+{
+ return d_ptr->interface;
+}
+
+/*!
+ Returns the name of the signal that was emitted or the name of the method that was called.
+*/
+QString QDBusMessage::member() const
+{
+ if (d_ptr->type != ErrorMessage)
+ return d_ptr->name;
+ return QString();
+}
+
+/*!
+ Returns the name of the error that was received.
+*/
+QString QDBusMessage::errorName() const
+{
+ if (d_ptr->type == ErrorMessage)
+ return d_ptr->name;
+ return QString();
+}
+
+/*!
+ Returns the signature of the signal that was received or for the output arguments
+ of a method call.
+*/
+QString QDBusMessage::signature() const
+{
+ return d_ptr->signature;
+}
+
+/*!
+ Returns the flag that indicates if this message should see a reply
+ or not. This is only meaningful for \l {MethodCallMessage}{method
+ call messages}: any other kind of message cannot have replies and
+ this function will always return false for them.
+*/
+bool QDBusMessage::isReplyRequired() const
+{
+ if (!d_ptr->msg)
+ return d_ptr->localMessage; // if it's a local message, reply is required
+ return !q_dbus_message_get_no_reply(d_ptr->msg);
+}
+
+/*!
+ Sets whether the message will be replied later (if \a enable is
+ true) or if an automatic reply should be generated by QtDBus
+ (if \a enable is false).
+
+ In D-Bus, all method calls must generate a reply to the caller, unless the
+ caller explicitly indicates otherwise (see isReplyRequired()). QtDBus
+ automatically generates such replies for any slots being called, but it
+ also allows slots to indicate whether they will take responsibility
+ of sending the reply at a later time, after the function has finished
+ processing.
+
+ \sa {Delayed Replies}
+*/
+void QDBusMessage::setDelayedReply(bool enable) const
+{
+ d_ptr->delayedReply = enable;
+}
+
+/*!
+ Returns the delayed reply flag, as set by setDelayedReply(). By default, this
+ flag is false, which means QtDBus will generate automatic replies
+ when necessary.
+*/
+bool QDBusMessage::isDelayedReply() const
+{
+ return d_ptr->delayedReply;
+}
+
+/*!
+ Sets the auto start flag to \a enable. This flag only makes sense
+ for method call messages, where it tells the D-Bus server to
+ either auto start the service responsible for the service name, or
+ not to auto start it.
+
+ By default this flag is true, i.e. a service is autostarted.
+ This means:
+
+ When the service that this method call is sent to is already
+ running, the method call is sent to it. If the service is not
+ running yet, the D-Bus daemon is requested to autostart the
+ service that is assigned to this service name. This is
+ handled by .service files that are placed in a directory known
+ to the D-Bus server. These files then each contain a service
+ name and the path to a program that should be executed when
+ this service name is requested.
+
+ \since 4.7
+*/
+void QDBusMessage::setAutoStartService(bool enable)
+{
+ d_ptr->autoStartService = enable;
+}
+
+/*!
+ Returns the auto start flag, as set by setAutoStartService(). By default, this
+ flag is true, which means QtDBus will auto start a service, if it is
+ not running already.
+
+ \sa setAutoStartService()
+
+ \since 4.7
+*/
+bool QDBusMessage::autoStartService() const
+{
+ return d_ptr->autoStartService;
+}
+
+/*!
+ Sets the arguments that are going to be sent over D-Bus to \a arguments. Those
+ will be the arguments to a method call or the parameters in the signal.
+
+ \sa arguments()
+*/
+void QDBusMessage::setArguments(const QList<QVariant> &arguments)
+{
+ // FIXME: should we detach?
+ d_ptr->arguments = arguments;
+}
+
+/*!
+ Returns the list of arguments that are going to be sent or were received from
+ D-Bus.
+*/
+QList<QVariant> QDBusMessage::arguments() const
+{
+ return d_ptr->arguments;
+}
+
+/*!
+ Appends the argument \a arg to the list of arguments to be sent over D-Bus in
+ a method call or signal emission.
+*/
+
+QDBusMessage &QDBusMessage::operator<<(const QVariant &arg)
+{
+ // FIXME: should we detach?
+ d_ptr->arguments.append(arg);
+ return *this;
+}
+
+/*!
+ Returns the message type.
+*/
+QDBusMessage::MessageType QDBusMessage::type() const
+{
+ switch (d_ptr->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:
+ break;
+ }
+ return InvalidMessage;
+}
+
+/*!
+ Sends the message without waiting for a reply. This is suitable
+ for errors, signals, and return values as well as calls whose
+ return values are not necessary.
+
+ Returns true if the message was queued successfully;
+ otherwise returns false.
+
+ \sa QDBusConnection::send()
+*/
+#ifndef QT_NO_DEBUG_STREAM
+static QDebug operator<<(QDebug dbg, QDBusMessage::MessageType t)
+{
+ switch (t)
+ {
+ case QDBusMessage::MethodCallMessage:
+ return dbg << "MethodCall";
+ case QDBusMessage::ReplyMessage:
+ return dbg << "MethodReturn";
+ case QDBusMessage::SignalMessage:
+ return dbg << "Signal";
+ case QDBusMessage::ErrorMessage:
+ return dbg << "Error";
+ default:
+ return dbg << "Invalid";
+ }
+}
+
+static void debugVariantList(QDebug dbg, const QVariantList &list)
+{
+ bool first = true;
+ QVariantList::ConstIterator it = list.constBegin();
+ QVariantList::ConstIterator end = list.constEnd();
+ for ( ; it != end; ++it) {
+ if (!first)
+ dbg.nospace() << ", ";
+ dbg.nospace() << qPrintable(QDBusUtil::argumentToString(*it));
+ first = false;
+ }
+}
+
+QDebug operator<<(QDebug dbg, const QDBusMessage &msg)
+{
+ dbg.nospace() << "QDBusMessage(type=" << msg.type()
+ << ", service=" << msg.service();
+ if (msg.type() == QDBusMessage::MethodCallMessage ||
+ msg.type() == QDBusMessage::SignalMessage)
+ dbg.nospace() << ", path=" << msg.path()
+ << ", interface=" << msg.interface()
+ << ", member=" << msg.member();
+ if (msg.type() == QDBusMessage::ErrorMessage)
+ dbg.nospace() << ", error name=" << msg.errorName()
+ << ", error message=" << msg.errorMessage();
+ dbg.nospace() << ", signature=" << msg.signature()
+ << ", contents=(";
+ debugVariantList(dbg, msg.arguments());
+ dbg.nospace() << ") )";
+ return dbg.space();
+}
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusmessage.h b/src/dbus/qdbusmessage.h
new file mode 100644
index 0000000000..d88cb4738d
--- /dev/null
+++ b/src/dbus/qdbusmessage.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSMESSAGE_H
+#define QDBUSMESSAGE_H
+
+#include <QtDBus/qdbusmacros.h>
+#include <QtDBus/qdbuserror.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qvariant.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(DBus)
+
+class QDBusMessagePrivate;
+class Q_DBUS_EXPORT QDBusMessage
+{
+public:
+ enum MessageType {
+ InvalidMessage,
+ MethodCallMessage,
+ ReplyMessage,
+ ErrorMessage,
+ SignalMessage
+ };
+
+ QDBusMessage();
+ QDBusMessage(const QDBusMessage &other);
+ QDBusMessage &operator=(const QDBusMessage &other);
+ ~QDBusMessage();
+
+ static QDBusMessage createSignal(const QString &path, const QString &interface,
+ const QString &name);
+ static QDBusMessage createMethodCall(const QString &destination, const QString &path,
+ const QString &interface, const QString &method);
+ static QDBusMessage createError(const QString &name, const QString &msg);
+ static inline QDBusMessage createError(const QDBusError &err)
+ { return createError(err.name(), err.message()); }
+ static inline QDBusMessage createError(QDBusError::ErrorType type, const QString &msg)
+ { return createError(QDBusError::errorString(type), msg); }
+
+ QDBusMessage createReply(const QList<QVariant> &arguments = QList<QVariant>()) const;
+ inline QDBusMessage createReply(const QVariant &argument) const
+ { return createReply(QList<QVariant>() << argument); }
+
+ QDBusMessage createErrorReply(const QString name, const QString &msg) const;
+ inline QDBusMessage createErrorReply(const QDBusError &err) const
+ { return createErrorReply(err.name(), err.message()); }
+ QDBusMessage createErrorReply(QDBusError::ErrorType type, const QString &msg) const;
+
+ // there are no setters; if this changes, see qdbusmessage_p.h
+ QString service() const;
+ QString path() const;
+ QString interface() const;
+ QString member() const;
+ QString errorName() const;
+ QString errorMessage() const;
+ MessageType type() const;
+ QString signature() const;
+
+ bool isReplyRequired() const;
+
+ void setDelayedReply(bool enable) const;
+ bool isDelayedReply() const;
+
+ void setAutoStartService(bool enable);
+ bool autoStartService() const;
+
+ void setArguments(const QList<QVariant> &arguments);
+ QList<QVariant> arguments() const;
+
+ QDBusMessage &operator<<(const QVariant &arg);
+
+private:
+ friend class QDBusMessagePrivate;
+ QDBusMessagePrivate *d_ptr;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_DBUS_EXPORT QDebug operator<<(QDebug, const QDBusMessage &);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif
+
diff --git a/src/dbus/qdbusmessage_p.h b/src/dbus/qdbusmessage_p.h
new file mode 100644
index 0000000000..52d4d25cdc
--- /dev/null
+++ b/src/dbus/qdbusmessage_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSMESSAGE_P_H
+#define QDBUSMESSAGE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qatomic.h>
+#include <qstring.h>
+#include <qdbusmessage.h>
+#include <qdbusconnection.h>
+
+struct DBusMessage;
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+class QDBusConnectionPrivate;
+
+class QDBusMessagePrivate
+{
+public:
+ QDBusMessagePrivate();
+ ~QDBusMessagePrivate();
+
+ QList<QVariant> arguments;
+
+ // the following parameters are "const": they are not changed after the constructors
+ // the parametersValidated member below controls whether they've been validated already
+ QString service, path, interface, name, message, signature;
+
+ DBusMessage *msg;
+ DBusMessage *reply;
+ int type;
+ int timeout;
+ mutable QDBusMessage *localReply;
+ QAtomicInt ref;
+
+ mutable uint delayedReply : 1;
+ uint localMessage : 1;
+ mutable uint parametersValidated : 1;
+ uint autoStartService : 1;
+
+ static void setParametersValidated(QDBusMessage &msg, bool enable)
+ { msg.d_ptr->parametersValidated = enable; }
+
+ static DBusMessage *toDBusMessage(const QDBusMessage &message, QDBusConnection::ConnectionCapabilities capabilities,
+ QDBusError *error);
+ static QDBusMessage fromDBusMessage(DBusMessage *dmsg, QDBusConnection::ConnectionCapabilities capabilities);
+
+ static bool isLocal(const QDBusMessage &msg);
+ static QDBusMessage makeLocal(const QDBusConnectionPrivate &conn,
+ const QDBusMessage &asSent);
+ static QDBusMessage makeLocalReply(const QDBusConnectionPrivate &conn,
+ const QDBusMessage &asSent);
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusmetaobject.cpp b/src/dbus/qdbusmetaobject.cpp
new file mode 100644
index 0000000000..df8bc1d288
--- /dev/null
+++ b/src/dbus/qdbusmetaobject.cpp
@@ -0,0 +1,703 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusmetaobject_p.h"
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qvarlengtharray.h>
+
+#include "qdbusutil_p.h"
+#include "qdbuserror.h"
+#include "qdbusmetatype.h"
+#include "qdbusargument.h"
+#include "qdbusintrospection_p.h"
+#include "qdbusabstractinterface_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+class QDBusMetaObjectGenerator
+{
+public:
+ QDBusMetaObjectGenerator(const QString &interface,
+ const QDBusIntrospection::Interface *parsedData);
+ void write(QDBusMetaObject *obj);
+ void writeWithoutXml(QDBusMetaObject *obj);
+
+private:
+ struct Method {
+ QByteArray parameters;
+ QByteArray typeName;
+ QByteArray tag;
+ QByteArray name;
+ QByteArray inputSignature;
+ QByteArray outputSignature;
+ QVarLengthArray<int, 4> inputTypes;
+ QVarLengthArray<int, 4> outputTypes;
+ int flags;
+ };
+
+ struct Property {
+ QByteArray typeName;
+ QByteArray signature;
+ int type;
+ int flags;
+ };
+ struct Type {
+ int id;
+ QByteArray name;
+ };
+
+ enum PropertyFlags {
+ Invalid = 0x00000000,
+ Readable = 0x00000001,
+ Writable = 0x00000002,
+ Resettable = 0x00000004,
+ EnumOrFlag = 0x00000008,
+ StdCppSet = 0x00000100,
+ // Override = 0x00000200,
+ Designable = 0x00001000,
+ ResolveDesignable = 0x00002000,
+ Scriptable = 0x00004000,
+ ResolveScriptable = 0x00008000,
+ Stored = 0x00010000,
+ ResolveStored = 0x00020000,
+ Editable = 0x00040000,
+ ResolveEditable = 0x00080000,
+ User = 0x00100000,
+ ResolveUser = 0x00200000
+ };
+
+ enum MethodFlags {
+ AccessPrivate = 0x00,
+ AccessProtected = 0x01,
+ AccessPublic = 0x02,
+ AccessMask = 0x03, //mask
+
+ MethodMethod = 0x00,
+ MethodSignal = 0x04,
+ MethodSlot = 0x08,
+ MethodTypeMask = 0x0c,
+
+ MethodCompatibility = 0x10,
+ MethodCloned = 0x20,
+ MethodScriptable = 0x40
+ };
+
+ QMap<QByteArray, Method> methods;
+ QMap<QByteArray, Property> properties;
+
+ const QDBusIntrospection::Interface *data;
+ QString interface;
+
+ Type findType(const QByteArray &signature,
+ const QDBusIntrospection::Annotations &annotations,
+ const char *direction = "Out", int id = -1);
+
+ void parseMethods();
+ void parseSignals();
+ void parseProperties();
+};
+
+static const int intsPerProperty = 2;
+static const int intsPerMethod = 5;
+
+// ### from kernel/qmetaobject.cpp (Qt 4.1.2):
+struct QDBusMetaObjectPrivate
+{
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ int propertyCount, propertyData;
+ int enumeratorCount, enumeratorData;
+
+ // this is specific for QDBusMetaObject:
+ int propertyDBusData;
+ int methodDBusData;
+};
+
+QDBusMetaObjectGenerator::QDBusMetaObjectGenerator(const QString &interfaceName,
+ const QDBusIntrospection::Interface *parsedData)
+ : data(parsedData), interface(interfaceName)
+{
+ if (data) {
+ parseProperties();
+ parseSignals(); // call parseSignals first so that slots override signals
+ parseMethods();
+ }
+}
+
+Q_DBUS_EXPORT bool qt_dbus_metaobject_skip_annotations = false;
+
+QDBusMetaObjectGenerator::Type
+QDBusMetaObjectGenerator::findType(const QByteArray &signature,
+ const QDBusIntrospection::Annotations &annotations,
+ const char *direction, int id)
+{
+ Type result;
+ result.id = QVariant::Invalid;
+
+ int type = QDBusMetaType::signatureToType(signature);
+ if (type == QVariant::Invalid && !qt_dbus_metaobject_skip_annotations) {
+ // it's not a type normally handled by our meta type system
+ // it must contain an annotation
+ QString annotationName = QString::fromLatin1("com.trolltech.QtDBus.QtTypeName");
+ if (id >= 0)
+ annotationName += QString::fromLatin1(".%1%2")
+ .arg(QLatin1String(direction))
+ .arg(id);
+
+ // extract from annotations:
+ QByteArray typeName = annotations.value(annotationName).toLatin1();
+
+ // verify that it's a valid one
+ if (!typeName.isEmpty()) {
+ // type name found
+ type = QVariant::nameToType(typeName);
+ if (type == QVariant::UserType)
+ type = QMetaType::type(typeName);
+ }
+
+ if (type == QVariant::Invalid || signature != QDBusMetaType::typeToSignature(type)) {
+ // type is still unknown or doesn't match back to the signature that it
+ // was expected to, so synthesize a fake type
+ type = QMetaType::VoidStar;
+ typeName = "QDBusRawType<0x" + signature.toHex() + ">*";
+ }
+
+ result.name = typeName;
+ } else if (type == QVariant::Invalid) {
+ // this case is used only by the qdbus command-line tool
+ // invalid, let's create an impossible type that contains the signature
+
+ if (signature == "av") {
+ result.name = "QVariantList";
+ type = QVariant::List;
+ } else if (signature == "a{sv}") {
+ result.name = "QVariantMap";
+ type = QVariant::Map;
+ } else {
+ result.name = "QDBusRawType::" + signature;
+ type = -1;
+ }
+ } else {
+ result.name = QVariant::typeToName( QVariant::Type(type) );
+ }
+
+ result.id = type;
+ return result; // success
+}
+
+void QDBusMetaObjectGenerator::parseMethods()
+{
+ //
+ // TODO:
+ // Add cloned methods when the remote object has return types
+ //
+
+ QDBusIntrospection::Methods::ConstIterator method_it = data->methods.constBegin();
+ QDBusIntrospection::Methods::ConstIterator method_end = data->methods.constEnd();
+ for ( ; method_it != method_end; ++method_it) {
+ const QDBusIntrospection::Method &m = *method_it;
+ Method mm;
+
+ mm.name = m.name.toLatin1();
+ QByteArray prototype = mm.name;
+ prototype += '(';
+
+ bool ok = true;
+
+ // build the input argument list
+ for (int i = 0; i < m.inputArgs.count(); ++i) {
+ const QDBusIntrospection::Argument &arg = m.inputArgs.at(i);
+
+ Type type = findType(arg.type.toLatin1(), m.annotations, "In", i);
+ if (type.id == QVariant::Invalid) {
+ ok = false;
+ break;
+ }
+
+ mm.inputSignature += arg.type.toLatin1();
+ mm.inputTypes.append(type.id);
+
+ mm.parameters.append(arg.name.toLatin1());
+ mm.parameters.append(',');
+
+ prototype.append(type.name);
+ prototype.append(',');
+ }
+ if (!ok) continue;
+
+ // build the output argument list:
+ for (int i = 0; i < m.outputArgs.count(); ++i) {
+ const QDBusIntrospection::Argument &arg = m.outputArgs.at(i);
+
+ Type type = findType(arg.type.toLatin1(), m.annotations, "Out", i);
+ if (type.id == QVariant::Invalid) {
+ ok = false;
+ break;
+ }
+
+ mm.outputSignature += arg.type.toLatin1();
+ mm.outputTypes.append(type.id);
+
+ if (i == 0) {
+ // return value
+ mm.typeName = type.name;
+ } else {
+ // non-const ref parameter
+ mm.parameters.append(arg.name.toLatin1());
+ mm.parameters.append(',');
+
+ prototype.append(type.name);
+ prototype.append("&,");
+ }
+ }
+ if (!ok) continue;
+
+ // convert the last commas:
+ if (!mm.parameters.isEmpty()) {
+ mm.parameters.truncate(mm.parameters.length() - 1);
+ prototype[prototype.length() - 1] = ')';
+ } else {
+ prototype.append(')');
+ }
+
+ // check the async tag
+ if (m.annotations.value(QLatin1String(ANNOTATION_NO_WAIT)) == QLatin1String("true"))
+ mm.tag = "Q_NOREPLY";
+
+ // meta method flags
+ mm.flags = AccessPublic | MethodSlot | MethodScriptable;
+
+ // add
+ methods.insert(QMetaObject::normalizedSignature(prototype), mm);
+ }
+}
+
+void QDBusMetaObjectGenerator::parseSignals()
+{
+ QDBusIntrospection::Signals::ConstIterator signal_it = data->signals_.constBegin();
+ QDBusIntrospection::Signals::ConstIterator signal_end = data->signals_.constEnd();
+ for ( ; signal_it != signal_end; ++signal_it) {
+ const QDBusIntrospection::Signal &s = *signal_it;
+ Method mm;
+
+ mm.name = s.name.toLatin1();
+ QByteArray prototype = mm.name;
+ prototype += '(';
+
+ bool ok = true;
+
+ // build the output argument list
+ for (int i = 0; i < s.outputArgs.count(); ++i) {
+ const QDBusIntrospection::Argument &arg = s.outputArgs.at(i);
+
+ Type type = findType(arg.type.toLatin1(), s.annotations, "Out", i);
+ if (type.id == QVariant::Invalid) {
+ ok = false;
+ break;
+ }
+
+ mm.inputSignature += arg.type.toLatin1();
+ mm.inputTypes.append(type.id);
+
+ mm.parameters.append(arg.name.toLatin1());
+ mm.parameters.append(',');
+
+ prototype.append(type.name);
+ prototype.append(',');
+ }
+ if (!ok) continue;
+
+ // convert the last commas:
+ if (!mm.parameters.isEmpty()) {
+ mm.parameters.truncate(mm.parameters.length() - 1);
+ prototype[prototype.length() - 1] = ')';
+ } else {
+ prototype.append(')');
+ }
+
+ // meta method flags
+ mm.flags = AccessProtected | MethodSignal | MethodScriptable;
+
+ // add
+ methods.insert(QMetaObject::normalizedSignature(prototype), mm);
+ }
+}
+
+void QDBusMetaObjectGenerator::parseProperties()
+{
+ QDBusIntrospection::Properties::ConstIterator prop_it = data->properties.constBegin();
+ QDBusIntrospection::Properties::ConstIterator prop_end = data->properties.constEnd();
+ for ( ; prop_it != prop_end; ++prop_it) {
+ const QDBusIntrospection::Property &p = *prop_it;
+ Property mp;
+ Type type = findType(p.type.toLatin1(), p.annotations);
+ if (type.id == QVariant::Invalid)
+ continue;
+
+ QByteArray name = p.name.toLatin1();
+ mp.signature = p.type.toLatin1();
+ mp.type = type.id;
+ mp.typeName = type.name;
+
+ // build the flags:
+ mp.flags = StdCppSet | Scriptable | Stored | Designable;
+ if (p.access != QDBusIntrospection::Property::Write)
+ mp.flags |= Readable;
+ if (p.access != QDBusIntrospection::Property::Read)
+ mp.flags |= Writable;
+
+ if (mp.typeName == "QDBusVariant")
+ mp.flags |= 0xff << 24;
+ else if (mp.type < 0xff)
+ // encode the type in the flags
+ mp.flags |= mp.type << 24;
+
+ // add the property:
+ properties.insert(name, mp);
+ }
+}
+
+void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
+{
+ // this code here is mostly copied from qaxbase.cpp
+ // with a few modifications to make it cleaner
+
+ QString className = interface;
+ className.replace(QLatin1Char('.'), QLatin1String("::"));
+ if (className.isEmpty())
+ className = QLatin1String("QDBusInterface");
+
+ QVarLengthArray<int> idata;
+ idata.resize(sizeof(QDBusMetaObjectPrivate) / sizeof(int));
+
+ QDBusMetaObjectPrivate *header = reinterpret_cast<QDBusMetaObjectPrivate *>(idata.data());
+ header->revision = 1;
+ header->className = 0;
+ header->classInfoCount = 0;
+ header->classInfoData = 0;
+ header->methodCount = methods.count();
+ header->methodData = idata.size();
+ header->propertyCount = properties.count();
+ header->propertyData = header->methodData + header->methodCount * 5;
+ header->enumeratorCount = 0;
+ header->enumeratorData = 0;
+ header->propertyDBusData = header->propertyData + header->propertyCount * 3;
+ header->methodDBusData = header->propertyDBusData + header->propertyCount * intsPerProperty;
+
+ int data_size = idata.size() +
+ (header->methodCount * (5+intsPerMethod)) +
+ (header->propertyCount * (3+intsPerProperty));
+ foreach (const Method &mm, methods)
+ data_size += 2 + mm.inputTypes.count() + mm.outputTypes.count();
+ idata.resize(data_size + 1);
+
+ char null('\0');
+ QByteArray stringdata = className.toLatin1();
+ stringdata += null;
+ stringdata.reserve(8192);
+
+ int offset = header->methodData;
+ int signatureOffset = header->methodDBusData;
+ int typeidOffset = header->methodDBusData + header->methodCount * intsPerMethod;
+ idata[typeidOffset++] = 0; // eod
+
+ // add each method:
+ for (QMap<QByteArray, Method>::ConstIterator it = methods.constBegin();
+ it != methods.constEnd(); ++it) {
+ // form "prototype\0parameters\0typeName\0tag\0methodname\0inputSignature\0outputSignature"
+ const Method &mm = it.value();
+
+ idata[offset++] = stringdata.length();
+ stringdata += it.key(); // prototype
+ stringdata += null;
+ idata[offset++] = stringdata.length();
+ stringdata += mm.parameters;
+ stringdata += null;
+ idata[offset++] = stringdata.length();
+ stringdata += mm.typeName;
+ stringdata += null;
+ idata[offset++] = stringdata.length();
+ stringdata += mm.tag;
+ stringdata += null;
+ idata[offset++] = mm.flags;
+
+ idata[signatureOffset++] = stringdata.length();
+ stringdata += mm.name;
+ stringdata += null;
+ idata[signatureOffset++] = stringdata.length();
+ stringdata += mm.inputSignature;
+ stringdata += null;
+ idata[signatureOffset++] = stringdata.length();
+ stringdata += mm.outputSignature;
+ stringdata += null;
+
+ idata[signatureOffset++] = typeidOffset;
+ idata[typeidOffset++] = mm.inputTypes.count();
+ memcpy(idata.data() + typeidOffset, mm.inputTypes.data(), mm.inputTypes.count() * sizeof(int));
+ typeidOffset += mm.inputTypes.count();
+
+ idata[signatureOffset++] = typeidOffset;
+ idata[typeidOffset++] = mm.outputTypes.count();
+ memcpy(idata.data() + typeidOffset, mm.outputTypes.data(), mm.outputTypes.count() * sizeof(int));
+ typeidOffset += mm.outputTypes.count();
+ }
+
+ Q_ASSERT(offset == header->propertyData);
+ Q_ASSERT(signatureOffset == header->methodDBusData + header->methodCount * intsPerMethod);
+ Q_ASSERT(typeidOffset == idata.size());
+
+ // add each property
+ signatureOffset = header->propertyDBusData;
+ for (QMap<QByteArray, Property>::ConstIterator it = properties.constBegin();
+ it != properties.constEnd(); ++it) {
+ const Property &mp = it.value();
+
+ // form is "name\0typeName\0signature\0"
+ idata[offset++] = stringdata.length();
+ stringdata += it.key(); // name
+ stringdata += null;
+ idata[offset++] = stringdata.length();
+ stringdata += mp.typeName;
+ stringdata += null;
+ idata[offset++] = mp.flags;
+
+ idata[signatureOffset++] = stringdata.length();
+ stringdata += mp.signature;
+ stringdata += null;
+ idata[signatureOffset++] = mp.type;
+ }
+
+ Q_ASSERT(offset == header->propertyDBusData);
+ Q_ASSERT(signatureOffset == header->methodDBusData);
+
+ char *string_data = new char[stringdata.length()];
+ memcpy(string_data, stringdata, stringdata.length());
+
+ uint *uint_data = new uint[idata.size()];
+ memcpy(uint_data, idata.data(), idata.size() * sizeof(int));
+
+ // put the metaobject together
+ obj->d.data = uint_data;
+ obj->d.extradata = 0;
+ obj->d.stringdata = string_data;
+ obj->d.superdata = &QDBusAbstractInterface::staticMetaObject;
+}
+
+#if 0
+void QDBusMetaObjectGenerator::writeWithoutXml(const QString &interface)
+{
+ // no XML definition
+ QString tmp(interface);
+ tmp.replace(QLatin1Char('.'), QLatin1String("::"));
+ QByteArray name(tmp.toLatin1());
+
+ QDBusMetaObjectPrivate *header = new QDBusMetaObjectPrivate;
+ memset(header, 0, sizeof *header);
+ header->revision = 1;
+ // leave the rest with 0
+
+ char *stringdata = new char[name.length() + 1];
+ stringdata[name.length()] = '\0';
+
+ d.data = reinterpret_cast<uint*>(header);
+ d.extradata = 0;
+ d.stringdata = stringdata;
+ d.superdata = &QDBusAbstractInterface::staticMetaObject;
+ cached = false;
+}
+#endif
+
+/////////
+// class QDBusMetaObject
+
+QDBusMetaObject *QDBusMetaObject::createMetaObject(const QString &interface, const QString &xml,
+ QHash<QString, QDBusMetaObject *> &cache,
+ QDBusError &error)
+{
+ error = QDBusError();
+ QDBusIntrospection::Interfaces parsed = QDBusIntrospection::parseInterfaces(xml);
+
+ QDBusMetaObject *we = 0;
+ QDBusIntrospection::Interfaces::ConstIterator it = parsed.constBegin();
+ QDBusIntrospection::Interfaces::ConstIterator end = parsed.constEnd();
+ for ( ; it != end; ++it) {
+ // check if it's in the cache
+ bool us = it.key() == interface;
+
+ QDBusMetaObject *obj = cache.value(it.key(), 0);
+ if ( !obj && ( us || !interface.startsWith( QLatin1String("local.") ) ) ) {
+ // not in cache; create
+ obj = new QDBusMetaObject;
+ QDBusMetaObjectGenerator generator(it.key(), it.value().constData());
+ generator.write(obj);
+
+ if ( (obj->cached = !it.key().startsWith( QLatin1String("local.") )) )
+ // cache it
+ cache.insert(it.key(), obj);
+ else if (!us)
+ delete obj;
+
+ }
+
+ if (us)
+ // it's us
+ we = obj;
+ }
+
+ if (we)
+ return we;
+ // still nothing?
+
+ if (parsed.isEmpty()) {
+ // object didn't return introspection
+ we = new QDBusMetaObject;
+ QDBusMetaObjectGenerator generator(interface, 0);
+ generator.write(we);
+ we->cached = false;
+ return we;
+ } else if (interface.isEmpty()) {
+ // merge all interfaces
+ it = parsed.constBegin();
+ QDBusIntrospection::Interface merged = *it.value().constData();
+
+ for (++it; it != end; ++it) {
+ merged.annotations.unite(it.value()->annotations);
+ merged.methods.unite(it.value()->methods);
+ merged.signals_.unite(it.value()->signals_);
+ merged.properties.unite(it.value()->properties);
+ }
+
+ merged.name = QLatin1String("local.Merged");
+ merged.introspection.clear();
+
+ we = new QDBusMetaObject;
+ QDBusMetaObjectGenerator generator(merged.name, &merged);
+ generator.write(we);
+ we->cached = false;
+ return we;
+ }
+
+ // mark as an error
+ error = QDBusError(QDBusError::UnknownInterface,
+ QString::fromLatin1("Interface '%1' was not found")
+ .arg(interface));
+ return 0;
+}
+
+QDBusMetaObject::QDBusMetaObject()
+{
+}
+
+static inline const QDBusMetaObjectPrivate *priv(const uint* data)
+{
+ return reinterpret_cast<const QDBusMetaObjectPrivate *>(data);
+}
+
+const char *QDBusMetaObject::dbusNameForMethod(int id) const
+{
+ //id -= methodOffset();
+ if (id >= 0 && id < priv(d.data)->methodCount) {
+ int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
+ return d.stringdata + d.data[handle];
+ }
+ return 0;
+}
+
+const char *QDBusMetaObject::inputSignatureForMethod(int id) const
+{
+ //id -= methodOffset();
+ if (id >= 0 && id < priv(d.data)->methodCount) {
+ int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
+ return d.stringdata + d.data[handle + 1];
+ }
+ return 0;
+}
+
+const char *QDBusMetaObject::outputSignatureForMethod(int id) const
+{
+ //id -= methodOffset();
+ if (id >= 0 && id < priv(d.data)->methodCount) {
+ int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
+ return d.stringdata + d.data[handle + 2];
+ }
+ return 0;
+}
+
+const int *QDBusMetaObject::inputTypesForMethod(int id) const
+{
+ //id -= methodOffset();
+ if (id >= 0 && id < priv(d.data)->methodCount) {
+ int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
+ return reinterpret_cast<const int*>(d.data + d.data[handle + 3]);
+ }
+ return 0;
+}
+
+const int *QDBusMetaObject::outputTypesForMethod(int id) const
+{
+ //id -= methodOffset();
+ if (id >= 0 && id < priv(d.data)->methodCount) {
+ int handle = priv(d.data)->methodDBusData + id*intsPerMethod;
+ return reinterpret_cast<const int*>(d.data + d.data[handle + 4]);
+ }
+ return 0;
+}
+
+int QDBusMetaObject::propertyMetaType(int id) const
+{
+ //id -= propertyOffset();
+ if (id >= 0 && id < priv(d.data)->propertyCount) {
+ int handle = priv(d.data)->propertyDBusData + id*intsPerProperty;
+ return d.data[handle + 1];
+ }
+ return 0;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusmetaobject_p.h b/src/dbus/qdbusmetaobject_p.h
new file mode 100644
index 0000000000..d71659b484
--- /dev/null
+++ b/src/dbus/qdbusmetaobject_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+//
+
+#ifndef QDBUSMETAOBJECTPRIVATE_H
+#define QDBUSMETAOBJECTPRIVATE_H
+
+#include <QtCore/qmetaobject.h>
+#include <qdbusmacros.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDBusError;
+
+struct QDBusMetaObjectPrivate;
+struct Q_DBUS_EXPORT QDBusMetaObject: public QMetaObject
+{
+ bool cached;
+
+ static QDBusMetaObject *createMetaObject(const QString &interface, const QString &xml,
+ QHash<QString, QDBusMetaObject *> &map,
+ QDBusError &error);
+ ~QDBusMetaObject()
+ {
+ delete [] d.stringdata;
+ delete [] d.data;
+ }
+
+ // methods (slots & signals):
+ const char *dbusNameForMethod(int id) const;
+ const char *inputSignatureForMethod(int id) const;
+ const char *outputSignatureForMethod(int id) const;
+ const int *inputTypesForMethod(int id) const;
+ const int *outputTypesForMethod(int id) const;
+
+ // properties:
+ int propertyMetaType(int id) const;
+
+private:
+ QDBusMetaObject();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/dbus/qdbusmetatype.cpp b/src/dbus/qdbusmetatype.cpp
new file mode 100644
index 0000000000..9d9112cde5
--- /dev/null
+++ b/src/dbus/qdbusmetatype.cpp
@@ -0,0 +1,483 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusmetatype.h"
+
+#include <string.h>
+#include "qdbus_symbols_p.h"
+
+#include <qbytearray.h>
+#include <qglobal.h>
+#include <qreadwritelock.h>
+#include <qvector.h>
+
+#include "qdbusmessage.h"
+#include "qdbusunixfiledescriptor.h"
+#include "qdbusutil_p.h"
+#include "qdbusmetatype_p.h"
+#include "qdbusargument_p.h"
+
+#ifndef QT_NO_DBUS
+
+#ifndef DBUS_TYPE_UNIX_FD
+# define DBUS_TYPE_UNIX_FD int('h')
+# define DBUS_TYPE_UNIX_FD_AS_STRING "h"
+#endif
+
+Q_DECLARE_METATYPE(QList<bool>)
+Q_DECLARE_METATYPE(QList<short>)
+Q_DECLARE_METATYPE(QList<ushort>)
+Q_DECLARE_METATYPE(QList<int>)
+Q_DECLARE_METATYPE(QList<uint>)
+Q_DECLARE_METATYPE(QList<qlonglong>)
+Q_DECLARE_METATYPE(QList<qulonglong>)
+Q_DECLARE_METATYPE(QList<double>)
+
+QT_BEGIN_NAMESPACE
+
+class QDBusCustomTypeInfo
+{
+public:
+ QDBusCustomTypeInfo() : signature(0, '\0'), marshall(0), demarshall(0)
+ { }
+
+ // Suggestion:
+ // change 'signature' to char* and make QDBusCustomTypeInfo a Movable type
+ QByteArray signature;
+ QDBusMetaType::MarshallFunction marshall;
+ QDBusMetaType::DemarshallFunction demarshall;
+};
+
+template<typename T>
+inline static void registerHelper(T * = 0)
+{
+ void (*mf)(QDBusArgument &, const T *) = qDBusMarshallHelper<T>;
+ void (*df)(const QDBusArgument &, T *) = qDBusDemarshallHelper<T>;
+ QDBusMetaType::registerMarshallOperators(qMetaTypeId<T>(),
+ reinterpret_cast<QDBusMetaType::MarshallFunction>(mf),
+ reinterpret_cast<QDBusMetaType::DemarshallFunction>(df));
+}
+
+int QDBusMetaTypeId::message;
+int QDBusMetaTypeId::argument;
+int QDBusMetaTypeId::variant;
+int QDBusMetaTypeId::objectpath;
+int QDBusMetaTypeId::signature;
+int QDBusMetaTypeId::error;
+int QDBusMetaTypeId::unixfd;
+
+void QDBusMetaTypeId::init()
+{
+ static volatile bool initialized = false;
+
+ // reentrancy is not a problem since everything else is locked on their own
+ // set the guard variable at the end
+ if (!initialized) {
+ // register our types with QtCore
+ message = qRegisterMetaType<QDBusMessage>("QDBusMessage");
+ argument = qRegisterMetaType<QDBusArgument>("QDBusArgument");
+ variant = qRegisterMetaType<QDBusVariant>("QDBusVariant");
+ objectpath = qRegisterMetaType<QDBusObjectPath>("QDBusObjectPath");
+ signature = qRegisterMetaType<QDBusSignature>("QDBusSignature");
+ error = qRegisterMetaType<QDBusError>("QDBusError");
+ unixfd = qRegisterMetaType<QDBusUnixFileDescriptor>("QDBusUnixFileDescriptor");
+
+#ifndef QDBUS_NO_SPECIALTYPES
+ // and register QtCore's with us
+ registerHelper<QDate>();
+ registerHelper<QTime>();
+ registerHelper<QDateTime>();
+ registerHelper<QRect>();
+ registerHelper<QRectF>();
+ registerHelper<QSize>();
+ registerHelper<QSizeF>();
+ registerHelper<QPoint>();
+ registerHelper<QPointF>();
+ registerHelper<QLine>();
+ registerHelper<QLineF>();
+ registerHelper<QVariantList>();
+ registerHelper<QVariantMap>();
+ registerHelper<QVariantHash>();
+
+ qDBusRegisterMetaType<QList<bool> >();
+ qDBusRegisterMetaType<QList<short> >();
+ qDBusRegisterMetaType<QList<ushort> >();
+ qDBusRegisterMetaType<QList<int> >();
+ qDBusRegisterMetaType<QList<uint> >();
+ qDBusRegisterMetaType<QList<qlonglong> >();
+ qDBusRegisterMetaType<QList<qulonglong> >();
+ qDBusRegisterMetaType<QList<double> >();
+ qDBusRegisterMetaType<QList<QDBusObjectPath> >();
+ qDBusRegisterMetaType<QList<QDBusSignature> >();
+ qDBusRegisterMetaType<QList<QDBusUnixFileDescriptor> >();
+#endif
+
+ initialized = true;
+ }
+}
+
+Q_GLOBAL_STATIC(QVector<QDBusCustomTypeInfo>, customTypes)
+Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock)
+
+/*!
+ \class QDBusMetaType
+ \brief Meta-type registration system for the QtDBus module.
+ \internal
+
+ The QDBusMetaType class allows you to register class types for
+ marshalling and demarshalling over D-Bus. D-Bus supports a very
+ limited set of primitive types, but allows one to extend the type
+ system by creating compound types, such as arrays (lists) and
+ structs. In order to use them with QtDBus, those types must be
+ registered.
+
+ See \l {qdbustypesystem.html}{QtDBus type system} for more
+ information on the type system and how to register additional
+ types.
+
+ \sa {qdbustypesystem.html}{QtDBus type system},
+ qDBusRegisterMetaType(), QMetaType, QVariant, QDBusArgument
+*/
+
+/*!
+ \fn int qDBusRegisterMetaType()
+ \relates QDBusArgument
+ \threadsafe
+ \since 4.2
+
+ Registers \c{T} with the
+ \l {qdbustypesystem.html}{QtDBus type system} and the Qt \l
+ {QMetaType}{meta-type system}, if it's not already registered.
+
+ To register a type, it must be declared as a meta-type with the
+ Q_DECLARE_METATYPE() macro, and then registered as in the
+ following example:
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbusmetatype.cpp 0
+
+ If \c{T} isn't a type derived from one of
+ Qt's \l{container classes}, the \c{operator<<} and
+ \c{operator>>} streaming operators between \c{T} and QDBusArgument
+ must be already declared. See the \l {qdbustypesystem.html}{QtDBus
+ type system} page for more information on how to declare such
+ types.
+
+ This function returns the Qt meta type id for the type (the same
+ value that is returned from qRegisterMetaType()).
+
+ \sa {qdbustypesystem.html}{QtDBus type system}, qRegisterMetaType(), QMetaType
+*/
+
+/*!
+ \typedef QDBusMetaType::MarshallFunction
+ \internal
+*/
+
+/*!
+ \typedef QDBusMetaType::DemarshallFunction
+ \internal
+*/
+
+/*!
+ \internal
+ Registers the marshalling and demarshalling functions for meta
+ type \a id.
+*/
+void QDBusMetaType::registerMarshallOperators(int id, MarshallFunction mf,
+ DemarshallFunction df)
+{
+ QByteArray var;
+ QVector<QDBusCustomTypeInfo> *ct = customTypes();
+ if (id < 0 || !mf || !df || !ct)
+ return; // error!
+
+ QWriteLocker locker(customTypesLock());
+ if (id >= ct->size())
+ ct->resize(id + 1);
+ QDBusCustomTypeInfo &info = (*ct)[id];
+ info.marshall = mf;
+ info.demarshall = df;
+}
+
+/*!
+ \internal
+ Executes the marshalling of type \a id (whose data is contained in
+ \a data) to the D-Bus marshalling argument \a arg. Returns true if
+ the marshalling succeeded, or false if an error occurred.
+*/
+bool QDBusMetaType::marshall(QDBusArgument &arg, int id, const void *data)
+{
+ QDBusMetaTypeId::init();
+
+ MarshallFunction mf;
+ {
+ QReadLocker locker(customTypesLock());
+ QVector<QDBusCustomTypeInfo> *ct = customTypes();
+ if (id >= ct->size())
+ return false; // non-existent
+
+ const QDBusCustomTypeInfo &info = (*ct).at(id);
+ if (!info.marshall) {
+ mf = 0; // make gcc happy
+ return false;
+ } else
+ mf = info.marshall;
+ }
+
+ mf(arg, data);
+ return true;
+}
+
+/*!
+ \internal
+ Executes the demarshalling of type \a id (whose data will be placed in
+ \a data) from the D-Bus marshalling argument \a arg. Returns true if
+ the demarshalling succeeded, or false if an error occurred.
+*/
+bool QDBusMetaType::demarshall(const QDBusArgument &arg, int id, void *data)
+{
+ QDBusMetaTypeId::init();
+
+ DemarshallFunction df;
+ {
+ QReadLocker locker(customTypesLock());
+ QVector<QDBusCustomTypeInfo> *ct = customTypes();
+ if (id >= ct->size())
+ return false; // non-existent
+
+ const QDBusCustomTypeInfo &info = (*ct).at(id);
+ if (!info.demarshall) {
+ df = 0; // make gcc happy
+ return false;
+ } else
+ df = info.demarshall;
+ }
+
+ QDBusArgument copy = arg;
+ df(copy, data);
+ return true;
+}
+
+/*!
+ \fn QDBusMetaType::signatureToType(const char *signature)
+ \internal
+
+ Returns the Qt meta type id for the given D-Bus signature for exactly one full type, given
+ by \a signature.
+
+ Note: this function only handles the basic D-Bus types.
+
+ \sa QDBusUtil::isValidSingleSignature(), typeToSignature(),
+ QVariant::type(), QVariant::userType()
+*/
+int QDBusMetaType::signatureToType(const char *signature)
+{
+ if (!signature)
+ return QVariant::Invalid;
+
+ QDBusMetaTypeId::init();
+ switch (signature[0])
+ {
+ case DBUS_TYPE_BOOLEAN:
+ return QVariant::Bool;
+
+ case DBUS_TYPE_BYTE:
+ return QMetaType::UChar;
+
+ case DBUS_TYPE_INT16:
+ return QMetaType::Short;
+
+ case DBUS_TYPE_UINT16:
+ return QMetaType::UShort;
+
+ case DBUS_TYPE_INT32:
+ return QVariant::Int;
+
+ case DBUS_TYPE_UINT32:
+ return QVariant::UInt;
+
+ case DBUS_TYPE_INT64:
+ return QVariant::LongLong;
+
+ case DBUS_TYPE_UINT64:
+ return QVariant::ULongLong;
+
+ case DBUS_TYPE_DOUBLE:
+ return QVariant::Double;
+
+ case DBUS_TYPE_STRING:
+ return QVariant::String;
+
+ case DBUS_TYPE_OBJECT_PATH:
+ return QDBusMetaTypeId::objectpath;
+
+ case DBUS_TYPE_SIGNATURE:
+ return QDBusMetaTypeId::signature;
+
+ case DBUS_TYPE_UNIX_FD:
+ return QDBusMetaTypeId::unixfd;
+
+ case DBUS_TYPE_VARIANT:
+ return QDBusMetaTypeId::variant;
+
+ case DBUS_TYPE_ARRAY: // special case
+ switch (signature[1]) {
+ case DBUS_TYPE_BYTE:
+ return QVariant::ByteArray;
+
+ case DBUS_TYPE_STRING:
+ return QVariant::StringList;
+
+ case DBUS_TYPE_VARIANT:
+ return QVariant::List;
+
+ case DBUS_TYPE_OBJECT_PATH:
+ return qMetaTypeId<QList<QDBusObjectPath> >();
+
+ case DBUS_TYPE_SIGNATURE:
+ return qMetaTypeId<QList<QDBusSignature> >();
+
+ }
+ // fall through
+ default:
+ return QVariant::Invalid;
+ }
+}
+
+/*!
+ \fn QDBusMetaType::typeToSignature(int type)
+ \internal
+
+ Returns the D-Bus signature equivalent to the supplied meta type id \a type.
+
+ More types can be registered with the qDBusRegisterMetaType() function.
+
+ \sa QDBusUtil::isValidSingleSignature(), signatureToType(),
+ QVariant::type(), QVariant::userType()
+*/
+const char *QDBusMetaType::typeToSignature(int type)
+{
+ // check if it's a static type
+ switch (type)
+ {
+ case QMetaType::UChar:
+ return DBUS_TYPE_BYTE_AS_STRING;
+
+ case QVariant::Bool:
+ return DBUS_TYPE_BOOLEAN_AS_STRING;
+
+ case QMetaType::Short:
+ return DBUS_TYPE_INT16_AS_STRING;
+
+ case QMetaType::UShort:
+ return DBUS_TYPE_UINT16_AS_STRING;
+
+ case QVariant::Int:
+ return DBUS_TYPE_INT32_AS_STRING;
+
+ case QVariant::UInt:
+ return DBUS_TYPE_UINT32_AS_STRING;
+
+ case QVariant::LongLong:
+ return DBUS_TYPE_INT64_AS_STRING;
+
+ case QVariant::ULongLong:
+ return DBUS_TYPE_UINT64_AS_STRING;
+
+ case QVariant::Double:
+ return DBUS_TYPE_DOUBLE_AS_STRING;
+
+ case QVariant::String:
+ return DBUS_TYPE_STRING_AS_STRING;
+
+ case QVariant::StringList:
+ return DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING; // as
+
+ case QVariant::ByteArray:
+ return DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_BYTE_AS_STRING; // ay
+ }
+
+ QDBusMetaTypeId::init();
+ if (type == QDBusMetaTypeId::variant)
+ return DBUS_TYPE_VARIANT_AS_STRING;
+ else if (type == QDBusMetaTypeId::objectpath)
+ return DBUS_TYPE_OBJECT_PATH_AS_STRING;
+ else if (type == QDBusMetaTypeId::signature)
+ return DBUS_TYPE_SIGNATURE_AS_STRING;
+ else if (type == QDBusMetaTypeId::unixfd)
+ return DBUS_TYPE_UNIX_FD_AS_STRING;
+
+ // try the database
+ QVector<QDBusCustomTypeInfo> *ct = customTypes();
+ {
+ QReadLocker locker(customTypesLock());
+ if (type >= ct->size())
+ return 0; // type not registered with us
+
+ const QDBusCustomTypeInfo &info = (*ct).at(type);
+
+ if (!info.signature.isNull())
+ return info.signature;
+
+ if (!info.marshall)
+ return 0; // type not registered with us
+ }
+
+ // call to user code to construct the signature type
+ QDBusCustomTypeInfo *info;
+ {
+ // createSignature will never return a null QByteArray
+ // if there was an error, it'll return ""
+ QByteArray signature = QDBusArgumentPrivate::createSignature(type);
+
+ // re-acquire lock
+ QWriteLocker locker(customTypesLock());
+ info = &(*ct)[type];
+ info->signature = signature;
+ }
+ return info->signature;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusmetatype.h b/src/dbus/qdbusmetatype.h
new file mode 100644
index 0000000000..b0cba9bbaa
--- /dev/null
+++ b/src/dbus/qdbusmetatype.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSMETATYPE_H
+#define QDBUSMETATYPE_H
+
+#include "QtCore/qmetatype.h"
+#include <QtDBus/qdbusargument.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(DBus)
+
+class Q_DBUS_EXPORT QDBusMetaType
+{
+public:
+ typedef void (*MarshallFunction)(QDBusArgument &, const void *);
+ typedef void (*DemarshallFunction)(const QDBusArgument &, void *);
+
+ static void registerMarshallOperators(int typeId, MarshallFunction, DemarshallFunction);
+ static bool marshall(QDBusArgument &, int id, const void *data);
+ static bool demarshall(const QDBusArgument &, int id, void *data);
+
+ static int signatureToType(const char *signature);
+ static const char *typeToSignature(int type);
+};
+
+template<typename T>
+void qDBusMarshallHelper(QDBusArgument &arg, const T *t)
+{ arg << *t; }
+
+template<typename T>
+void qDBusDemarshallHelper(const QDBusArgument &arg, T *t)
+{ arg >> *t; }
+
+template<typename T>
+int qDBusRegisterMetaType(
+#ifndef qdoc
+ T * /* dummy */ = 0
+#endif
+)
+{
+ void (*mf)(QDBusArgument &, const T *) = qDBusMarshallHelper<T>;
+ void (*df)(const QDBusArgument &, T *) = qDBusDemarshallHelper<T>;
+
+ int id = qRegisterMetaType<T>(); // make sure it's registered
+ QDBusMetaType::registerMarshallOperators(id,
+ reinterpret_cast<QDBusMetaType::MarshallFunction>(mf),
+ reinterpret_cast<QDBusMetaType::DemarshallFunction>(df));
+ return id;
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusmetatype_p.h b/src/dbus/qdbusmetatype_p.h
new file mode 100644
index 0000000000..b931c75ab1
--- /dev/null
+++ b/src/dbus/qdbusmetatype_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSMETATYPE_P_H
+#define QDBUSMETATYPE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qdbusmetatype.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QDBusMetaTypeId
+{
+ static int message; // QDBusMessage
+ static int argument; // QDBusArgument
+ static int variant; // QDBusVariant
+ static int objectpath; // QDBusObjectPath
+ static int signature; // QDBusSignature
+ static int error; // QDBusError
+ static int unixfd; // QDBusUnixFileDescriptor
+
+ static void init();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/dbus/qdbusmisc.cpp b/src/dbus/qdbusmisc.cpp
new file mode 100644
index 0000000000..58c28cf287
--- /dev/null
+++ b/src/dbus/qdbusmisc.cpp
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <string.h>
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qmetaobject.h>
+
+#include "qdbusutil_p.h"
+#include "qdbusconnection_p.h"
+#include "qdbusmetatype_p.h"
+#include "qdbusabstractadaptor_p.h" // for QCLASSINFO_DBUS_*
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+bool qDBusCheckAsyncTag(const char *tag)
+{
+ static const char noReplyTag[] = "Q_NOREPLY";
+ if (!tag || !*tag)
+ return false;
+
+ const char *p = strstr(tag, noReplyTag);
+ if (p != NULL &&
+ (p == tag || *(p-1) == ' ') &&
+ (p[sizeof noReplyTag - 1] == '\0' || p[sizeof noReplyTag - 1] == ' '))
+ return true;
+
+ return false;
+}
+
+int qDBusNameToTypeId(const char *name)
+{
+ int id = static_cast<int>( QVariant::nameToType(name) );
+ if (id == QVariant::UserType)
+ id = QMetaType::type(name);
+ return id;
+}
+
+QString qDBusInterfaceFromMetaObject(const QMetaObject *mo)
+{
+ QString interface;
+
+ int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
+ if (idx >= mo->classInfoOffset()) {
+ interface = QLatin1String(mo->classInfo(idx).value());
+ } else {
+ interface = QLatin1String(mo->className());
+ interface.replace(QLatin1String("::"), QLatin1String("."));
+
+ if (interface.startsWith(QLatin1String("QDBus"))) {
+ interface.prepend(QLatin1String("com.trolltech.QtDBus."));
+ } else if (interface.startsWith(QLatin1Char('Q')) &&
+ interface.length() >= 2 && interface.at(1).isUpper()) {
+ // assume it's Qt
+ interface.prepend(QLatin1String("com.trolltech.Qt."));
+ } else if (!QCoreApplication::instance()||
+ QCoreApplication::instance()->applicationName().isEmpty()) {
+ interface.prepend(QLatin1String("local."));
+ } else {
+ interface.prepend(QLatin1Char('.')).prepend(QCoreApplication::instance()->applicationName());
+ QStringList domainName =
+ QCoreApplication::instance()->organizationDomain().split(QLatin1Char('.'),
+ QString::SkipEmptyParts);
+ if (domainName.isEmpty())
+ interface.prepend(QLatin1String("local."));
+ else
+ for (int i = 0; i < domainName.count(); ++i)
+ interface.prepend(QLatin1Char('.')).prepend(domainName.at(i));
+ }
+ }
+
+ return interface;
+}
+
+bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name)
+{
+ const QMetaObject *mo = obj->metaObject();
+ for ( ; mo != &QObject::staticMetaObject; mo = mo->superClass())
+ if (interface_name == qDBusInterfaceFromMetaObject(mo))
+ return true;
+ return false;
+}
+
+// calculates the metatypes for the method
+// the slot must have the parameters in the following form:
+// - zero or more value or const-ref parameters of any kind
+// - zero or one const ref of QDBusMessage
+// - zero or more non-const ref parameters
+// No parameter may be a template.
+// this function returns -1 if the parameters don't match the above form
+// this function returns the number of *input* parameters, including the QDBusMessage one if any
+// this function does not check the return type, so metaTypes[0] is always 0 and always present
+// metaTypes.count() >= retval + 1 in all cases
+//
+// sig must be the normalised signature for the method
+int qDBusParametersForMethod(const QMetaMethod &mm, QList<int>& metaTypes)
+{
+ QDBusMetaTypeId::init();
+
+ QList<QByteArray> parameterTypes = mm.parameterTypes();
+ metaTypes.clear();
+
+ metaTypes.append(0); // return type
+ int inputCount = 0;
+ bool seenMessage = false;
+ QList<QByteArray>::ConstIterator it = parameterTypes.constBegin();
+ QList<QByteArray>::ConstIterator end = parameterTypes.constEnd();
+ for ( ; it != end; ++it) {
+ const QByteArray &type = *it;
+ if (type.endsWith('*')) {
+ //qWarning("Could not parse the method '%s'", mm.signature());
+ // pointer?
+ return -1;
+ }
+
+ if (type.endsWith('&')) {
+ QByteArray basictype = type;
+ basictype.truncate(type.length() - 1);
+
+ int id = qDBusNameToTypeId(basictype);
+ if (id == 0) {
+ //qWarning("Could not parse the method '%s'", mm.signature());
+ // invalid type in method parameter list
+ return -1;
+ } else if (QDBusMetaType::typeToSignature(id) == 0)
+ return -1;
+
+ metaTypes.append( id );
+ seenMessage = true; // it cannot appear anymore anyways
+ continue;
+ }
+
+ if (seenMessage) { // && !type.endsWith('&')
+ //qWarning("Could not parse the method '%s'", mm.signature());
+ // non-output parameters after message or after output params
+ return -1; // not allowed
+ }
+
+ int id = qDBusNameToTypeId(type);
+ if (id == 0) {
+ //qWarning("Could not parse the method '%s'", mm.signature());
+ // invalid type in method parameter list
+ return -1;
+ }
+
+ if (id == QDBusMetaTypeId::message)
+ seenMessage = true;
+ else if (QDBusMetaType::typeToSignature(id) == 0)
+ return -1;
+
+ metaTypes.append(id);
+ ++inputCount;
+ }
+
+ return inputCount;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbuspendingcall.cpp b/src/dbus/qdbuspendingcall.cpp
new file mode 100644
index 0000000000..3ebd149ed3
--- /dev/null
+++ b/src/dbus/qdbuspendingcall.cpp
@@ -0,0 +1,539 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbuspendingcall.h"
+#include "qdbuspendingcall_p.h"
+
+#include "qdbusconnection_p.h"
+#include "qdbusmetatype_p.h"
+#include "qcoreapplication.h"
+#include "qcoreevent.h"
+#include <private/qobject_p.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QDBusPendingCall
+ \inmodule QtDBus
+ \since 4.5
+
+ \brief The QDBusPendingCall class refers to one pending asynchronous call
+
+ A QDBusPendingCall object is a reference to a method call that was
+ sent over D-Bus without waiting for a reply. QDBusPendingCall is an
+ opaque type, meant to be used as a handle for a pending reply.
+
+ In most programs, the QDBusPendingCall class will not be used
+ directly. It can be safely replaced with the template-based
+ QDBusPendingReply, in order to access the contents of the reply or
+ wait for it to be complete.
+
+ The QDBusPendingCallWatcher class allows one to connect to a signal
+ that will indicate when the reply has arrived or if the call has
+ timed out. It also provides the
+ QDBusPendingCallWatcher::waitForFinished() method which will suspend
+ the execution of the program until the reply has arrived.
+
+ \note If you create a copy of a QDBusPendingCall object, all
+ information will be shared among the many copies. Therefore,
+ QDBusPendingCall is an explicitly-shared object and does not
+ provide a method of detaching the copies (since they refer
+ to the same pending call)
+
+ \sa QDBusPendingReply, QDBusPendingCallWatcher,
+ QDBusAbstractInterface::asyncCall()
+*/
+
+/*!
+ \class QDBusPendingCallWatcher
+ \inmodule QtDBus
+ \since 4.5
+
+ \brief The QDBusPendingCallWatcher class provides a convenient way for
+ waiting for asynchronous replies
+
+ The QDBusPendingCallWatcher provides the finished() signal that will be
+ emitted when a reply arrives.
+
+ It is usually used like the following example:
+
+ \snippet doc/src/snippets/code/src.qdbus.qdbuspendingcall.cpp 0
+
+ Note that it is not necessary to keep the original QDBusPendingCall
+ object around since QDBusPendingCallWatcher inherits from that class
+ too.
+
+ The slot connected to by the above code could be something similar
+ to the following:
+
+ \snippet doc/src/snippets/code/src.qdbus.qdbuspendingcall.cpp 1
+
+ Note the use of QDBusPendingReply to validate the argument types in
+ the reply. If the reply did not contain exactly two arguments
+ (one string and one QByteArray), QDBusPendingReply::isError() will
+ return true.
+
+ \sa QDBusPendingReply, QDBusAbstractInterface::asyncCall()
+*/
+
+/*!
+ \fn void QDBusPendingCallWatcher::finished(QDBusPendingCallWatcher *self)
+
+ This signal is emitted when the pending call has finished and its
+ reply is available. The \a self parameter is a pointer to the
+ object itself, passed for convenience so that the slot can access
+ the properties and determine the contents of the reply.
+*/
+
+void QDBusPendingCallWatcherHelper::add(QDBusPendingCallWatcher *watcher)
+{
+ connect(this, SIGNAL(finished()), watcher, SLOT(_q_finished()), Qt::QueuedConnection);
+}
+
+QDBusPendingCallPrivate::~QDBusPendingCallPrivate()
+{
+ if (pending) {
+ q_dbus_pending_call_cancel(pending);
+ q_dbus_pending_call_unref(pending);
+ }
+ delete watcherHelper;
+}
+
+bool QDBusPendingCallPrivate::setReplyCallback(QObject *target, const char *member)
+{
+ receiver = target;
+ metaTypes.clear();
+ methodIdx = -1;
+ if (!target)
+ return true;; // unsetting
+
+ if (!member || !*member) {
+ // would not be able to deliver a reply
+ qWarning("QDBusPendingCall::setReplyCallback: error: cannot deliver a reply to %s::%s (%s)",
+ target ? target->metaObject()->className() : "(null)",
+ member ? member + 1 : "(null)",
+ target ? qPrintable(target->objectName()) : "no name");
+ return false;
+ }
+
+ methodIdx = QDBusConnectionPrivate::findSlot(target, member + 1, metaTypes);
+ if (methodIdx == -1) {
+ QByteArray normalizedName = QMetaObject::normalizedSignature(member + 1);
+ methodIdx = QDBusConnectionPrivate::findSlot(target, normalizedName, metaTypes);
+ }
+ if (methodIdx == -1) {
+ // would not be able to deliver a reply
+ qWarning("QDBusPendingCall::setReplyCallback: error: cannot deliver a reply to %s::%s (%s)",
+ target->metaObject()->className(),
+ member + 1, qPrintable(target->objectName()));
+ return false;
+ }
+
+ // success
+ // construct the expected signature
+ int count = metaTypes.count() - 1;
+ if (count == 1 && metaTypes.at(1) == QDBusMetaTypeId::message) {
+ // wildcard slot, can receive anything, so don't set the signature
+ return true;
+ }
+
+ if (metaTypes.at(count) == QDBusMetaTypeId::message)
+ --count;
+
+ // QList<int> is actually a vector
+ // kids, don't try this at home
+ setMetaTypes(count, count ? &metaTypes.at(1) : 0);
+ return true;
+}
+
+void QDBusPendingCallPrivate::setMetaTypes(int count, const int *types)
+{
+ expectedReplyCount = count;
+ if (count == 0) {
+ expectedReplySignature = QLatin1String(""); // not null
+ return;
+ }
+
+ QByteArray sig;
+ sig.reserve(count + count / 2);
+ for (int i = 0; i < count; ++i) {
+ const char *typeSig = QDBusMetaType::typeToSignature(types[i]);
+ if (!typeSig) {
+ qFatal("QDBusPendingReply: type %s is not registered with QtDBus",
+ QMetaType::typeName(types[i]));
+ }
+ sig += typeSig;
+ }
+
+ expectedReplySignature = QString::fromLatin1(sig);
+}
+
+void QDBusPendingCallPrivate::checkReceivedSignature()
+{
+ // MUST BE CALLED WITH A LOCKED MUTEX!
+
+ if (replyMessage.type() == QDBusMessage::InvalidMessage)
+ return; // not yet finished - no message to
+ // validate against
+ if (replyMessage.type() == QDBusMessage::ErrorMessage)
+ return; // we don't have to check the signature of an error reply
+
+ if (expectedReplySignature.isNull())
+ return; // no signature to validate against
+
+ // can't use startsWith here because a null string doesn't start or end with an empty string
+ if (!replyMessage.signature().indexOf(expectedReplySignature) == 0) {
+ QString errorMsg = QLatin1String("Unexpected reply signature: got \"%1\", "
+ "expected \"%2\"");
+ replyMessage = QDBusMessage::createError(
+ QDBusError::InvalidSignature,
+ errorMsg.arg(replyMessage.signature(), expectedReplySignature));
+
+ }
+}
+
+void QDBusPendingCallPrivate::waitForFinished()
+{
+ QMutexLocker locker(&mutex);
+
+ if (replyMessage.type() != QDBusMessage::InvalidMessage)
+ return; // already finished
+
+ connection->waitForFinished(this);
+}
+
+/*!
+ Creates a copy of the \a other pending asynchronous call. Note
+ that both objects will refer to the same pending call.
+*/
+QDBusPendingCall::QDBusPendingCall(const QDBusPendingCall &other)
+ : d(other.d)
+{
+}
+
+/*!
+ \internal
+*/
+QDBusPendingCall::QDBusPendingCall(QDBusPendingCallPrivate *dd)
+ : d(dd)
+{
+}
+
+/*!
+ Destroys this copy of the QDBusPendingCall object. If this copy is
+ also the last copy of a pending asynchronous call, the call will
+ be canceled and no further notifications will be received. There
+ will be no way of accessing the reply's contents when it arrives.
+*/
+QDBusPendingCall::~QDBusPendingCall()
+{
+ // d deleted by QExplicitlySharedDataPointer
+}
+
+
+/*!
+ Creates a copy of the \a other pending asynchronous call and drops
+ the reference to the previously-referenced call. Note that both
+ objects will refer to the same pending call after this function.
+
+ If this object contained the last reference of a pending
+ asynchronous call, the call will be canceled and no further
+ notifications will be received. There will be no way of accessing
+ the reply's contents when it arrives.
+*/
+QDBusPendingCall &QDBusPendingCall::operator=(const QDBusPendingCall &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ \fn bool QDBusPendingCallWatcher::isFinished() const
+
+ Returns true if the pending call has finished processing and the
+ reply has been received.
+
+ Note that this function only changes state if you call
+ waitForFinished() or if an external D-Bus event happens, which in
+ general only happens if you return to the event loop execution.
+
+ \sa QDBusPendingReply::isFinished()
+*/
+/*!
+ \fn bool QDBusPendingReply::isFinished() const
+
+ Returns true if the pending call has finished processing and the
+ reply has been received. If this function returns true, the
+ isError(), error() and reply() methods should return valid
+ information.
+
+ Note that this function only changes state if you call
+ waitForFinished() or if an external D-Bus event happens, which in
+ general only happens if you return to the event loop execution.
+
+ \sa QDBusPendingCallWatcher::isFinished()
+*/
+
+bool QDBusPendingCall::isFinished() const
+{
+ if (!d)
+ return true; // considered finished
+
+ QMutexLocker locker(&d->mutex);
+ return d->replyMessage.type() != QDBusMessage::InvalidMessage;
+}
+
+void QDBusPendingCall::waitForFinished()
+{
+ if (d) d->waitForFinished();
+}
+
+/*!
+ \fn bool QDBusPendingReply::isValid() const
+
+ Returns true if the reply contains a normal reply message, false
+ if it contains anything else.
+
+ If the pending call has not finished processing, this function
+ return false.
+*/
+bool QDBusPendingCall::isValid() const
+{
+ if (!d)
+ return false;
+ QMutexLocker locker(&d->mutex);
+ return d->replyMessage.type() == QDBusMessage::ReplyMessage;
+}
+
+/*!
+ \fn bool QDBusPendingReply::isError() const
+
+ Returns true if the reply contains an error message, false if it
+ contains a normal method reply.
+
+ If the pending call has not finished processing, this function
+ also returns true.
+*/
+bool QDBusPendingCall::isError() const
+{
+ if (!d)
+ return true; // considered finished and an error
+ QMutexLocker locker(&d->mutex);
+ return d->replyMessage.type() == QDBusMessage::ErrorMessage;
+}
+
+/*!
+ \fn QDBusError QDBusPendingReply::error() const
+
+ Retrieves the error content of the reply message, if it has
+ finished processing. If the reply message has not finished
+ processing or if it contains a normal reply message (non-error),
+ this function returns an invalid QDBusError.
+*/
+QDBusError QDBusPendingCall::error() const
+{
+ if (d) {
+ QMutexLocker locker(&d->mutex);
+ return d->replyMessage;
+ }
+
+ // not connected, return an error
+ QDBusError err = QDBusError(QDBusError::Disconnected,
+ QLatin1String("Not connected to D-Bus server"));
+ return err;
+}
+
+/*!
+ \fn QDBusMessage QDBusPendingReply::reply() const
+
+ Retrieves the reply message received for the asynchronous call
+ that was sent, if it has finished processing. If the pending call
+ is not finished, this function returns a QDBusMessage of type
+ QDBusMessage::InvalidMessage.
+
+ After it has finished processing, the message type will either be
+ an error message or a normal method reply message.
+*/
+QDBusMessage QDBusPendingCall::reply() const
+{
+ if (!d)
+ return QDBusMessage::createError(error());
+ QMutexLocker locker(&d->mutex);
+ return d->replyMessage;
+}
+
+#if 0
+/*!
+ Sets the slot \a member in object \a target to be called when the
+ reply arrives. The slot's parameter list must match the reply
+ message's arguments for it to be called.
+
+ It may, optionally, contain a QDBusMessage final parameter. If it
+ is present, the parameter will contain the reply message object.
+
+ The callback will not be called if the reply is an error message.
+
+ This function returns true if it could set the callback, false
+ otherwise. It is not a guarantee that the callback will be
+ called.
+
+ \warning QDBusPendingCall only supports one callback per pending
+ asynchronous call, even if multiple QDBusPendingCall
+ objects are referencing the same pending call.
+*/
+bool QDBusPendingCall::setReplyCallback(QObject *target, const char *member)
+{
+ if (!d)
+ return false;
+
+ return d->setReplyCallback(target, member);
+}
+#endif
+
+/*!
+ \since 4.6
+ Creates a QDBusPendingCall object based on the error condition
+ \a error. The resulting pending call object will be in the
+ "finished" state and QDBusPendingReply::isError() will return true.
+
+ \sa fromCompletedCall()
+*/
+QDBusPendingCall QDBusPendingCall::fromError(const QDBusError &error)
+{
+ return fromCompletedCall(QDBusMessage::createError(error));
+}
+
+/*!
+ \since 4.6
+ Creates a QDBusPendingCall object based on the message \a msg.
+ The message must be of type QDBusMessage::ErrorMessage or
+ QDBusMessage::ReplyMessage (that is, a message that is typical
+ of a completed call).
+
+ This function is useful for code that requires simulating a pending
+ call, but that has already finished.
+
+ \sa fromError()
+*/
+QDBusPendingCall QDBusPendingCall::fromCompletedCall(const QDBusMessage &msg)
+{
+ QDBusPendingCallPrivate *d = 0;
+ if (msg.type() == QDBusMessage::ErrorMessage ||
+ msg.type() == QDBusMessage::ReplyMessage) {
+ d = new QDBusPendingCallPrivate(QDBusMessage(), 0);
+ d->replyMessage = msg;
+ }
+
+ return QDBusPendingCall(d);
+}
+
+
+class QDBusPendingCallWatcherPrivate: public QObjectPrivate
+{
+public:
+ void _q_finished();
+
+ Q_DECLARE_PUBLIC(QDBusPendingCallWatcher)
+};
+
+inline void QDBusPendingCallWatcherPrivate::_q_finished()
+{
+ Q_Q(QDBusPendingCallWatcher);
+ emit q->finished(q);
+}
+
+/*!
+ Creates a QDBusPendingCallWatcher object to watch for replies on the
+ asynchronous pending call \a call and sets this object's parent
+ to \a parent.
+*/
+QDBusPendingCallWatcher::QDBusPendingCallWatcher(const QDBusPendingCall &call, QObject *parent)
+ : QObject(*new QDBusPendingCallWatcherPrivate, parent), QDBusPendingCall(call)
+{
+ if (d) { // QDBusPendingCall::d
+ QMutexLocker locker(&d->mutex);
+ if (!d->watcherHelper) {
+ d->watcherHelper = new QDBusPendingCallWatcherHelper;
+ if (d->replyMessage.type() != QDBusMessage::InvalidMessage) {
+ // cause a signal emission anyways
+ QMetaObject::invokeMethod(d->watcherHelper, "finished", Qt::QueuedConnection);
+ }
+ }
+ d->watcherHelper->add(this);
+ }
+}
+
+/*!
+ Destroys this object. If this QDBusPendingCallWatcher object was the
+ last reference to the unfinished pending call, the call will be
+ canceled.
+*/
+QDBusPendingCallWatcher::~QDBusPendingCallWatcher()
+{
+}
+
+/*!
+ \fn void QDBusPendingCallWatcher::waitForFinished()
+
+ Suspends the execution of the calling thread until the reply is
+ received and processed. After this function returns, isFinished()
+ should return true, indicating the reply's contents are ready to
+ be processed.
+
+ \sa QDBusPendingReply::waitForFinished()
+*/
+void QDBusPendingCallWatcher::waitForFinished()
+{
+ if (d) {
+ d->waitForFinished();
+
+ // our signals were queued, so deliver them
+ QCoreApplication::sendPostedEvents(d->watcherHelper, QEvent::MetaCall);
+ QCoreApplication::sendPostedEvents(this, QEvent::MetaCall);
+ }
+}
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
+
+#include "moc_qdbuspendingcall.cpp"
diff --git a/src/dbus/qdbuspendingcall.h b/src/dbus/qdbuspendingcall.h
new file mode 100644
index 0000000000..d1e783f459
--- /dev/null
+++ b/src/dbus/qdbuspendingcall.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSPENDINGCALL_H
+#define QDBUSPENDINGCALL_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qshareddata.h>
+
+#include <QtDBus/qdbusmacros.h>
+#include <QtDBus/qdbusmessage.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(DBus)
+
+class QDBusConnection;
+class QDBusError;
+class QDBusPendingCallWatcher;
+
+class QDBusPendingCallPrivate;
+class Q_DBUS_EXPORT QDBusPendingCall
+{
+public:
+ QDBusPendingCall(const QDBusPendingCall &other);
+ ~QDBusPendingCall();
+ QDBusPendingCall &operator=(const QDBusPendingCall &other);
+
+#ifndef Q_QDOC
+ // pretend that they aren't here
+ bool isFinished() const;
+ void waitForFinished();
+
+ bool isError() const;
+ bool isValid() const;
+ QDBusError error() const;
+ QDBusMessage reply() const;
+#endif
+
+ static QDBusPendingCall fromError(const QDBusError &error);
+ static QDBusPendingCall fromCompletedCall(const QDBusMessage &message);
+
+protected:
+ QExplicitlySharedDataPointer<QDBusPendingCallPrivate> d;
+ friend class QDBusPendingCallPrivate;
+ friend class QDBusPendingCallWatcher;
+ friend class QDBusConnection;
+
+ QDBusPendingCall(QDBusPendingCallPrivate *dd);
+
+private:
+ QDBusPendingCall(); // not defined
+};
+
+class QDBusPendingCallWatcherPrivate;
+class Q_DBUS_EXPORT QDBusPendingCallWatcher: public QObject, public QDBusPendingCall
+{
+ Q_OBJECT
+public:
+ QDBusPendingCallWatcher(const QDBusPendingCall &call, QObject *parent = 0);
+ ~QDBusPendingCallWatcher();
+
+#ifdef Q_QDOC
+ // trick qdoc into thinking this method is here
+ bool isFinished() const;
+#endif
+ void waitForFinished(); // non-virtual override
+
+Q_SIGNALS:
+ void finished(QDBusPendingCallWatcher *self);
+
+private:
+ Q_DECLARE_PRIVATE(QDBusPendingCallWatcher)
+ Q_PRIVATE_SLOT(d_func(), void _q_finished())
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbuspendingcall_p.h b/src/dbus/qdbuspendingcall_p.h
new file mode 100644
index 0000000000..b61f2578ba
--- /dev/null
+++ b/src/dbus/qdbuspendingcall_p.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// 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.
+//
+//
+
+#ifndef QDBUSPENDINGCALL_P_H
+#define QDBUSPENDINGCALL_P_H
+
+#include <qshareddata.h>
+#include <qpointer.h>
+#include <qlist.h>
+#include <qmutex.h>
+#include <qwaitcondition.h>
+
+#include "qdbusmessage.h"
+#include "qdbus_symbols_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+class QDBusPendingCall;
+class QDBusPendingCallWatcher;
+class QDBusPendingCallWatcherHelper;
+class QDBusConnectionPrivate;
+
+class QDBusPendingCallPrivate: public QSharedData
+{
+public:
+ // {
+ // set only during construction:
+ const QDBusMessage sentMessage;
+ QDBusConnectionPrivate * const connection;
+
+ // for the callback mechanism (see setReplyCallback and QDBusConnectionPrivate::sendWithReplyAsync)
+ QPointer<QObject> receiver;
+ QList<int> metaTypes;
+ int methodIdx;
+
+ bool autoDelete;
+ // }
+
+ mutable QMutex mutex;
+ QWaitCondition waitForFinishedCondition;
+
+ // {
+ // protected by the mutex above:
+ QDBusPendingCallWatcherHelper *watcherHelper;
+ QDBusMessage replyMessage;
+ DBusPendingCall *pending;
+ volatile bool waitingForFinished;
+
+ QString expectedReplySignature;
+ int expectedReplyCount;
+ // }
+
+ QDBusPendingCallPrivate(const QDBusMessage &sent, QDBusConnectionPrivate *connection)
+ : sentMessage(sent), connection(connection), autoDelete(false), watcherHelper(0), pending(0), waitingForFinished(false)
+ { }
+ ~QDBusPendingCallPrivate();
+ bool setReplyCallback(QObject *target, const char *member);
+ void waitForFinished();
+ void setMetaTypes(int count, const int *types);
+ void checkReceivedSignature();
+
+ static QDBusPendingCall fromMessage(const QDBusMessage &msg);
+};
+
+class QDBusPendingCallWatcherHelper: public QObject
+{
+ Q_OBJECT
+public:
+ void add(QDBusPendingCallWatcher *watcher);
+
+ void emitSignals(const QDBusMessage &replyMessage, const QDBusMessage &sentMessage)
+ {
+ if (replyMessage.type() == QDBusMessage::ReplyMessage)
+ emit reply(replyMessage);
+ else
+ emit error(replyMessage, sentMessage);
+ emit finished();
+ }
+
+Q_SIGNALS:
+ void finished();
+ void reply(const QDBusMessage &msg);
+ void error(const QDBusError &error, const QDBusMessage &msg);
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbuspendingreply.cpp b/src/dbus/qdbuspendingreply.cpp
new file mode 100644
index 0000000000..4dc1c77b8e
--- /dev/null
+++ b/src/dbus/qdbuspendingreply.cpp
@@ -0,0 +1,281 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbuspendingreply.h"
+#include "qdbuspendingcall_p.h"
+#include "qdbusmetatype.h"
+
+#ifndef QT_NO_DBUS
+
+/*!
+ \class QDBusPendingReply
+ \inmodule QtDBus
+ \since 4.5
+
+ \brief The QDBusPendingReply class contains the reply to an asynchronous method call
+
+ The QDBusPendingReply is a template class with up to 8 template
+ parameters. Those parameters are the types that will be used to
+ extract the contents of the reply's data.
+
+ This class is similar in functionality to QDBusReply, but with two
+ important differences:
+
+ \list
+ \o QDBusReply accepts exactly one return type, whereas
+ QDBusPendingReply can have from 1 to 8 types
+ \o QDBusReply only works on already completed replies, whereas
+ QDBusPendingReply allows one to wait for replies from pending
+ calls
+ \endlist
+
+ Where with QDBusReply you would write:
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbusreply.cpp 0
+
+ with QDBusPendingReply, the equivalent code (including the blocking
+ wait for the reply) would be:
+
+ \snippet doc/src/snippets/code/src.qdbus.qdbuspendingreply.cpp 0
+
+ For method calls that have more than one output argument, with
+ QDBusReply, you would write:
+
+ \snippet doc/src/snippets/code/src_qdbus_qdbusreply.cpp 1
+
+ whereas with QDBusPendingReply, all of the output arguments should
+ be template parameters:
+
+ \snippet doc/src/snippets/code/src.qdbus.qdbuspendingreply.cpp 2
+
+ QDBusPendingReply objects can be associated with
+ QDBusPendingCallWatcher objects, which emit signals when the reply
+ arrives.
+
+ \sa QDBusPendingCallWatcher, QDBusReply,
+ QDBusAbstractInterface::asyncCall()
+*/
+
+/*!
+ \fn QDBusPendingReply::QDBusPendingReply()
+
+ Creates an empty QDBusPendingReply object. Without assigning a
+ QDBusPendingCall object to this reply, QDBusPendingReply cannot do
+ anything. All functions return their failure values.
+*/
+
+/*!
+ \fn QDBusPendingReply::QDBusPendingReply(const QDBusPendingReply &other)
+
+ Creates a copy of the \a other QDBusPendingReply object. Just like
+ QDBusPendingCall and QDBusPendingCallWatcher, this QDBusPendingReply
+ object will share the same pending call reference. All copies
+ share the same return values.
+*/
+
+/*!
+ \fn QDBusPendingReply::QDBusPendingReply(const QDBusPendingCall &call)
+
+ Creates a QDBusPendingReply object that will take its contents from
+ the \a call pending asynchronous call. This QDBusPendingReply object
+ will share the same pending call reference as \a call.
+*/
+
+/*!
+ \fn QDBusPendingReply::QDBusPendingReply(const QDBusMessage &message)
+
+ Creates a QDBusPendingReply object that will take its contents from
+ the message \a message. In this case, this object will be already
+ in its finished state and the reply's contents will be accessible.
+
+ \sa isFinished()
+*/
+
+/*!
+ \fn QDBusPendingReply &QDBusPendingReply::operator=(const QDBusPendingReply &other)
+
+ Makes a copy of \a other and drops the reference to the current
+ pending call. If the current reference is to an unfinished pending
+ call and this is the last reference, the pending call will be
+ canceled and there will be no way of retrieving the reply's
+ contents, when they arrive.
+*/
+
+/*!
+ \fn QDBusPendingReply &QDBusPendingReply::operator=(const QDBusPendingCall &call)
+
+ Makes this object take its contents from the \a call pending call
+ and drops the reference to the current pending call. If the
+ current reference is to an unfinished pending call and this is the
+ last reference, the pending call will be canceled and there will
+ be no way of retrieving the reply's contents, when they arrive.
+*/
+
+/*!
+ \fn QDBusPendingReply &QDBusPendingReply::operator=(const QDBusMessage &message)
+
+ Makes this object take its contents from the \a message message
+ and drops the reference to the current pending call. If the
+ current reference is to an unfinished pending call and this is the
+ last reference, the pending call will be canceled and there will
+ be no way of retrieving the reply's contents, when they arrive.
+
+ After this function is finished, the QDBusPendingReply object will
+ be in its "finished" state and the \a message contents will be
+ accessible.
+
+ \sa isFinished()
+*/
+
+/*!
+ \fn int QDBusPendingReply::count() const
+
+ Return the number of arguments the reply is supposed to have. This
+ number matches the number of non-void template parameters in this
+ class.
+
+ If the reply arrives with a different number of arguments (or with
+ different types), it will be transformed into an error reply
+ indicating a bad signature.
+*/
+
+/*!
+ \fn QVariant QDBusPendingReply::argumentAt(int index) const
+
+ Returns the argument at position \a index in the reply's
+ contents. If the reply doesn't have that many elements, this
+ function's return value is undefined (will probably cause an
+ assertion failure), so it is important to verify that the
+ processing is finished and the reply is valid.
+*/
+
+/*!
+ \fn Type QDBusPendingReply::argumentAt() const
+
+ Returns the argument at position \c Index (which is a template
+ parameter) cast to type \c Type. This function uses template code
+ to determine the proper \c Type type, according to the type list
+ used in the construction of this object.
+
+ Note that, if the reply hasn't arrived, this function causes the
+ calling thread to block until the reply is processed.
+*/
+
+/*!
+ \fn T1 QDBusPendingReply::value() const
+
+ Returns the first argument in this reply, cast to type \c T1 (the
+ first template parameter of this class). This is equivalent to
+ calling argumentAt<0>().
+
+ This function is provided as a convenience, matching the
+ QDBusReply::value() function.
+
+ Note that, if the reply hasn't arrived, this function causes the
+ calling thread to block until the reply is processed.
+*/
+
+/*!
+ \fn QDBusPendingReply::operator T1() const
+
+ Returns the first argument in this reply, cast to type \c T1 (the
+ first template parameter of this class). This is equivalent to
+ calling argumentAt<0>().
+
+ This function is provided as a convenience, matching the
+ QDBusReply::value() function.
+
+ Note that, if the reply hasn't arrived, this function causes the
+ calling thread to block until the reply is processed.
+*/
+
+/*!
+ \fn void QDBusPendingReply::waitForFinished()
+
+ Suspends the execution of the calling thread until the reply is
+ received and processed. After this function returns, isFinished()
+ should return true, indicating the reply's contents are ready to
+ be processed.
+
+ \sa QDBusPendingCallWatcher::waitForFinished()
+*/
+
+QDBusPendingReplyData::QDBusPendingReplyData()
+ : QDBusPendingCall(0) // initialize base class empty
+{
+}
+
+QDBusPendingReplyData::~QDBusPendingReplyData()
+{
+}
+
+void QDBusPendingReplyData::assign(const QDBusPendingCall &other)
+{
+ QDBusPendingCall::operator=(other);
+}
+
+void QDBusPendingReplyData::assign(const QDBusMessage &message)
+{
+ d = new QDBusPendingCallPrivate(QDBusMessage(), 0); // drops the reference to the old one
+ d->replyMessage = message;
+}
+
+QVariant QDBusPendingReplyData::argumentAt(int index) const
+{
+ if (d)
+ d->waitForFinished(); // bypasses "const"
+
+ Q_ASSERT_X(d && index >= 0 && index < d->replyMessage.arguments().count(),
+ "QDBusPendingReply::argumentAt",
+ "Index out of bounds");
+
+ return d->replyMessage.arguments().at(index);
+}
+
+void QDBusPendingReplyData::setMetaTypes(int count, const int *types)
+{
+ Q_ASSERT(d);
+ QMutexLocker locker(&d->mutex);
+ d->setMetaTypes(count, types);
+ d->checkReceivedSignature();
+}
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbuspendingreply.h b/src/dbus/qdbuspendingreply.h
new file mode 100644
index 0000000000..cb230ca8da
--- /dev/null
+++ b/src/dbus/qdbuspendingreply.h
@@ -0,0 +1,217 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSPENDINGREPLY_H
+#define QDBUSPENDINGREPLY_H
+
+#include <QtCore/qglobal.h>
+#include <QtDBus/qdbusmacros.h>
+#include <QtDBus/qdbusargument.h>
+#include <QtDBus/qdbuspendingcall.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(DBus)
+
+class Q_DBUS_EXPORT QDBusPendingReplyData: public QDBusPendingCall
+{
+protected:
+ QDBusPendingReplyData();
+ ~QDBusPendingReplyData();
+ void assign(const QDBusPendingCall &call);
+ void assign(const QDBusMessage &message);
+
+ QVariant argumentAt(int index) const;
+ void setMetaTypes(int count, const int *metaTypes);
+};
+
+namespace QDBusPendingReplyTypes {
+ template<int Index,
+ typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8>
+ struct Select
+ {
+ typedef Select<Index - 1, T2, T3, T4, T5, T6, T7, T8, void> Next;
+ typedef typename Next::Type Type;
+ };
+ template<typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8>
+ struct Select<0, T1, T2, T3, T4, T5, T6, T7, T8>
+ {
+ typedef T1 Type;
+ };
+
+ template<typename T1> inline int metaTypeFor(T1 * = 0)
+ { return qMetaTypeId<T1>(); }
+ // specialize for QVariant, allowing it to be used in place of QDBusVariant
+ template<> inline int metaTypeFor<QVariant>(QVariant *)
+ { return qMetaTypeId<QDBusVariant>(); }
+
+ template<typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6, typename T7, typename T8>
+ struct ForEach
+ {
+ typedef ForEach<T2, T3, T4, T5, T6, T7, T8, void> Next;
+ enum { Total = Next::Total + 1 };
+ static inline void fillMetaTypes(int *p)
+ {
+ *p = metaTypeFor<T1>(0);
+ Next::fillMetaTypes(++p);
+ }
+ };
+ template<>
+ struct ForEach<void, void, void, void, void, void, void, void>
+ {
+ enum { Total = 0 };
+ static inline void fillMetaTypes(int *)
+ { }
+ };
+} // namespace QDBusPendingReplyTypes
+
+template<typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void,
+ typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void>
+class QDBusPendingReply:
+#ifdef Q_QDOC
+ public QDBusPendingCall
+#else
+ public QDBusPendingReplyData
+#endif
+{
+ typedef QDBusPendingReplyTypes::ForEach<T1, T2, T3, T4, T5, T6, T7, T8> ForEach;
+ template<int Index> struct Select :
+ QDBusPendingReplyTypes::Select<Index, T1, T2, T3, T4, T5, T6, T7, T8>
+ {
+ };
+
+public:
+ enum { Count = ForEach::Total };
+
+ inline QDBusPendingReply()
+ { }
+ inline QDBusPendingReply(const QDBusPendingReply &other)
+ : QDBusPendingReplyData(other)
+ { }
+ inline QDBusPendingReply(const QDBusPendingCall &call)
+ { *this = call; }
+ inline QDBusPendingReply(const QDBusMessage &message)
+ { *this = message; }
+ inline QDBusPendingReply &operator=(const QDBusPendingReply &other)
+ { assign(other); return *this; }
+ inline QDBusPendingReply &operator=(const QDBusPendingCall &call)
+ { assign(call); return *this; }
+ inline QDBusPendingReply &operator=(const QDBusMessage &message)
+ { assign(message); return *this; }
+
+ inline int count() const { return Count; }
+
+#if defined(Q_QDOC) || defined(Q_NO_USING_KEYWORD)
+ inline QVariant argumentAt(int index) const
+ { return QDBusPendingReplyData::argumentAt(index); }
+#else
+ using QDBusPendingReplyData::argumentAt;
+#endif
+
+#if defined(Q_QDOC)
+ bool isFinished() const;
+ void waitForFinished();
+
+ bool isValid() const;
+ bool isError() const;
+ QDBusError error() const;
+ QDBusMessage reply() const;
+
+ template<int Index> inline Type argumentAt() const;
+ inline T1 value() const;
+ inline operator T1() const;
+#else
+ template<int Index> inline
+ const typename Select<Index>::Type argumentAt() const
+ {
+ // static assert?
+ Q_ASSERT_X(Index < count() && Index >= 0, "QDBusPendingReply::argumentAt",
+ "Index out of bounds");
+ typedef typename Select<Index>::Type ResultType;
+ return qdbus_cast<ResultType>(argumentAt(Index), 0);
+ }
+
+ inline typename Select<0>::Type value() const
+ {
+ return argumentAt<0>();
+ }
+
+ inline operator typename Select<0>::Type() const
+ {
+ return argumentAt<0>();
+ }
+#endif
+
+private:
+ inline void calculateMetaTypes()
+ {
+ if (!d) return;
+ int typeIds[Count > 0 ? Count : 1]; // use at least one since zero-sized arrays aren't valid
+ ForEach::fillMetaTypes(typeIds);
+ setMetaTypes(Count, typeIds);
+ }
+
+ inline void assign(const QDBusPendingCall &call)
+ {
+ QDBusPendingReplyData::assign(call);
+ calculateMetaTypes();
+ }
+
+ inline void assign(const QDBusMessage &message)
+ {
+ QDBusPendingReplyData::assign(message);
+ calculateMetaTypes();
+ }
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusreply.cpp b/src/dbus/qdbusreply.cpp
new file mode 100644
index 0000000000..d360f27290
--- /dev/null
+++ b/src/dbus/qdbusreply.cpp
@@ -0,0 +1,248 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusreply.h"
+#include "qdbusmetatype.h"
+#include "qdbusmetatype_p.h"
+#include <QDebug>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QDBusReply
+ \inmodule QtDBus
+ \since 4.2
+
+ \brief The QDBusReply class stores the reply for a method call to a remote object.
+
+ A QDBusReply object is a subset of the QDBusMessage object that represents a method call's
+ reply. It contains only the first output argument or the error code and is used by
+ QDBusInterface-derived classes to allow returning the error code as the function's return
+ argument.
+
+ It can be used in the following manner:
+ \snippet doc/src/snippets/code/src_qdbus_qdbusreply.cpp 0
+
+ If the remote method call cannot fail, you can skip the error checking:
+ \snippet doc/src/snippets/code/src_qdbus_qdbusreply.cpp 1
+
+ However, if it does fail under those conditions, the value returned by QDBusReply::value() is
+ a default-constructed value. It may be indistinguishable from a valid return value.
+
+ QDBusReply objects are used for remote calls that have no output
+ arguments or return values (i.e., they have a "void" return
+ type). Use the isValid() function to test if the reply succeeded.
+
+ \sa QDBusMessage, QDBusInterface
+*/
+
+/*!
+ \fn QDBusReply::QDBusReply(const QDBusMessage &reply)
+ Automatically construct a QDBusReply object from the reply message \a reply, extracting the
+ first return value from it if it is a success reply.
+*/
+
+/*!
+ \fn QDBusReply::QDBusReply(const QDBusPendingReply<T> &reply)
+ Constructs a QDBusReply object from the pending reply message, \a reply.
+*/
+
+/*!
+ \fn QDBusReply::QDBusReply(const QDBusPendingCall &pcall)
+ Automatically construct a QDBusReply object from the asynchronous
+ pending call \a pcall. If the call isn't finished yet, QDBusReply
+ will call QDBusPendingCall::waitForFinished(), which is a blocking
+ operation.
+
+ If the return types patch, QDBusReply will extract the first
+ return argument from the reply.
+*/
+
+/*!
+ \fn QDBusReply::QDBusReply(const QDBusError &error)
+ Constructs an error reply from the D-Bus error code given by \a error.
+*/
+
+/*!
+ \fn QDBusReply::operator=(const QDBusReply &other)
+ Makes this object be a copy of the object \a other.
+*/
+
+/*!
+ \fn QDBusReply::operator=(const QDBusError &error)
+ Sets this object to contain the error code given by \a error. You
+ can later access it with error().
+*/
+
+/*!
+ \fn QDBusReply::operator=(const QDBusMessage &message)
+
+ Makes this object contain the reply specified by message \a
+ message. If \a message is an error message, this function will
+ copy the error code and message into this object
+
+ If \a message is a standard reply message and contains at least
+ one parameter, it will be copied into this object, as long as it
+ is of the correct type. If it's not of the same type as this
+ QDBusError object, this function will instead set an error code
+ indicating a type mismatch.
+*/
+
+/*!
+ \fn QDBusReply::operator=(const QDBusPendingCall &pcall)
+
+ Makes this object contain the reply specified by the pending
+ asynchronous call \a pcall. If the call is not finished yet, this
+ function will call QDBusPendingCall::waitForFinished() to block
+ until the reply arrives.
+
+ If \a pcall finishes with an error message, this function will
+ copy the error code and message into this object
+
+ If \a pcall finished with a standard reply message and contains at
+ least one parameter, it will be copied into this object, as long
+ as it is of the correct type. If it's not of the same type as this
+ QDBusError object, this function will instead set an error code
+ indicating a type mismatch.
+*/
+
+/*!
+ \fn bool QDBusReply::isValid() const
+
+ Returns true if no error occurred; otherwise, returns false.
+
+ \sa error()
+*/
+
+/*!
+ \fn QDBusReply::error()
+
+ Returns the error code that was returned from the remote function call. If the remote call did
+ not return an error (i.e., if it succeeded), then the QDBusError object that is returned will
+ not be a valid error code (QDBusError::isValid() will return false).
+
+ \sa isValid()
+*/
+
+/*!
+ \fn QDBusReply::value() const
+ Returns the remote function's calls return value. If the remote call returned with an error,
+ the return value of this function is undefined and may be undistinguishable from a valid return
+ value.
+
+ This function is not available if the remote call returns \c void.
+*/
+
+/*!
+ \fn QDBusReply::operator Type() const
+ Returns the same as value().
+
+ This function is not available if the remote call returns \c void.
+*/
+
+/*!
+ \internal
+ Fills in the QDBusReply data \a error and \a data from the reply message \a reply.
+*/
+void qDBusReplyFill(const QDBusMessage &reply, QDBusError &error, QVariant &data)
+{
+ error = reply;
+
+ if (error.isValid()) {
+ data = QVariant(); // clear it
+ return;
+ }
+
+ if (reply.arguments().count() >= 1 && reply.arguments().at(0).userType() == data.userType()) {
+ data = reply.arguments().at(0);
+ return;
+ }
+
+ const char *expectedSignature = QDBusMetaType::typeToSignature(data.userType());
+ const char *receivedType = 0;
+ QByteArray receivedSignature;
+
+ if (reply.arguments().count() >= 1) {
+ if (reply.arguments().at(0).userType() == QDBusMetaTypeId::argument) {
+ // compare signatures instead
+ QDBusArgument arg = qvariant_cast<QDBusArgument>(reply.arguments().at(0));
+ receivedSignature = arg.currentSignature().toLatin1();
+ if (receivedSignature == expectedSignature) {
+ // matched. Demarshall it
+ QDBusMetaType::demarshall(arg, data.userType(), data.data());
+ return;
+ }
+ } else {
+ // not an argument and doesn't match?
+ int type = reply.arguments().at(0).userType();
+ receivedType = QVariant::typeToName(QVariant::Type(type));
+ receivedSignature = QDBusMetaType::typeToSignature(type);
+ }
+ }
+
+ // error
+ if (receivedSignature.isEmpty())
+ receivedSignature = "no signature";
+ QString errorMsg;
+ if (receivedType) {
+ errorMsg = QString::fromLatin1("Unexpected reply signature: got \"%1\" (%4), "
+ "expected \"%2\" (%3)")
+ .arg(QLatin1String(receivedSignature),
+ QLatin1String(expectedSignature),
+ QLatin1String(data.typeName()),
+ QLatin1String(receivedType));
+ } else {
+ errorMsg = QString::fromLatin1("Unexpected reply signature: got \"%1\", "
+ "expected \"%2\" (%3)")
+ .arg(QLatin1String(receivedSignature),
+ QLatin1String(expectedSignature),
+ QLatin1String(data.typeName()));
+ }
+
+ error = QDBusError(QDBusError::InvalidSignature, errorMsg);
+ data = QVariant(); // clear it
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusreply.h b/src/dbus/qdbusreply.h
new file mode 100644
index 0000000000..1f535e3356
--- /dev/null
+++ b/src/dbus/qdbusreply.h
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSREPLY_H
+#define QDBUSREPLY_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qvariant.h>
+
+#include <QtDBus/qdbusmacros.h>
+#include <QtDBus/qdbusmessage.h>
+#include <QtDBus/qdbuserror.h>
+#include <QtDBus/qdbusextratypes.h>
+#include <QtDBus/qdbuspendingreply.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(DBus)
+
+Q_DBUS_EXPORT void qDBusReplyFill(const QDBusMessage &reply, QDBusError &error, QVariant &data);
+
+template<typename T>
+class QDBusReply
+{
+ typedef T Type;
+public:
+ inline QDBusReply(const QDBusMessage &reply)
+ {
+ *this = reply;
+ }
+ inline QDBusReply& operator=(const QDBusMessage &reply)
+ {
+ QVariant data(qMetaTypeId(&m_data), reinterpret_cast<void*>(0));
+ qDBusReplyFill(reply, m_error, data);
+ m_data = qvariant_cast<Type>(data);
+ return *this;
+ }
+
+ inline QDBusReply(const QDBusPendingCall &pcall)
+ {
+ *this = pcall;
+ }
+ inline QDBusReply &operator=(const QDBusPendingCall &pcall)
+ {
+ QDBusPendingCall other(pcall);
+ other.waitForFinished();
+ return *this = other.reply();
+ }
+ inline QDBusReply(const QDBusPendingReply<T> &reply)
+ {
+ *this = static_cast<QDBusPendingCall>(reply);
+ }
+
+ inline QDBusReply(const QDBusError &dbusError = QDBusError())
+ : m_error(dbusError), m_data(Type())
+ {
+ }
+ inline QDBusReply& operator=(const QDBusError& dbusError)
+ {
+ m_error = dbusError;
+ m_data = Type();
+ return *this;
+ }
+
+ inline QDBusReply& operator=(const QDBusReply& other)
+ {
+ m_error = other.m_error;
+ m_data = other.m_data;
+ return *this;
+ }
+
+ inline bool isValid() const { return !m_error.isValid(); }
+
+ inline const QDBusError& error() { return m_error; }
+
+ inline Type value() const
+ {
+ return m_data;
+ }
+
+ inline operator Type () const
+ {
+ return m_data;
+ }
+
+private:
+ QDBusError m_error;
+ Type m_data;
+};
+
+# ifndef Q_QDOC
+// specialize for QVariant:
+template<> inline QDBusReply<QVariant>&
+QDBusReply<QVariant>::operator=(const QDBusMessage &reply)
+{
+ void *null = 0;
+ QVariant data(qMetaTypeId<QDBusVariant>(), null);
+ qDBusReplyFill(reply, m_error, data);
+ m_data = qvariant_cast<QDBusVariant>(data).variant();
+ return *this;
+}
+
+// specialize for void:
+template<>
+class QDBusReply<void>
+{
+public:
+ inline QDBusReply(const QDBusMessage &reply)
+ : m_error(reply)
+ {
+ }
+ inline QDBusReply& operator=(const QDBusMessage &reply)
+ {
+ m_error = reply;
+ return *this;
+ }
+ inline QDBusReply(const QDBusError &dbusError = QDBusError())
+ : m_error(dbusError)
+ {
+ }
+ inline QDBusReply(const QDBusPendingCall &pcall)
+ {
+ *this = pcall;
+ }
+ inline QDBusReply &operator=(const QDBusPendingCall &pcall)
+ {
+ QDBusPendingCall other(pcall);
+ other.waitForFinished();
+ return *this = other.reply();
+ }
+ inline QDBusReply& operator=(const QDBusError& dbusError)
+ {
+ m_error = dbusError;
+ return *this;
+ }
+
+ inline QDBusReply& operator=(const QDBusReply& other)
+ {
+ m_error = other.m_error;
+ return *this;
+ }
+
+ inline bool isValid() const { return !m_error.isValid(); }
+
+ inline const QDBusError& error() { return m_error; }
+
+private:
+ QDBusError m_error;
+};
+# endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusserver.cpp b/src/dbus/qdbusserver.cpp
new file mode 100644
index 0000000000..abc5cb3cbe
--- /dev/null
+++ b/src/dbus/qdbusserver.cpp
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusserver.h"
+#include "qdbusconnection_p.h"
+#include "qdbusconnectionmanager_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QDBusServer
+ \inmodule QtDBus
+ \internal
+
+ \brief The QDBusServer class provides peer-to-peer communication
+ between processes on the same computer.
+*/
+
+/*!
+ Constructs a QDBusServer with the given \a address, and the given
+ \a parent.
+*/
+QDBusServer::QDBusServer(const QString &address, QObject *parent)
+ : QObject(parent)
+{
+ if (address.isEmpty())
+ return;
+
+ if (!qdbus_loadLibDBus()) {
+ d = 0;
+ return;
+ }
+ d = new QDBusConnectionPrivate(this);
+
+ QMutexLocker locker(&QDBusConnectionManager::instance()->mutex);
+ QDBusConnectionManager::instance()->setConnection(QLatin1String("QDBusServer-") + QString::number(reinterpret_cast<qulonglong>(d)), d);
+
+ QObject::connect(d, SIGNAL(newServerConnection(QDBusConnection)),
+ this, SIGNAL(newConnection(QDBusConnection)));
+
+ QDBusErrorInternal error;
+ d->setServer(q_dbus_server_listen(address.toUtf8().constData(), error), error);
+}
+
+/*!
+ Destructs a QDBusServer
+*/
+QDBusServer::~QDBusServer()
+{
+ if (QDBusConnectionManager::instance()) {
+ QMutexLocker locker(&QDBusConnectionManager::instance()->mutex);
+ QDBusConnectionManager::instance()->removeConnection(d->name);
+ }
+}
+
+/*!
+ Returns true if this QDBusServer object is connected.
+
+ If it isn't connected, you need to call the constructor again.
+*/
+bool QDBusServer::isConnected() const
+{
+ return d && d->server && q_dbus_server_get_is_connected(d->server);
+}
+
+/*!
+ Returns the last error that happened in this server.
+
+ This function is provided for low-level code.
+*/
+QDBusError QDBusServer::lastError() const
+{
+ return d->lastError;
+}
+
+/*!
+ Returns the address this server is associated with.
+*/
+QString QDBusServer::address() const
+{
+ QString addr;
+ if (d && d->server) {
+ char *c = q_dbus_server_get_address(d->server);
+ addr = QString::fromUtf8(c);
+ q_dbus_free(c);
+ }
+
+ return addr;
+}
+
+/*!
+ \fn void QDBusServer::newConnection(const QDBusConnection &connection)
+
+ This signal is emitted when a new client connection \a connection is
+ established to the server.
+ */
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusserver.h b/src/dbus/qdbusserver.h
new file mode 100644
index 0000000000..fcb78bdb1e
--- /dev/null
+++ b/src/dbus/qdbusserver.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QDBUSSERVER_H
+#define QDBUSSERVER_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+#include <QtDBus/qdbusmacros.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(DBus)
+
+class QDBusConnectionPrivate;
+class QDBusError;
+class QDBusConnection;
+
+class Q_DBUS_EXPORT QDBusServer: public QObject
+{
+ Q_OBJECT
+public:
+ QDBusServer(const QString &address = "unix:tmpdir=/tmp", QObject *parent = 0);
+ virtual ~QDBusServer();
+
+ bool isConnected() const;
+ QDBusError lastError() const;
+ QString address() const;
+
+Q_SIGNALS:
+ void newConnection(const QDBusConnection &connection);
+
+private:
+ Q_DISABLE_COPY(QDBusServer)
+ QDBusConnectionPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusservicewatcher.cpp b/src/dbus/qdbusservicewatcher.cpp
new file mode 100644
index 0000000000..615d7d38e0
--- /dev/null
+++ b/src/dbus/qdbusservicewatcher.cpp
@@ -0,0 +1,381 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusservicewatcher.h"
+#include "qdbusconnection.h"
+#include "qdbus_symbols_p.h"
+
+#include <QStringList>
+
+#include <private/qobject_p.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC_WITH_ARGS(QString, busService, (QLatin1String(DBUS_SERVICE_DBUS)))
+Q_GLOBAL_STATIC_WITH_ARGS(QString, busInterface, (QLatin1String(DBUS_INTERFACE_DBUS)))
+Q_GLOBAL_STATIC_WITH_ARGS(QString, signalName, (QLatin1String("NameOwnerChanged")))
+
+class QDBusServiceWatcherPrivate: public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QDBusServiceWatcher)
+public:
+ QDBusServiceWatcherPrivate(const QDBusConnection &c, QDBusServiceWatcher::WatchMode wm)
+ : connection(c), watchMode(wm)
+ {
+ }
+
+ QStringList servicesWatched;
+ QDBusConnection connection;
+ QDBusServiceWatcher::WatchMode watchMode;
+
+ void _q_serviceOwnerChanged(const QString &, const QString &, const QString &);
+ void setConnection(const QStringList &services, const QDBusConnection &c, QDBusServiceWatcher::WatchMode watchMode);
+
+ QStringList matchArgsForService(const QString &service);
+ void addService(const QString &service);
+ void removeService(const QString &service);
+};
+
+void QDBusServiceWatcherPrivate::_q_serviceOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner)
+{
+ Q_Q(QDBusServiceWatcher);
+ emit q->serviceOwnerChanged(service, oldOwner, newOwner);
+ if (oldOwner.isEmpty())
+ emit q->serviceRegistered(service);
+ else if (newOwner.isEmpty())
+ emit q->serviceUnregistered(service);
+}
+
+void QDBusServiceWatcherPrivate::setConnection(const QStringList &s, const QDBusConnection &c, QDBusServiceWatcher::WatchMode wm)
+{
+ if (connection.isConnected()) {
+ // remove older rules
+ foreach (const QString &s, servicesWatched)
+ removeService(s);
+ }
+
+ connection = c;
+ watchMode = wm;
+ servicesWatched = s;
+
+ if (connection.isConnected()) {
+ // add new rules
+ foreach (const QString &s, servicesWatched)
+ addService(s);
+ }
+}
+
+QStringList QDBusServiceWatcherPrivate::matchArgsForService(const QString &service)
+{
+ QStringList matchArgs;
+ matchArgs << service;
+
+ switch (watchMode) {
+ case QDBusServiceWatcher::WatchForOwnerChange:
+ break;
+
+ case QDBusServiceWatcher::WatchForRegistration:
+ matchArgs << QString::fromLatin1("", 0);
+ break;
+
+ case QDBusServiceWatcher::WatchForUnregistration:
+ matchArgs << QString() << QString::fromLatin1("", 0);
+ break;
+ }
+ return matchArgs;
+}
+
+void QDBusServiceWatcherPrivate::addService(const QString &service)
+{
+ QStringList matchArgs = matchArgsForService(service);
+ connection.connect(*busService(), QString(), *busInterface(), *signalName(),
+ matchArgs, QString(), q_func(),
+ SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
+}
+
+void QDBusServiceWatcherPrivate::removeService(const QString &service)
+{
+ QStringList matchArgs = matchArgsForService(service);
+ connection.disconnect(*busService(), QString(), *busInterface(), *signalName(),
+ matchArgs, QString(), q_func(),
+ SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
+}
+
+/*!
+ \class QDBusServiceWatcher
+ \since 4.6
+ \inmodule QtDBus
+
+ \brief The QDBusServiceWatcher class allows the user to watch for a bus service change.
+
+ A QDBusServiceWatcher object can be used to notify the application about
+ an ownership change of a service name on the bus. It has three watch
+ modes:
+
+ \list
+ \o Watching for service registration only.
+ \o Watching for service unregistration only.
+ \o Watching for any kind of service ownership change (the default mode).
+ \endlist
+
+ Besides being created or deleted, services may change owners without a
+ unregister/register operation happening. So the serviceRegistered()
+ and serviceUnregistered() signals may not be emitted if that
+ happens.
+
+ This class is more efficient than using the
+ QDBusConnectionInterface::serviceOwnerChanged() signal because it allows
+ one to receive only the signals for which the class is interested in.
+
+ \sa QDBusConnection
+*/
+
+/*!
+ \enum QDBusServiceWatcher::WatchModeFlag
+
+ QDBusServiceWatcher supports three different watch modes, which are configured by this flag:
+
+ \value WatchForRegistration watch for service registration only, ignoring
+ any signals related to other service ownership change.
+
+ \value WatchForUnregistration watch for service unregistration only,
+ ignoring any signals related to other service ownership change.
+
+ \value WatchForOwnerChange watch for any kind of service ownership
+ change.
+*/
+
+/*!
+ \property QDBusServiceWatcher::watchMode
+
+ The \c watchMode property holds the current watch mode for this
+ QDBusServiceWatcher object. The default value for this property is
+ QDBusServiceWatcher::WatchForOwnershipChange.
+*/
+
+/*!
+ \property QDBusServiceWatcher::watchedServices
+
+ The \c servicesWatched property holds the list of services watched.
+
+ Note that modifying this list with setServicesWatched() is an expensive
+ operation. If you can, prefer to change it by way of addWatchedService()
+ and removeWatchedService().
+*/
+
+/*!
+ \fn void QDBusServiceWatcher::serviceRegistered(const QString &serviceName)
+
+ This signal is emitted whenever this object detects that the service \a
+ serviceName became available on the bus.
+
+ \sa serviceUnregistered(), serviceOwnerChanged()
+*/
+
+/*!
+ \fn void QDBusServiceWatcher::serviceUnregistered(const QString &serviceName)
+
+ This signal is emitted whenever this object detects that the service \a
+ serviceName was unregistered from the bus and is no longer available.
+
+ \sa serviceRegistered(), serviceOwnerChanged()
+*/
+
+/*!
+ \fn void QDBusServiceWatcher::serviceOwnerChanged(const QString &serviceName, const QString &oldOwner, const QString &newOwner)
+
+ This signal is emitted whenever this object detects that there was a
+ service ownership change relating to the \a serviceName service. The \a
+ oldOwner parameter contains the old owner name and \a newOwner is the new
+ owner. Both \a oldOwner and \a newOwner are unique connection names.
+
+ Note that this signal is also emitted whenever the \a serviceName service
+ was registered or unregistered. If it was registered, \a oldOwner will
+ contain an empty string, whereas if it was unregistered, \a newOwner will
+ contain an empty string.
+
+ If you need only to find out if the service is registered or unregistered
+ only, without being notified that the ownership changed, consider using
+ the specific modes for those operations. This class is more efficient if
+ you use the more specific modes.
+
+ \sa serviceRegistered(), serviceUnregistered()
+*/
+
+/*!
+ Creates a QDBusServiceWatcher object. Note that until you set a
+ connection with setConnection(), this object will not emit any signals.
+
+ The \a parent parameter is passed to QObject to set the parent of this
+ object.
+*/
+QDBusServiceWatcher::QDBusServiceWatcher(QObject *parent)
+ : QObject(*new QDBusServiceWatcherPrivate(QDBusConnection(QString()), WatchForOwnerChange), parent)
+{
+}
+
+/*!
+ Creates a QDBusServiceWatcher object and attaches it to the \a connection
+ connection. Also, this function immediately starts watching for \a
+ watchMode changes to service \a service.
+
+ The \a parent parameter is passed to QObject to set the parent of this
+ object.
+*/
+QDBusServiceWatcher::QDBusServiceWatcher(const QString &service, const QDBusConnection &connection, WatchMode watchMode, QObject *parent)
+ : QObject(*new QDBusServiceWatcherPrivate(connection, watchMode), parent)
+{
+ d_func()->setConnection(QStringList() << service, connection, watchMode);
+}
+
+/*!
+ Destroys the QDBusServiceWatcher object and releases any resources
+ associated with it.
+*/
+QDBusServiceWatcher::~QDBusServiceWatcher()
+{
+}
+
+/*!
+ Returns the list of D-Bus services that are being watched.
+
+ \sa setWatchedServices()
+*/
+QStringList QDBusServiceWatcher::watchedServices() const
+{
+ return d_func()->servicesWatched;
+}
+
+/*!
+ Sets the list of D-Bus services being watched to be \a services.
+
+ Note that setting the entire list means removing all previous rules for
+ watching services and adding new ones. This is an expensive operation and
+ should be avoided, if possible. Instead, use addWatchedService() and
+ removeWatchedService() if you can to manipulate entries in the list.
+*/
+void QDBusServiceWatcher::setWatchedServices(const QStringList &services)
+{
+ Q_D(QDBusServiceWatcher);
+ if (services == d->servicesWatched)
+ return;
+ d->setConnection(services, d->connection, d->watchMode);
+}
+
+/*!
+ Adds \a newService to the list of services to be watched by this object.
+ This function is more efficient than setWatchedServices() and should be
+ used whenever possible to add services.
+*/
+void QDBusServiceWatcher::addWatchedService(const QString &newService)
+{
+ Q_D(QDBusServiceWatcher);
+ if (d->servicesWatched.contains(newService))
+ return;
+ d->addService(newService);
+ d->servicesWatched << newService;
+}
+
+/*!
+ Removes the \a service from the list of services being watched by this
+ object. Note that D-Bus notifications are asynchronous, so there may
+ still be signals pending delivery about \a service. Those signals will
+ still be emitted whenever the D-Bus messages are processed.
+
+ This function returns true if any services were removed.
+*/
+bool QDBusServiceWatcher::removeWatchedService(const QString &service)
+{
+ Q_D(QDBusServiceWatcher);
+ d->removeService(service);
+ return d->servicesWatched.removeOne(service);
+}
+
+QDBusServiceWatcher::WatchMode QDBusServiceWatcher::watchMode() const
+{
+ return d_func()->watchMode;
+}
+
+void QDBusServiceWatcher::setWatchMode(WatchMode mode)
+{
+ Q_D(QDBusServiceWatcher);
+ if (mode == d->watchMode)
+ return;
+ d->setConnection(d->servicesWatched, d->connection, mode);
+}
+
+/*!
+ Returns the QDBusConnection that this object is attached to.
+
+ \sa setConnection()
+*/
+QDBusConnection QDBusServiceWatcher::connection() const
+{
+ return d_func()->connection;
+}
+
+/*!
+ Sets the D-Bus connection that this object is attached to be \a
+ connection. All services watched will be transferred to this connection.
+
+ Note that QDBusConnection objects are reference counted:
+ QDBusServiceWatcher will keep a reference for this connection while it
+ exists. The connection is not closed until the reference count drops to
+ zero, so this will ensure that any notifications are received while this
+ QDBusServiceWatcher object exists.
+
+ \sa connection()
+*/
+void QDBusServiceWatcher::setConnection(const QDBusConnection &connection)
+{
+ Q_D(QDBusServiceWatcher);
+ if (connection.name() == d->connection.name())
+ return;
+ d->setConnection(d->servicesWatched, connection, d->watchMode);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
+
+#include "moc_qdbusservicewatcher.cpp"
diff --git a/src/dbus/qdbusservicewatcher.h b/src/dbus/qdbusservicewatcher.h
new file mode 100644
index 0000000000..0e0b52efac
--- /dev/null
+++ b/src/dbus/qdbusservicewatcher.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSSERVICEWATCHER_H
+#define QDBUSSERVICEWATCHER_H
+
+#include <QtCore/qobject.h>
+#include <QtDBus/qdbusmacros.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(DBus)
+
+class QDBusConnection;
+
+class QDBusServiceWatcherPrivate;
+class Q_DBUS_EXPORT QDBusServiceWatcher: public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QStringList watchedServices READ watchedServices WRITE setWatchedServices)
+ Q_PROPERTY(WatchMode watchMode READ watchMode WRITE setWatchMode)
+public:
+ enum WatchModeFlag {
+ WatchForRegistration = 0x01,
+ WatchForUnregistration = 0x02,
+ WatchForOwnerChange = 0x03
+ };
+ Q_DECLARE_FLAGS(WatchMode, WatchModeFlag)
+
+ explicit QDBusServiceWatcher(QObject *parent = 0);
+ QDBusServiceWatcher(const QString &service, const QDBusConnection &connection,
+ WatchMode watchMode = WatchForOwnerChange, QObject *parent = 0);
+ ~QDBusServiceWatcher();
+
+ QStringList watchedServices() const;
+ void setWatchedServices(const QStringList &services);
+ void addWatchedService(const QString &newService);
+ bool removeWatchedService(const QString &service);
+
+ WatchMode watchMode() const;
+ void setWatchMode(WatchMode mode);
+
+ QDBusConnection connection() const;
+ void setConnection(const QDBusConnection &connection);
+
+Q_SIGNALS:
+ void serviceRegistered(const QString &service);
+ void serviceUnregistered(const QString &service);
+ void serviceOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner);
+
+private:
+ Q_PRIVATE_SLOT(d_func(), void _q_serviceOwnerChanged(QString,QString,QString))
+ Q_DISABLE_COPY(QDBusServiceWatcher)
+ Q_DECLARE_PRIVATE(QDBusServiceWatcher)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDBusServiceWatcher::WatchMode)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif // QDBUSSERVICEWATCHER_H
diff --git a/src/dbus/qdbusthreaddebug_p.h b/src/dbus/qdbusthreaddebug_p.h
new file mode 100644
index 0000000000..d595a41cb7
--- /dev/null
+++ b/src/dbus/qdbusthreaddebug_p.h
@@ -0,0 +1,235 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QDBUSTHREADDEBUG_P_H
+#define QDBUSTHREADDEBUG_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+#ifndef QT_NO_DBUS
+
+#if !defined(QDBUS_THREAD_DEBUG) && defined(QT_BUILD_INTERNAL)
+# define QDBUS_THREAD_DEBUG 1
+#endif
+
+#if QDBUS_THREAD_DEBUG
+QT_BEGIN_NAMESPACE
+typedef void (*qdbusThreadDebugFunc)(int, int, QDBusConnectionPrivate *);
+Q_DBUS_EXPORT void qdbusDefaultThreadDebug(int, int, QDBusConnectionPrivate *);
+extern Q_DBUS_EXPORT qdbusThreadDebugFunc qdbusThreadDebug;
+QT_END_NAMESPACE
+#endif
+
+enum ThreadAction {
+ ConnectAction = 0,
+ DisconnectAction = 1,
+ RegisterObjectAction = 2,
+ UnregisterObjectAction = 3,
+ ObjectRegisteredAtAction = 4,
+
+ CloseConnectionAction = 10,
+ ObjectDestroyedAction = 11,
+ RelaySignalAction = 12,
+ HandleObjectCallAction = 13,
+ HandleSignalAction = 14,
+ ConnectRelayAction = 15,
+ DisconnectRelayAction = 16,
+ FindMetaObject1Action = 17,
+ FindMetaObject2Action = 18,
+ RegisterServiceAction = 19,
+ UnregisterServiceAction = 20,
+ UpdateSignalHookOwnerAction = 21,
+ HandleObjectCallPostEventAction = 22,
+ HandleObjectCallSemaphoreAction = 23,
+ DoDispatchAction = 24,
+ SendWithReplyAsyncAction = 25,
+ MessageResultReceivedAction = 26,
+ ActivateSignalAction = 27,
+ PendingCallBlockAction = 28,
+
+ AddTimeoutAction = 50,
+ RealAddTimeoutAction = 51,
+ RemoveTimeoutAction = 52,
+ KillTimerAction = 58,
+ TimerEventAction = 59,
+ AddWatchAction = 60,
+ RemoveWatchAction = 61,
+ ToggleWatchAction = 62,
+ SocketReadAction = 63,
+ SocketWriteAction = 64
+};
+
+struct QDBusLockerBase
+{
+ enum Condition
+ {
+ BeforeLock,
+ AfterLock,
+ BeforeUnlock,
+ AfterUnlock,
+
+ BeforePost,
+ AfterPost,
+ BeforeDeliver,
+ AfterDeliver,
+
+ BeforeAcquire,
+ AfterAcquire,
+ BeforeRelease,
+ AfterRelease
+ };
+
+#if QDBUS_THREAD_DEBUG
+ static inline void reportThreadAction(int action, int condition, QDBusConnectionPrivate *ptr)
+ { if (qdbusThreadDebug) qdbusThreadDebug(action, condition, ptr); }
+#else
+ static inline void reportThreadAction(int, int, QDBusConnectionPrivate *) { }
+#endif
+};
+
+struct QDBusReadLocker: QDBusLockerBase
+{
+ QDBusConnectionPrivate *self;
+ ThreadAction action;
+ inline QDBusReadLocker(ThreadAction a, QDBusConnectionPrivate *s)
+ : self(s), action(a)
+ {
+ reportThreadAction(action, BeforeLock, self);
+ self->lock.lockForRead();
+ reportThreadAction(action, AfterLock, self);
+ }
+
+ inline ~QDBusReadLocker()
+ {
+ reportThreadAction(action, BeforeUnlock, self);
+ self->lock.unlock();
+ reportThreadAction(action, AfterUnlock, self);
+ }
+};
+
+struct QDBusWriteLocker: QDBusLockerBase
+{
+ QDBusConnectionPrivate *self;
+ ThreadAction action;
+ inline QDBusWriteLocker(ThreadAction a, QDBusConnectionPrivate *s)
+ : self(s), action(a)
+ {
+ reportThreadAction(action, BeforeLock, self);
+ self->lock.lockForWrite();
+ reportThreadAction(action, AfterLock, self);
+ }
+
+ inline ~QDBusWriteLocker()
+ {
+ reportThreadAction(action, BeforeUnlock, self);
+ self->lock.unlock();
+ reportThreadAction(action, AfterUnlock, self);
+ }
+};
+
+struct QDBusMutexLocker: QDBusLockerBase
+{
+ QDBusConnectionPrivate *self;
+ QMutex *mutex;
+ ThreadAction action;
+ inline QDBusMutexLocker(ThreadAction a, QDBusConnectionPrivate *s,
+ QMutex *m)
+ : self(s), mutex(m), action(a)
+ {
+ reportThreadAction(action, BeforeLock, self);
+ mutex->lock();
+ reportThreadAction(action, AfterLock, self);
+ }
+
+ inline ~QDBusMutexLocker()
+ {
+ reportThreadAction(action, BeforeUnlock, self);
+ mutex->unlock();
+ reportThreadAction(action, AfterUnlock, self);
+ }
+};
+
+struct QDBusDispatchLocker: QDBusMutexLocker
+{
+ inline QDBusDispatchLocker(ThreadAction a, QDBusConnectionPrivate *s)
+ : QDBusMutexLocker(a, s, &s->dispatchLock)
+ { }
+};
+
+struct QDBusWatchAndTimeoutLocker: QDBusMutexLocker
+{
+ inline QDBusWatchAndTimeoutLocker(ThreadAction a, QDBusConnectionPrivate *s)
+ : QDBusMutexLocker(a, s, &s->watchAndTimeoutLock)
+ { }
+};
+
+#if QDBUS_THREAD_DEBUG
+# define SEM_ACQUIRE(action, sem) \
+ do { \
+ QDBusLockerBase::reportThreadAction(action, QDBusLockerBase::BeforeAcquire, this); \
+ sem.acquire(); \
+ QDBusLockerBase::reportThreadAction(action, QDBusLockerBase::AfterAcquire, this); \
+ } while (0)
+
+# define SEM_RELEASE(action, sem) \
+ do { \
+ QDBusLockerBase::reportThreadAction(action, QDBusLockerBase::BeforeRelease, that); \
+ sem.release(); \
+ QDBusLockerBase::reportThreadAction(action, QDBusLockerBase::AfterRelease, that); \
+ } while (0)
+
+#else
+# define SEM_ACQUIRE(action, sem) sem.acquire()
+# define SEM_RELEASE(action, sem) sem.release()
+#endif
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusunixfiledescriptor.cpp b/src/dbus/qdbusunixfiledescriptor.cpp
new file mode 100644
index 0000000000..f45b6cc2ec
--- /dev/null
+++ b/src/dbus/qdbusunixfiledescriptor.cpp
@@ -0,0 +1,316 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the FOO module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qdbusunixfiledescriptor.h"
+#include <QSharedData>
+
+#ifdef Q_OS_UNIX
+# include <private/qcore_unix_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QDBusUnixFileDescriptor
+ \inmodule QtDBus
+ \since 4.8
+
+ \brief The QDBusUnixFileDescriptor class holds one Unix file descriptor.
+
+ The QDBusUnixFileDescriptor class is used to hold one Unix file
+ descriptor for use with the QtDBus module. This allows applications to
+ send and receive Unix file descriptors over the D-Bus connection, mapping
+ automatically to the D-Bus type 'h'.
+
+ Objects of type QDBusUnixFileDescriptors can be used also as parameters
+ in signals and slots that get exported to D-Bus by registering with
+ QDBusConnection::registerObject.
+
+ QDBusUnixFileDescriptor does not take ownership of the file descriptor.
+ Instead, it will use the Unix system call \c dup(2) to make a copy of the
+ file descriptor. This file descriptor belongs to the
+ QDBusUnixFileDescriptor object and should not be stored or closed by the
+ user. Instead, you should make your own copy if you need that.
+
+ \section2 Availability
+
+ Unix file descriptor passing is not available in all D-Bus connections.
+ This feature is present with D-Bus library and bus daemon version 1.4 and
+ upwards on Unix systems. QtDBus automatically enables the feature if such
+ a version was found at compile-time and run-time.
+
+ To verify that your connection does support passing file descriptors,
+ check if the QDBusConnection::UnixFileDescriptorPassing capability is set
+ with QDBusConnection::connectionCapabilities(). If the flag is not
+ active, then you will not be able to make calls to methods that have
+ QDBusUnixFileDescriptor as arguments or even embed such a type in a
+ variant. You will also not receive calls containing that type.
+
+ Note also that remote applications may not have support for Unix file
+ descriptor passing. If you make a D-Bus to a remote application that
+ cannot receive such a type, you will receive an error reply. If you try
+ to send a signal containing a D-Bus file descriptor or return one from a
+ method call, the message will be silently dropped.
+
+ Even if the feature is not available, QDBusUnixFileDescriptor will
+ continue to operate, so code need not have compile-time checks for the
+ availability of this feature.
+
+ On non-Unix systems, QDBusUnixFileDescriptor will always report an
+ invalid state and QDBusUnixFileDescriptor::isSupported() will return
+ false.
+
+ \sa QDBusConnection::ConnectionCapabilities, QDBusConnection::connectionCapabilities
+*/
+
+class QDBusUnixFileDescriptorPrivate : public QSharedData {
+public:
+ QDBusUnixFileDescriptorPrivate() : fd(-1) { }
+ QDBusUnixFileDescriptorPrivate(const QDBusUnixFileDescriptorPrivate &other)
+ : QSharedData(other), fd(-1)
+ { }
+ ~QDBusUnixFileDescriptorPrivate();
+
+ QAtomicInt fd;
+};
+
+template<> inline
+QExplicitlySharedDataPointer<QDBusUnixFileDescriptorPrivate>::~QExplicitlySharedDataPointer()
+{ if (d && !d->ref.deref()) delete d; }
+
+/*!
+ Constructs a QDBusUnixFileDescriptor without a wrapped file descriptor.
+ This is equivalent to constructing the object with an invalid file
+ descriptor (like -1).
+
+ \sa fileDescriptor, isValid
+*/
+QDBusUnixFileDescriptor::QDBusUnixFileDescriptor()
+ : d(0)
+{
+}
+
+/*!
+ Constructs a QDBusUnixFileDescriptor object by copying the \a
+ fileDescriptor parameter. The original file descriptor is not touched and
+ must be closed by the user.
+
+ Note that the value returned by fileDescriptor() will be different from
+ the \a fileDescriptor parameter passed.
+
+ If the \a fileDescriptor parameter is not valid, isValid() will return
+ false and fileDescriptor() will return -1.
+
+ \sa setFileDescriptor, fileDescriptor
+*/
+QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(int fileDescriptor)
+ : d(0)
+{
+ if (fileDescriptor != -1)
+ setFileDescriptor(fileDescriptor);
+}
+
+/*!
+ Constructs a QDBusUnixFileDescriptor object by copying \a other.
+*/
+QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(const QDBusUnixFileDescriptor &other)
+ : d(other.d)
+{
+}
+
+/*!
+ Copies the Unix file descriptor from the \a other QDBusUnixFileDescriptor
+ object. If the current object contained a file descriptor, it will be
+ properly disposed of before.
+*/
+QDBusUnixFileDescriptor &QDBusUnixFileDescriptor::operator=(const QDBusUnixFileDescriptor &other)
+{
+ if (this != &other)
+ d.operator=(other.d);
+ return *this;
+}
+
+/*!
+ Destroys this QDBusUnixFileDescriptor object and disposes of the Unix file descriptor that it contained.
+*/
+QDBusUnixFileDescriptor::~QDBusUnixFileDescriptor()
+{
+}
+
+/*!
+ Returns true if this Unix file descriptor is valid. A valid Unix file
+ descriptor is not -1.
+
+ \sa fileDescriptor()
+*/
+bool QDBusUnixFileDescriptor::isValid() const
+{
+ return d ? d->fd != -1 : false;
+}
+
+/*!
+ Returns the Unix file descriptor contained by this
+ QDBusUnixFileDescriptor object. An invalid file descriptor is represented
+ by the value -1.
+
+ Note that the file descriptor returned by this function is owned by the
+ QDBusUnixFileDescriptor object and must not be stored past the lifetime
+ of this object. It is ok to use it while this object is valid, but if one
+ wants to store it for longer use, the file descriptor should be cloned
+ using the Unix \c dup(2), \c dup2(2) or \c dup3(2) functions.
+
+ \sa isValid()
+*/
+int QDBusUnixFileDescriptor::fileDescriptor() const
+{
+ return d ? d->fd.operator int() : -1;
+}
+
+// actual implementation
+#ifdef Q_OS_UNIX
+
+// qdoc documentation is generated on Unix
+
+/*!
+ Returns true if Unix file descriptors are supported on this platform. In
+ other words, this function returns true if this is a Unix platform.
+
+ Note that QDBusUnixFileDescriptor continues to operate even if this
+ function returns false. The only difference is that the
+ QDBusUnixFileDescriptor objects will always be in the isValid() == false
+ state and fileDescriptor() will always return -1. The class will not
+ consume any operating system resources.
+*/
+bool QDBusUnixFileDescriptor::isSupported()
+{
+ return true;
+}
+
+/*!
+ Sets the file descriptor that this QDBusUnixFileDescriptor object holds
+ to a copy of \a fileDescriptor.T he original file descriptor is not
+ touched and must be closed by the user.
+
+ Note that the value returned by fileDescriptor() will be different from
+ the \a fileDescriptor parameter passed.
+
+ If the \a fileDescriptor parameter is not valid, isValid() will return
+ false and fileDescriptor() will return -1.
+
+ \sa isValid(), fileDescriptor()
+*/
+void QDBusUnixFileDescriptor::setFileDescriptor(int fileDescriptor)
+{
+ if (fileDescriptor != -1)
+ giveFileDescriptor(qt_safe_dup(fileDescriptor));
+}
+
+/*!
+ \internal
+ Sets the Unix file descriptor to \a fileDescriptor without copying.
+
+ \sa setFileDescriptor()
+*/
+void QDBusUnixFileDescriptor::giveFileDescriptor(int fileDescriptor)
+{
+ // if we are the sole ref, d remains unchanged
+ // if detaching happens, d->fd will be -1
+ if (d)
+ d.detach();
+ else
+ d = new QDBusUnixFileDescriptorPrivate;
+
+ if (d->fd != -1)
+ qt_safe_close(d->fd);
+
+ if (fileDescriptor != -1)
+ d->fd = fileDescriptor;
+}
+
+/*!
+ \internal
+ Extracts the Unix file descriptor from the QDBusUnixFileDescriptor object
+ and transfers ownership.
+
+ Note: since QDBusUnixFileDescriptor is implicitly shared, this function
+ is inherently racy and should be avoided.
+*/
+int QDBusUnixFileDescriptor::takeFileDescriptor()
+{
+ if (!d)
+ return -1;
+
+ return d->fd.fetchAndStoreRelaxed(-1);
+}
+
+QDBusUnixFileDescriptorPrivate::~QDBusUnixFileDescriptorPrivate()
+{
+ if (fd != -1)
+ qt_safe_close(fd);
+}
+
+#else
+bool QDBusUnixFileDescriptor::isSupported()
+{
+ return false;
+}
+
+void QDBusUnixFileDescriptor::setFileDescriptor(int)
+{
+}
+
+void QDBusUnixFileDescriptor::giveFileDescriptor(int)
+{
+}
+
+int QDBusUnixFileDescriptor::takeFileDescriptor()
+{
+ return -1;
+}
+
+QDBusUnixFileDescriptorPrivate::~QDBusUnixFileDescriptorPrivate()
+{
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/dbus/qdbusunixfiledescriptor.h b/src/dbus/qdbusunixfiledescriptor.h
new file mode 100644
index 0000000000..d0a2f3c174
--- /dev/null
+++ b/src/dbus/qdbusunixfiledescriptor.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the FOO module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QDBUSUNIXFILEDESCRIPTOR_H
+#define QDBUSUNIXFILEDESCRIPTOR_H
+
+#include <QtCore/QSharedDataPointer>
+#include <QtDBus/qdbusmacros.h>
+
+#ifndef QT_NO_DBUS
+
+#ifdef Q_COMPILER_RVALUE_REFS
+# include <utility>
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(DBus)
+
+class QDBusUnixFileDescriptorPrivate;
+template<> QExplicitlySharedDataPointer<QDBusUnixFileDescriptorPrivate>::~QExplicitlySharedDataPointer();
+
+class Q_DBUS_EXPORT QDBusUnixFileDescriptor
+{
+public:
+ QDBusUnixFileDescriptor();
+ explicit QDBusUnixFileDescriptor(int fileDescriptor);
+ QDBusUnixFileDescriptor(const QDBusUnixFileDescriptor &other);
+ QDBusUnixFileDescriptor &operator=(const QDBusUnixFileDescriptor &other);
+ ~QDBusUnixFileDescriptor();
+
+ bool isValid() const;
+
+ int fileDescriptor() const;
+ void setFileDescriptor(int fileDescriptor);
+
+ void giveFileDescriptor(int fileDescriptor);
+ int takeFileDescriptor();
+
+ static bool isSupported();
+
+#if defined(Q_COMPILER_RVALUE_REFS)
+ QDBusUnixFileDescriptor(QDBusUnixFileDescriptor &&other) : d(static_cast<Data &&>(other.d))
+ { }
+ inline QDBusUnixFileDescriptor &operator=(QDBusUnixFileDescriptor &&other)
+ { d.swap(other.d); return *this; }
+#endif
+
+protected:
+ typedef QExplicitlySharedDataPointer<QDBusUnixFileDescriptorPrivate> Data;
+ Data d;
+};
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QDBusUnixFileDescriptor)
+Q_DECLARE_METATYPE(QList<QDBusUnixFileDescriptor>)
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif // QDBUSUNIXFILEDESCRIPTOR_H
diff --git a/src/dbus/qdbusutil.cpp b/src/dbus/qdbusutil.cpp
new file mode 100644
index 0000000000..a4bd16864e
--- /dev/null
+++ b/src/dbus/qdbusutil.cpp
@@ -0,0 +1,568 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusutil_p.h"
+
+#include "qdbus_symbols_p.h"
+
+#include <QtCore/qstringlist.h>
+
+#include "qdbusargument.h"
+#include "qdbusunixfiledescriptor.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+static inline bool isValidCharacterNoDash(const QChar &c)
+{
+ register ushort u = c.unicode();
+ return (u >= 'a' && u <= 'z')
+ || (u >= 'A' && u <= 'Z')
+ || (u >= '0' && u <= '9')
+ || (u == '_');
+}
+
+static inline bool isValidCharacter(const QChar &c)
+{
+ register ushort u = c.unicode();
+ return (u >= 'a' && u <= 'z')
+ || (u >= 'A' && u <= 'Z')
+ || (u >= '0' && u <= '9')
+ || (u == '_') || (u == '-');
+}
+
+static inline bool isValidNumber(const QChar &c)
+{
+ register ushort u = c.unicode();
+ return (u >= '0' && u <= '9');
+}
+
+static bool argToString(const QDBusArgument &arg, QString &out);
+
+static bool variantToString(const QVariant &arg, QString &out)
+{
+ int argType = arg.userType();
+
+ if (argType == QVariant::StringList) {
+ out += QLatin1Char('{');
+ QStringList list = arg.toStringList();
+ foreach (QString item, list)
+ out += QLatin1Char('\"') + item + QLatin1String("\", ");
+ if (!list.isEmpty())
+ out.chop(2);
+ out += QLatin1Char('}');
+ } else if (argType == QVariant::ByteArray) {
+ out += QLatin1Char('{');
+ QByteArray list = arg.toByteArray();
+ for (int i = 0; i < list.count(); ++i) {
+ out += QString::number(list.at(i));
+ out += QLatin1String(", ");
+ }
+ if (!list.isEmpty())
+ out.chop(2);
+ out += QLatin1Char('}');
+ } else if (argType == QVariant::List) {
+ out += QLatin1Char('{');
+ QList<QVariant> list = arg.toList();
+ foreach (QVariant item, list) {
+ if (!variantToString(item, out))
+ return false;
+ out += QLatin1String(", ");
+ }
+ if (!list.isEmpty())
+ out.chop(2);
+ out += QLatin1Char('}');
+ } else if (argType == QMetaType::Char || argType == QMetaType::Short || argType == QMetaType::Int
+ || argType == QMetaType::Long || argType == QMetaType::LongLong) {
+ out += QString::number(arg.toLongLong());
+ } else if (argType == QMetaType::UChar || argType == QMetaType::UShort || argType == QMetaType::UInt
+ || argType == QMetaType::ULong || argType == QMetaType::ULongLong) {
+ out += QString::number(arg.toULongLong());
+ } else if (argType == QMetaType::Double) {
+ out += QString::number(arg.toDouble());
+ } else if (argType == QMetaType::Bool) {
+ out += QLatin1String(arg.toBool() ? "true" : "false");
+ } else if (argType == qMetaTypeId<QDBusArgument>()) {
+ argToString(qvariant_cast<QDBusArgument>(arg), out);
+ } else if (argType == qMetaTypeId<QDBusObjectPath>()) {
+ const QString path = qvariant_cast<QDBusObjectPath>(arg).path();
+ out += QLatin1String("[ObjectPath: ");
+ out += path;
+ out += QLatin1Char(']');
+ } else if (argType == qMetaTypeId<QDBusSignature>()) {
+ out += QLatin1String("[Signature: ") + qvariant_cast<QDBusSignature>(arg).signature();
+ out += QLatin1Char(']');
+ } else if (argType == qMetaTypeId<QDBusUnixFileDescriptor>()) {
+ out += QLatin1String("[Unix FD: ");
+ out += QLatin1String(qvariant_cast<QDBusUnixFileDescriptor>(arg).isValid() ? "valid" : "not valid");
+ out += QLatin1Char(']');
+ } else if (argType == qMetaTypeId<QDBusVariant>()) {
+ const QVariant v = qvariant_cast<QDBusVariant>(arg).variant();
+ out += QLatin1String("[Variant");
+ int vUserType = v.userType();
+ if (vUserType != qMetaTypeId<QDBusVariant>()
+ && vUserType != qMetaTypeId<QDBusSignature>()
+ && vUserType != qMetaTypeId<QDBusObjectPath>()
+ && vUserType != qMetaTypeId<QDBusArgument>())
+ out += QLatin1Char('(') + QLatin1String(v.typeName()) + QLatin1Char(')');
+ out += QLatin1String(": ");
+ if (!variantToString(v, out))
+ return false;
+ out += QLatin1Char(']');
+ } else if (arg.canConvert(QVariant::String)) {
+ out += QLatin1Char('\"') + arg.toString() + QLatin1Char('\"');
+ } else {
+ out += QLatin1Char('[');
+ out += QLatin1String(arg.typeName());
+ out += QLatin1Char(']');
+ }
+
+ return true;
+}
+
+bool argToString(const QDBusArgument &busArg, QString &out)
+{
+ QString busSig = busArg.currentSignature();
+ bool doIterate = false;
+ QDBusArgument::ElementType elementType = busArg.currentType();
+
+ if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
+ && elementType != QDBusArgument::MapEntryType)
+ out += QLatin1String("[Argument: ") + busSig + QLatin1Char(' ');
+
+ switch (elementType) {
+ case QDBusArgument::BasicType:
+ case QDBusArgument::VariantType:
+ if (!variantToString(busArg.asVariant(), out))
+ return false;
+ break;
+ case QDBusArgument::StructureType:
+ busArg.beginStructure();
+ doIterate = true;
+ break;
+ case QDBusArgument::ArrayType:
+ busArg.beginArray();
+ out += QLatin1Char('{');
+ doIterate = true;
+ break;
+ case QDBusArgument::MapType:
+ busArg.beginMap();
+ out += QLatin1Char('{');
+ doIterate = true;
+ break;
+ case QDBusArgument::MapEntryType:
+ busArg.beginMapEntry();
+ if (!variantToString(busArg.asVariant(), out))
+ return false;
+ out += QLatin1String(" = ");
+ if (!argToString(busArg, out))
+ return false;
+ busArg.endMapEntry();
+ break;
+ case QDBusArgument::UnknownType:
+ default:
+ out += QLatin1String("<ERROR - Unknown Type>");
+ return false;
+ }
+ if (doIterate && !busArg.atEnd()) {
+ while (!busArg.atEnd()) {
+ if (!argToString(busArg, out))
+ return false;
+ out += QLatin1String(", ");
+ }
+ out.chop(2);
+ }
+ switch (elementType) {
+ case QDBusArgument::BasicType:
+ case QDBusArgument::VariantType:
+ case QDBusArgument::UnknownType:
+ case QDBusArgument::MapEntryType:
+ // nothing to do
+ break;
+ case QDBusArgument::StructureType:
+ busArg.endStructure();
+ break;
+ case QDBusArgument::ArrayType:
+ out += QLatin1Char('}');
+ busArg.endArray();
+ break;
+ case QDBusArgument::MapType:
+ out += QLatin1Char('}');
+ busArg.endMap();
+ break;
+ }
+
+ if (elementType != QDBusArgument::BasicType && elementType != QDBusArgument::VariantType
+ && elementType != QDBusArgument::MapEntryType)
+ out += QLatin1Char(']');
+
+ return true;
+}
+
+//------- D-Bus Types --------
+static const char oneLetterTypes[] = "vsogybnqiuxtdh";
+static const char basicTypes[] = "sogybnqiuxtdh";
+static const char fixedTypes[] = "ybnqiuxtdh";
+
+static bool isBasicType(int c)
+{
+ return c != DBUS_TYPE_INVALID && strchr(basicTypes, c) != NULL;
+}
+
+static bool isFixedType(int c)
+{
+ return c != DBUS_TYPE_INVALID && strchr(fixedTypes, c) != NULL;
+}
+
+// Returns a pointer to one-past-end of this type if it's valid;
+// returns NULL if it isn't valid.
+static const char *validateSingleType(const char *signature)
+{
+ register char c = *signature;
+ if (c == DBUS_TYPE_INVALID)
+ return false;
+
+ // is it one of the one-letter types?
+ if (strchr(oneLetterTypes, c) != NULL)
+ return signature + 1;
+
+ // is it an array?
+ if (c == DBUS_TYPE_ARRAY) {
+ // then it's valid if the next type is valid
+ // or if it's a dict-entry
+ c = *++signature;
+ if (c == DBUS_DICT_ENTRY_BEGIN_CHAR) {
+ // beginning of a dictionary entry
+ // a dictionary entry has a key which is of basic types
+ // and a free value
+ c = *++signature;
+ if (!isBasicType(c))
+ return 0;
+ signature = validateSingleType(signature + 1);
+ return signature && *signature == DBUS_DICT_ENTRY_END_CHAR ? signature + 1 : 0;
+ }
+
+ return validateSingleType(signature);
+ }
+
+ if (c == DBUS_STRUCT_BEGIN_CHAR) {
+ // beginning of a struct
+ ++signature;
+ while (true) {
+ signature = validateSingleType(signature);
+ if (!signature)
+ return 0;
+ if (*signature == DBUS_STRUCT_END_CHAR)
+ return signature + 1;
+ }
+ }
+
+ // invalid/unknown type
+ return 0;
+}
+
+/*!
+ \namespace QDBusUtil
+ \inmodule QtDBus
+ \internal
+
+ \brief The QDBusUtil namespace contains a few functions that are of general use when
+ dealing with D-Bus strings.
+*/
+namespace QDBusUtil
+{
+ /*!
+ \internal
+ \since 4.5
+ Dumps the contents of a QtDBus argument from \a arg into a string.
+ */
+ QString argumentToString(const QVariant &arg)
+ {
+ QString out;
+
+ variantToString(arg, out);
+
+ return out;
+ }
+
+ /*!
+ \internal
+ \fn bool QDBusUtil::isValidPartOfObjectPath(const QString &part)
+ See QDBusUtil::isValidObjectPath
+ */
+ bool isValidPartOfObjectPath(const QString &part)
+ {
+ if (part.isEmpty())
+ return false; // can't be valid if it's empty
+
+ const QChar *c = part.unicode();
+ for (int i = 0; i < part.length(); ++i)
+ if (!isValidCharacterNoDash(c[i]))
+ return false;
+
+ return true;
+ }
+
+ /*!
+ \fn bool QDBusUtil::isValidInterfaceName(const QString &ifaceName)
+ Returns true if this is \a ifaceName is a valid interface name.
+
+ Valid interface names must:
+ \list
+ \o not be empty
+ \o not exceed 255 characters in length
+ \o be composed of dot-separated string components that contain only ASCII letters, digits
+ and the underscore ("_") character
+ \o contain at least two such components
+ \endlist
+ */
+ bool isValidInterfaceName(const QString& ifaceName)
+ {
+ if (ifaceName.isEmpty() || ifaceName.length() > DBUS_MAXIMUM_NAME_LENGTH)
+ return false;
+
+ QStringList parts = ifaceName.split(QLatin1Char('.'));
+ if (parts.count() < 2)
+ return false; // at least two parts
+
+ for (int i = 0; i < parts.count(); ++i)
+ if (!isValidMemberName(parts.at(i)))
+ return false;
+
+ return true;
+ }
+
+ /*!
+ \fn bool QDBusUtil::isValidUniqueConnectionName(const QString &connName)
+ Returns true if \a connName is a valid unique connection name.
+
+ Unique connection names start with a colon (":") and are followed by a list of dot-separated
+ components composed of ASCII letters, digits, the hyphen or the underscore ("_") character.
+ */
+ bool isValidUniqueConnectionName(const QString &connName)
+ {
+ if (connName.isEmpty() || connName.length() > DBUS_MAXIMUM_NAME_LENGTH ||
+ !connName.startsWith(QLatin1Char(':')))
+ return false;
+
+ QStringList parts = connName.mid(1).split(QLatin1Char('.'));
+ if (parts.count() < 1)
+ return false;
+
+ for (int i = 0; i < parts.count(); ++i) {
+ const QString &part = parts.at(i);
+ if (part.isEmpty())
+ return false;
+
+ const QChar* c = part.unicode();
+ for (int j = 0; j < part.length(); ++j)
+ if (!isValidCharacter(c[j]))
+ return false;
+ }
+
+ return true;
+ }
+
+ /*!
+ \fn bool QDBusUtil::isValidBusName(const QString &busName)
+ Returns true if \a busName is a valid bus name.
+
+ A valid bus name is either a valid unique connection name or follows the rules:
+ \list
+ \o is not empty
+ \o does not exceed 255 characters in length
+ \o be composed of dot-separated string components that contain only ASCII letters, digits,
+ hyphens or underscores ("_"), but don't start with a digit
+ \o contains at least two such elements
+ \endlist
+
+ \sa isValidUniqueConnectionName()
+ */
+ bool isValidBusName(const QString &busName)
+ {
+ if (busName.isEmpty() || busName.length() > DBUS_MAXIMUM_NAME_LENGTH)
+ return false;
+
+ if (busName.startsWith(QLatin1Char(':')))
+ return isValidUniqueConnectionName(busName);
+
+ QStringList parts = busName.split(QLatin1Char('.'));
+ if (parts.count() < 1)
+ return false;
+
+ for (int i = 0; i < parts.count(); ++i) {
+ const QString &part = parts.at(i);
+ if (part.isEmpty())
+ return false;
+
+ const QChar *c = part.unicode();
+ if (isValidNumber(c[0]))
+ return false;
+ for (int j = 0; j < part.length(); ++j)
+ if (!isValidCharacter(c[j]))
+ return false;
+ }
+
+ return true;
+ }
+
+ /*!
+ \fn bool QDBusUtil::isValidMemberName(const QString &memberName)
+ Returns true if \a memberName is a valid member name. A valid member name does not exceed
+ 255 characters in length, is not empty, is composed only of ASCII letters, digits and
+ underscores, but does not start with a digit.
+ */
+ bool isValidMemberName(const QString &memberName)
+ {
+ if (memberName.isEmpty() || memberName.length() > DBUS_MAXIMUM_NAME_LENGTH)
+ return false;
+
+ const QChar* c = memberName.unicode();
+ if (isValidNumber(c[0]))
+ return false;
+ for (int j = 0; j < memberName.length(); ++j)
+ if (!isValidCharacterNoDash(c[j]))
+ return false;
+ return true;
+ }
+
+ /*!
+ \fn bool QDBusUtil::isValidErrorName(const QString &errorName)
+ Returns true if \a errorName is a valid error name. Valid error names are valid interface
+ names and vice-versa, so this function is actually an alias for isValidInterfaceName.
+ */
+ bool isValidErrorName(const QString &errorName)
+ {
+ return isValidInterfaceName(errorName);
+ }
+
+ /*!
+ \fn bool QDBusUtil::isValidObjectPath(const QString &path)
+ Returns true if \a path is valid object path.
+
+ Valid object paths follow the rules:
+ \list
+ \o start with the slash character ("/")
+ \o do not end in a slash, unless the path is just the initial slash
+ \o do not contain any two slashes in sequence
+ \o contain slash-separated parts, each of which is composed of ASCII letters, digits and
+ underscores ("_")
+ \endlist
+ */
+ bool isValidObjectPath(const QString &path)
+ {
+ if (path == QLatin1String("/"))
+ return true;
+
+ if (!path.startsWith(QLatin1Char('/')) || path.indexOf(QLatin1String("//")) != -1 ||
+ path.endsWith(QLatin1Char('/')))
+ return false;
+
+ QStringList parts = path.split(QLatin1Char('/'));
+ Q_ASSERT(parts.count() >= 1);
+ parts.removeFirst(); // it starts with /, so we get an empty first part
+
+ for (int i = 0; i < parts.count(); ++i)
+ if (!isValidPartOfObjectPath(parts.at(i)))
+ return false;
+
+ return true;
+ }
+
+ /*!
+ \fn bool QDBusUtil::isValidBasicType(int type)
+ Returns true if \a c is a valid, basic D-Bus type.
+ */
+ bool isValidBasicType(int c)
+ {
+ return isBasicType(c);
+ }
+
+ /*!
+ \fn bool QDBusUtil::isValidFixedType(int type)
+ Returns true if \a c is a valid, fixed D-Bus type.
+ */
+ bool isValidFixedType(int c)
+ {
+ return isFixedType(c);
+ }
+
+
+ /*!
+ \fn bool QDBusUtil::isValidSignature(const QString &signature)
+ Returns true if \a signature is a valid D-Bus type signature for one or more types.
+ This function returns true if it can all of \a signature into valid, individual types and no
+ characters remain in \a signature.
+
+ \sa isValidSingleSignature()
+ */
+ bool isValidSignature(const QString &signature)
+ {
+ QByteArray ba = signature.toLatin1();
+ const char *data = ba.constData();
+ while (true) {
+ data = validateSingleType(data);
+ if (!data)
+ return false;
+ if (*data == '\0')
+ return true;
+ }
+ }
+
+ /*!
+ \fn bool QDBusUtil::isValidSingleSignature(const QString &signature)
+ Returns true if \a signature is a valid D-Bus type signature for exactly one full type. This
+ function tries to convert the type signature into a D-Bus type and, if it succeeds and no
+ characters remain in the signature, it returns true.
+ */
+ bool isValidSingleSignature(const QString &signature)
+ {
+ QByteArray ba = signature.toLatin1();
+ const char *data = validateSingleType(ba.constData());
+ return data && *data == '\0';
+ }
+
+} // namespace QDBusUtil
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusutil_p.h b/src/dbus/qdbusutil_p.h
new file mode 100644
index 0000000000..24b5cea847
--- /dev/null
+++ b/src/dbus/qdbusutil_p.h
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QDBUSUTIL_H
+#define QDBUSUTIL_H
+
+#include <QtCore/qstring.h>
+#include <QtCore/qvariant.h>
+
+#include <QtDBus/qdbusmacros.h>
+#include <QtDBus/qdbuserror.h>
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+namespace QDBusUtil
+{
+ Q_DBUS_EXPORT bool isValidInterfaceName(const QString &ifaceName);
+
+ Q_DBUS_EXPORT bool isValidUniqueConnectionName(const QString &busName);
+
+ Q_DBUS_EXPORT bool isValidBusName(const QString &busName);
+
+ Q_DBUS_EXPORT bool isValidMemberName(const QString &memberName);
+
+ Q_DBUS_EXPORT bool isValidErrorName(const QString &errorName);
+
+ Q_DBUS_EXPORT bool isValidPartOfObjectPath(const QString &path);
+
+ Q_DBUS_EXPORT bool isValidObjectPath(const QString &path);
+
+ Q_DBUS_EXPORT bool isValidFixedType(int c);
+
+ Q_DBUS_EXPORT bool isValidBasicType(int c);
+
+ Q_DBUS_EXPORT bool isValidSignature(const QString &signature);
+
+ Q_DBUS_EXPORT bool isValidSingleSignature(const QString &signature);
+
+ Q_DBUS_EXPORT QString argumentToString(const QVariant &variant);
+
+ enum AllowEmptyFlag {
+ EmptyAllowed,
+ EmptyNotAllowed
+ };
+
+ inline bool checkInterfaceName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
+ {
+ if (name.isEmpty()) {
+ if (empty == EmptyAllowed) return true;
+ *error = QDBusError(QDBusError::InvalidInterface, QLatin1String("Interface name cannot be empty"));
+ return false;
+ }
+ if (isValidInterfaceName(name)) return true;
+ *error = QDBusError(QDBusError::InvalidInterface, QString::fromLatin1("Invalid interface class: %1").arg(name));
+ return false;
+ }
+
+ inline bool checkBusName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
+ {
+ if (name.isEmpty()) {
+ if (empty == EmptyAllowed) return true;
+ *error = QDBusError(QDBusError::InvalidService, QLatin1String("Service name cannot be empty"));
+ return false;
+ }
+ if (isValidBusName(name)) return true;
+ *error = QDBusError(QDBusError::InvalidService, QString::fromLatin1("Invalid service name: %1").arg(name));
+ return false;
+ }
+
+ inline bool checkObjectPath(const QString &path, AllowEmptyFlag empty, QDBusError *error)
+ {
+ if (path.isEmpty()) {
+ if (empty == EmptyAllowed) return true;
+ *error = QDBusError(QDBusError::InvalidObjectPath, QLatin1String("Object path cannot be empty"));
+ return false;
+ }
+ if (isValidObjectPath(path)) return true;
+ *error = QDBusError(QDBusError::InvalidObjectPath, QString::fromLatin1("Invalid object path: %1").arg(path));
+ return false;
+ }
+
+ inline bool checkMemberName(const QString &name, AllowEmptyFlag empty, QDBusError *error, const char *nameType = 0)
+ {
+ if (!nameType) nameType = "member";
+ if (name.isEmpty()) {
+ if (empty == EmptyAllowed) return true;
+ *error = QDBusError(QDBusError::InvalidMember, QLatin1String(nameType) + QLatin1String(" name cannot be empty"));
+ return false;
+ }
+ if (isValidMemberName(name)) return true;
+ *error = QDBusError(QDBusError::InvalidMember, QString::fromLatin1("Invalid %1 name: %2")
+ .arg(QString::fromLatin1(nameType), name));
+ return false;
+ }
+
+ inline bool checkErrorName(const QString &name, AllowEmptyFlag empty, QDBusError *error)
+ {
+ if (name.isEmpty()) {
+ if (empty == EmptyAllowed) return true;
+ *error = QDBusError(QDBusError::InvalidInterface, QLatin1String("Error name cannot be empty"));
+ return false;
+ }
+ if (isValidErrorName(name)) return true;
+ *error = QDBusError(QDBusError::InvalidInterface, QString::fromLatin1("Invalid error name: %1").arg(name));
+ return false;
+ }
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+#endif
diff --git a/src/dbus/qdbusxmlgenerator.cpp b/src/dbus/qdbusxmlgenerator.cpp
new file mode 100644
index 0000000000..930290c653
--- /dev/null
+++ b/src/dbus/qdbusxmlgenerator.cpp
@@ -0,0 +1,308 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qstringlist.h>
+
+#include "qdbusinterface_p.h" // for ANNOTATION_NO_WAIT
+#include "qdbusabstractadaptor_p.h" // for QCLASSINFO_DBUS_*
+#include "qdbusconnection_p.h" // for the flags
+#include "qdbusmetatype_p.h"
+#include "qdbusmetatype.h"
+#include "qdbusutil_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+extern Q_DBUS_EXPORT QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
+ const QMetaObject *base, int flags);
+
+static inline QString typeNameToXml(const char *typeName)
+{
+ // ### copied from qtextdocument.cpp
+ // ### move this into QtCore at some point
+ QString plain = QLatin1String(typeName);
+ QString rich;
+ rich.reserve(int(plain.length() * 1.1));
+ for (int i = 0; i < plain.length(); ++i) {
+ if (plain.at(i) == QLatin1Char('<'))
+ rich += QLatin1String("&lt;");
+ else if (plain.at(i) == QLatin1Char('>'))
+ rich += QLatin1String("&gt;");
+ else if (plain.at(i) == QLatin1Char('&'))
+ rich += QLatin1String("&amp;");
+ else
+ rich += plain.at(i);
+ }
+ return rich;
+}
+
+// implement the D-Bus org.freedesktop.DBus.Introspectable interface
+// we do that by analysing the metaObject of all the adaptor interfaces
+
+static QString generateInterfaceXml(const QMetaObject *mo, int flags, int methodOffset, int propOffset)
+{
+ QString retval;
+
+ // start with properties:
+ if (flags & (QDBusConnection::ExportScriptableProperties |
+ QDBusConnection::ExportNonScriptableProperties)) {
+ for (int i = propOffset; i < mo->propertyCount(); ++i) {
+ static const char *accessvalues[] = {0, "read", "write", "readwrite"};
+
+ QMetaProperty mp = mo->property(i);
+
+ if (!((mp.isScriptable() && (flags & QDBusConnection::ExportScriptableProperties)) ||
+ (!mp.isScriptable() && (flags & QDBusConnection::ExportNonScriptableProperties))))
+ continue;
+
+ int access = 0;
+ if (mp.isReadable())
+ access |= 1;
+ if (mp.isWritable())
+ access |= 2;
+
+ int typeId = qDBusNameToTypeId(mp.typeName());
+ if (!typeId)
+ continue;
+ const char *signature = QDBusMetaType::typeToSignature(typeId);
+ if (!signature)
+ continue;
+
+ retval += QString::fromLatin1(" <property name=\"%1\" type=\"%2\" access=\"%3\"")
+ .arg(QLatin1String(mp.name()))
+ .arg(QLatin1String(signature))
+ .arg(QLatin1String(accessvalues[access]));
+
+ if (QDBusMetaType::signatureToType(signature) == QVariant::Invalid) {
+ const char *typeName = QVariant::typeToName(QVariant::Type(typeId));
+ retval += QString::fromLatin1(">\n <annotation name=\"com.trolltech.QtDBus.QtTypeName\" value=\"%3\"/>\n </property>\n")
+ .arg(typeNameToXml(typeName));
+ } else {
+ retval += QLatin1String("/>\n");
+ }
+ }
+ }
+
+ // now add methods:
+ for (int i = methodOffset; i < mo->methodCount(); ++i) {
+ QMetaMethod mm = mo->method(i);
+ QByteArray signature = mm.signature();
+ int paren = signature.indexOf('(');
+
+ bool isSignal;
+ if (mm.methodType() == QMetaMethod::Signal)
+ // adding a signal
+ isSignal = true;
+ else if (mm.access() == QMetaMethod::Public && (mm.methodType() == QMetaMethod::Slot || mm.methodType() == QMetaMethod::Method))
+ isSignal = false;
+ else
+ continue; // neither signal nor public slot
+
+ if (isSignal && !(flags & (QDBusConnection::ExportScriptableSignals |
+ QDBusConnection::ExportNonScriptableSignals)))
+ continue; // we're not exporting any signals
+ if (!isSignal && (!(flags & (QDBusConnection::ExportScriptableSlots | QDBusConnection::ExportNonScriptableSlots)) &&
+ !(flags & (QDBusConnection::ExportScriptableInvokables | QDBusConnection::ExportNonScriptableInvokables))))
+ continue; // we're not exporting any slots or invokables
+
+ QString xml = QString::fromLatin1(" <%1 name=\"%2\">\n")
+ .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"))
+ .arg(QLatin1String(signature.left(paren)));
+
+ // check the return type first
+ int typeId = qDBusNameToTypeId(mm.typeName());
+ if (typeId) {
+ const char *typeName = QDBusMetaType::typeToSignature(typeId);
+ if (typeName) {
+ xml += QString::fromLatin1(" <arg type=\"%1\" direction=\"out\"/>\n")
+ .arg(typeNameToXml(typeName));
+
+ // do we need to describe this argument?
+ if (QDBusMetaType::signatureToType(typeName) == QVariant::Invalid)
+ xml += QString::fromLatin1(" <annotation name=\"com.trolltech.QtDBus.QtTypeName.Out0\" value=\"%1\"/>\n")
+ .arg(typeNameToXml(QVariant::typeToName(QVariant::Type(typeId))));
+ } else
+ continue;
+ }
+ else if (*mm.typeName())
+ continue; // wasn't a valid type
+
+ QList<QByteArray> names = mm.parameterNames();
+ QList<int> types;
+ int inputCount = qDBusParametersForMethod(mm, types);
+ if (inputCount == -1)
+ continue; // invalid form
+ if (isSignal && inputCount + 1 != types.count())
+ continue; // signal with output arguments?
+ if (isSignal && types.at(inputCount) == QDBusMetaTypeId::message)
+ continue; // signal with QDBusMessage argument?
+ if (isSignal && mm.attributes() & QMetaMethod::Cloned)
+ continue; // cloned signal?
+
+ int j;
+ bool isScriptable = mm.attributes() & QMetaMethod::Scriptable;
+ for (j = 1; j < types.count(); ++j) {
+ // input parameter for a slot or output for a signal
+ if (types.at(j) == QDBusMetaTypeId::message) {
+ isScriptable = true;
+ continue;
+ }
+
+ QString name;
+ if (!names.at(j - 1).isEmpty())
+ name = QString::fromLatin1("name=\"%1\" ").arg(QLatin1String(names.at(j - 1)));
+
+ bool isOutput = isSignal || j > inputCount;
+
+ const char *signature = QDBusMetaType::typeToSignature(types.at(j));
+ xml += QString::fromLatin1(" <arg %1type=\"%2\" direction=\"%3\"/>\n")
+ .arg(name)
+ .arg(QLatin1String(signature))
+ .arg(isOutput ? QLatin1String("out") : QLatin1String("in"));
+
+ // do we need to describe this argument?
+ if (QDBusMetaType::signatureToType(signature) == QVariant::Invalid) {
+ const char *typeName = QVariant::typeToName( QVariant::Type(types.at(j)) );
+ xml += QString::fromLatin1(" <annotation name=\"com.trolltech.QtDBus.QtTypeName.%1%2\" value=\"%3\"/>\n")
+ .arg(isOutput ? QLatin1String("Out") : QLatin1String("In"))
+ .arg(isOutput && !isSignal ? j - inputCount : j - 1)
+ .arg(typeNameToXml(typeName));
+ }
+ }
+
+ int wantedMask;
+ if (isScriptable)
+ wantedMask = isSignal ? QDBusConnection::ExportScriptableSignals
+ : QDBusConnection::ExportScriptableSlots;
+ else
+ wantedMask = isSignal ? QDBusConnection::ExportNonScriptableSignals
+ : QDBusConnection::ExportNonScriptableSlots;
+ if ((flags & wantedMask) != wantedMask)
+ continue;
+
+ if (qDBusCheckAsyncTag(mm.tag()))
+ // add the no-reply annotation
+ xml += QLatin1String(" <annotation name=\"" ANNOTATION_NO_WAIT "\""
+ " value=\"true\"/>\n");
+
+ retval += xml;
+ retval += QString::fromLatin1(" </%1>\n")
+ .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"));
+ }
+
+ return retval;
+}
+
+QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
+ const QMetaObject *base, int flags)
+{
+ if (interface.isEmpty())
+ // generate the interface name from the meta object
+ interface = qDBusInterfaceFromMetaObject(mo);
+
+ QString xml;
+ int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTROSPECTION);
+ if (idx >= mo->classInfoOffset())
+ return QString::fromUtf8(mo->classInfo(idx).value());
+ else
+ xml = generateInterfaceXml(mo, flags, base->methodCount(), base->propertyCount());
+
+ if (xml.isEmpty())
+ return QString(); // don't add an empty interface
+ return QString::fromLatin1(" <interface name=\"%1\">\n%2 </interface>\n")
+ .arg(interface, xml);
+}
+#if 0
+QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo, const QMetaObject *base,
+ int flags)
+{
+ if (interface.isEmpty()) {
+ // generate the interface name from the meta object
+ int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
+ if (idx >= mo->classInfoOffset()) {
+ interface = QLatin1String(mo->classInfo(idx).value());
+ } else {
+ interface = QLatin1String(mo->className());
+ interface.replace(QLatin1String("::"), QLatin1String("."));
+
+ if (interface.startsWith(QLatin1String("QDBus"))) {
+ interface.prepend(QLatin1String("com.trolltech.QtDBus."));
+ } else if (interface.startsWith(QLatin1Char('Q')) &&
+ interface.length() >= 2 && interface.at(1).isUpper()) {
+ // assume it's Qt
+ interface.prepend(QLatin1String("com.trolltech.Qt."));
+ } else if (!QCoreApplication::instance()||
+ QCoreApplication::instance()->applicationName().isEmpty()) {
+ interface.prepend(QLatin1String("local."));
+ } else {
+ interface.prepend(QLatin1Char('.')).prepend(QCoreApplication::instance()->applicationName());
+ QStringList domainName =
+ QCoreApplication::instance()->organizationDomain().split(QLatin1Char('.'),
+ QString::SkipEmptyParts);
+ if (domainName.isEmpty())
+ interface.prepend(QLatin1String("local."));
+ else
+ for (int i = 0; i < domainName.count(); ++i)
+ interface.prepend(QLatin1Char('.')).prepend(domainName.at(i));
+ }
+ }
+ }
+
+ QString xml;
+ int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTROSPECTION);
+ if (idx >= mo->classInfoOffset())
+ return QString::fromUtf8(mo->classInfo(idx).value());
+ else
+ xml = generateInterfaceXml(mo, flags, base->methodCount(), base->propertyCount());
+
+ if (xml.isEmpty())
+ return QString(); // don't add an empty interface
+ return QString::fromLatin1(" <interface name=\"%1\">\n%2 </interface>\n")
+ .arg(interface, xml);
+}
+
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusxmlparser.cpp b/src/dbus/qdbusxmlparser.cpp
new file mode 100644
index 0000000000..3feeddec5a
--- /dev/null
+++ b/src/dbus/qdbusxmlparser.cpp
@@ -0,0 +1,378 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdbusxmlparser_p.h"
+#include "qdbusinterface.h"
+#include "qdbusinterface_p.h"
+#include "qdbusconnection_p.h"
+#include "qdbusutil_p.h"
+
+#include <QtXml/qdom.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qtextstream.h>
+
+#ifndef QT_NO_DBUS
+
+//#define QDBUS_PARSER_DEBUG
+#ifdef QDBUS_PARSER_DEBUG
+# define qDBusParserError qWarning
+#else
+# define qDBusParserError if (true) {} else qDebug
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static QDBusIntrospection::Annotations
+parseAnnotations(const QDomElement& elem)
+{
+ QDBusIntrospection::Annotations retval;
+ QDomNodeList list = elem.elementsByTagName(QLatin1String("annotation"));
+ for (int i = 0; i < list.count(); ++i)
+ {
+ QDomElement ann = list.item(i).toElement();
+ if (ann.isNull())
+ continue;
+
+ QString name = ann.attribute(QLatin1String("name")),
+ value = ann.attribute(QLatin1String("value"));
+
+ if (!QDBusUtil::isValidInterfaceName(name)) {
+ qDBusParserError("Invalid D-BUS annotation '%s' found while parsing introspection",
+ qPrintable(name));
+ continue;
+ }
+
+ retval.insert(name, value);
+ }
+
+ return retval;
+}
+
+static QDBusIntrospection::Arguments
+parseArgs(const QDomElement& elem, const QLatin1String& direction, bool acceptEmpty)
+{
+ QDBusIntrospection::Arguments retval;
+ QDomNodeList list = elem.elementsByTagName(QLatin1String("arg"));
+ for (int i = 0; i < list.count(); ++i)
+ {
+ QDomElement arg = list.item(i).toElement();
+ if (arg.isNull())
+ continue;
+
+ if ((acceptEmpty && !arg.hasAttribute(QLatin1String("direction"))) ||
+ arg.attribute(QLatin1String("direction")) == direction) {
+
+ QDBusIntrospection::Argument argData;
+ if (arg.hasAttribute(QLatin1String("name")))
+ argData.name = arg.attribute(QLatin1String("name")); // can be empty
+ argData.type = arg.attribute(QLatin1String("type"));
+ if (!QDBusUtil::isValidSingleSignature(argData.type)) {
+ qDBusParserError("Invalid D-BUS type signature '%s' found while parsing introspection",
+ qPrintable(argData.type));
+ }
+
+ retval << argData;
+ }
+ }
+ return retval;
+}
+
+QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
+ const QString& xmlData)
+ : m_service(service), m_path(path)
+{
+ QDomDocument doc;
+ doc.setContent(xmlData);
+ m_node = doc.firstChildElement(QLatin1String("node"));
+}
+
+QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
+ const QDomElement& node)
+ : m_service(service), m_path(path), m_node(node)
+{
+}
+
+QDBusIntrospection::Interfaces
+QDBusXmlParser::interfaces() const
+{
+ QDBusIntrospection::Interfaces retval;
+
+ if (m_node.isNull())
+ return retval;
+
+ QDomNodeList interfaceList = m_node.elementsByTagName(QLatin1String("interface"));
+ for (int i = 0; i < interfaceList.count(); ++i)
+ {
+ QDomElement iface = interfaceList.item(i).toElement();
+ QString ifaceName = iface.attribute(QLatin1String("name"));
+ if (iface.isNull())
+ continue; // for whatever reason
+ if (!QDBusUtil::isValidInterfaceName(ifaceName)) {
+ qDBusParserError("Invalid D-BUS interface name '%s' found while parsing introspection",
+ qPrintable(ifaceName));
+ continue;
+ }
+
+ QDBusIntrospection::Interface *ifaceData = new QDBusIntrospection::Interface;
+ ifaceData->name = ifaceName;
+ {
+ // save the data
+ QTextStream ts(&ifaceData->introspection);
+ iface.save(ts,2);
+ }
+
+ // parse annotations
+ ifaceData->annotations = parseAnnotations(iface);
+
+ // parse methods
+ QDomNodeList list = iface.elementsByTagName(QLatin1String("method"));
+ for (int j = 0; j < list.count(); ++j)
+ {
+ QDomElement method = list.item(j).toElement();
+ QString methodName = method.attribute(QLatin1String("name"));
+ if (method.isNull())
+ continue;
+ if (!QDBusUtil::isValidMemberName(methodName)) {
+ qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
+ qPrintable(methodName), qPrintable(ifaceName));
+ continue;
+ }
+
+ QDBusIntrospection::Method methodData;
+ methodData.name = methodName;
+
+ // parse arguments
+ methodData.inputArgs = parseArgs(method, QLatin1String("in"), true);
+ methodData.outputArgs = parseArgs(method, QLatin1String("out"), false);
+ methodData.annotations = parseAnnotations(method);
+
+ // add it
+ ifaceData->methods.insert(methodName, methodData);
+ }
+
+ // parse signals
+ list = iface.elementsByTagName(QLatin1String("signal"));
+ for (int j = 0; j < list.count(); ++j)
+ {
+ QDomElement signal = list.item(j).toElement();
+ QString signalName = signal.attribute(QLatin1String("name"));
+ if (signal.isNull())
+ continue;
+ if (!QDBusUtil::isValidMemberName(signalName)) {
+ qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
+ qPrintable(signalName), qPrintable(ifaceName));
+ continue;
+ }
+
+ QDBusIntrospection::Signal signalData;
+ signalData.name = signalName;
+
+ // parse data
+ signalData.outputArgs = parseArgs(signal, QLatin1String("out"), true);
+ signalData.annotations = parseAnnotations(signal);
+
+ // add it
+ ifaceData->signals_.insert(signalName, signalData);
+ }
+
+ // parse properties
+ list = iface.elementsByTagName(QLatin1String("property"));
+ for (int j = 0; j < list.count(); ++j)
+ {
+ QDomElement property = list.item(j).toElement();
+ QString propertyName = property.attribute(QLatin1String("name"));
+ if (property.isNull())
+ continue;
+ if (!QDBusUtil::isValidMemberName(propertyName)) {
+ qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
+ qPrintable(propertyName), qPrintable(ifaceName));
+ continue;
+ }
+
+ QDBusIntrospection::Property propertyData;
+
+ // parse data
+ propertyData.name = propertyName;
+ propertyData.type = property.attribute(QLatin1String("type"));
+ propertyData.annotations = parseAnnotations(property);
+
+ if (!QDBusUtil::isValidSingleSignature(propertyData.type)) {
+ // cannot be!
+ qDBusParserError("Invalid D-BUS type signature '%s' found in property '%s.%s' while parsing introspection",
+ qPrintable(propertyData.type), qPrintable(ifaceName),
+ qPrintable(propertyName));
+ }
+
+ QString access = property.attribute(QLatin1String("access"));
+ if (access == QLatin1String("read"))
+ propertyData.access = QDBusIntrospection::Property::Read;
+ else if (access == QLatin1String("write"))
+ propertyData.access = QDBusIntrospection::Property::Write;
+ else if (access == QLatin1String("readwrite"))
+ propertyData.access = QDBusIntrospection::Property::ReadWrite;
+ else {
+ qDBusParserError("Invalid D-BUS property access '%s' found in property '%s.%s' while parsing introspection",
+ qPrintable(access), qPrintable(ifaceName),
+ qPrintable(propertyName));
+ continue; // invalid one!
+ }
+
+ // add it
+ ifaceData->properties.insert(propertyName, propertyData);
+ }
+
+ // add it
+ retval.insert(ifaceName, QSharedDataPointer<QDBusIntrospection::Interface>(ifaceData));
+ }
+
+ return retval;
+}
+
+QSharedDataPointer<QDBusIntrospection::Object>
+QDBusXmlParser::object() const
+{
+ if (m_node.isNull())
+ return QSharedDataPointer<QDBusIntrospection::Object>();
+
+ QDBusIntrospection::Object* objData;
+ objData = new QDBusIntrospection::Object;
+ objData->service = m_service;
+ objData->path = m_path;
+
+ // check if we have anything to process
+ if (objData->introspection.isNull() && !m_node.firstChild().isNull()) {
+ // yes, introspect this object
+ QTextStream ts(&objData->introspection);
+ m_node.save(ts,2);
+
+ QDomNodeList objects = m_node.elementsByTagName(QLatin1String("node"));
+ for (int i = 0; i < objects.count(); ++i) {
+ QDomElement obj = objects.item(i).toElement();
+ QString objName = obj.attribute(QLatin1String("name"));
+ if (obj.isNull())
+ continue; // for whatever reason
+ if (!QDBusUtil::isValidObjectPath(m_path + QLatin1Char('/') + objName)) {
+ qDBusParserError("Invalid D-BUS object path '%s/%s' found while parsing introspection",
+ qPrintable(m_path), qPrintable(objName));
+ continue;
+ }
+
+ objData->childObjects.append(objName);
+ }
+
+ QDomNodeList interfaceList = m_node.elementsByTagName(QLatin1String("interface"));
+ for (int i = 0; i < interfaceList.count(); ++i) {
+ QDomElement iface = interfaceList.item(i).toElement();
+ QString ifaceName = iface.attribute(QLatin1String("name"));
+ if (iface.isNull())
+ continue;
+ if (!QDBusUtil::isValidInterfaceName(ifaceName)) {
+ qDBusParserError("Invalid D-BUS interface name '%s' found while parsing introspection",
+ qPrintable(ifaceName));
+ continue;
+ }
+
+ objData->interfaces.append(ifaceName);
+ }
+ } else {
+ objData->introspection = QLatin1String("<node/>\n");
+ }
+
+ QSharedDataPointer<QDBusIntrospection::Object> retval;
+ retval = objData;
+ return retval;
+}
+
+QSharedDataPointer<QDBusIntrospection::ObjectTree>
+QDBusXmlParser::objectTree() const
+{
+ QSharedDataPointer<QDBusIntrospection::ObjectTree> retval;
+
+ if (m_node.isNull())
+ return retval;
+
+ retval = new QDBusIntrospection::ObjectTree;
+
+ retval->service = m_service;
+ retval->path = m_path;
+
+ QTextStream ts(&retval->introspection);
+ m_node.save(ts,2);
+
+ // interfaces are easy:
+ retval->interfaceData = interfaces();
+ retval->interfaces = retval->interfaceData.keys();
+
+ // sub-objects are slightly more difficult:
+ QDomNodeList objects = m_node.elementsByTagName(QLatin1String("node"));
+ for (int i = 0; i < objects.count(); ++i) {
+ QDomElement obj = objects.item(i).toElement();
+ QString objName = obj.attribute(QLatin1String("name"));
+ if (obj.isNull() || objName.isEmpty())
+ continue; // for whatever reason
+
+ // check if we have anything to process
+ if (!obj.firstChild().isNull()) {
+ // yes, introspect this object
+ QString xml;
+ QTextStream ts2(&xml);
+ obj.save(ts2,0);
+
+ // parse it
+ QString objAbsName = m_path;
+ if (!objAbsName.endsWith(QLatin1Char('/')))
+ objAbsName.append(QLatin1Char('/'));
+ objAbsName += objName;
+
+ QDBusXmlParser parser(m_service, objAbsName, obj);
+ retval->childObjectData.insert(objName, parser.objectTree());
+ }
+
+ retval->childObjects << objName;
+ }
+
+ return QSharedDataPointer<QDBusIntrospection::ObjectTree>( retval );
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusxmlparser_p.h b/src/dbus/qdbusxmlparser_p.h
new file mode 100644
index 0000000000..2869539f31
--- /dev/null
+++ b/src/dbus/qdbusxmlparser_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDBus module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDBUSXMLPARSER_H
+#define QDBUSXMLPARSER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qmap.h>
+#include <QtXml/qdom.h>
+#include <qdbusmacros.h>
+#include "qdbusintrospection_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+*/
+class QDBusXmlParser
+{
+ QString m_service;
+ QString m_path;
+ QDomElement m_node;
+
+public:
+ QDBusXmlParser(const QString& service, const QString& path,
+ const QString& xmlData);
+ QDBusXmlParser(const QString& service, const QString& path,
+ const QDomElement& node);
+
+ QDBusIntrospection::Interfaces interfaces() const;
+ QSharedDataPointer<QDBusIntrospection::Object> object() const;
+ QSharedDataPointer<QDBusIntrospection::ObjectTree> objectTree() const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DBUS
+#endif