summaryrefslogtreecommitdiffstats
path: root/src/dbus
diff options
context:
space:
mode:
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