1 /* This file is part of the KDE project
2 Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License version 2 as published by the Free Software Foundation.
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
20 #ifndef PHONONDEFS_P_H
21 #define PHONONDEFS_P_H
23 #include <QtCore/QMetaType>
24 #include "medianode_p.h"
26 #define K_D(Class) Class##Private *const d = k_func()
28 #define PHONON_CONCAT_HELPER_INTERNAL(x, y) x ## y
29 #define PHONON_CONCAT_HELPER(x, y) PHONON_CONCAT_HELPER_INTERNAL(x, y)
31 #define PHONON_PRIVATECLASS \
33 virtual bool aboutToDeleteBackendObject(); \
34 virtual void createBackendObject(); \
37 * After construction of the Iface object this method is called
38 * throughout the complete class hierarchy in order to set up the
39 * properties that were already set on the public interface.
41 * An example implementation could look like this:
43 * ParentClassPrivate::setupBackendObject();
44 * m_iface->setPropertyA(d->propertyA);
45 * m_iface->setPropertyB(d->propertyB);
48 void setupBackendObject();
50 #define PHONON_PRIVATEABSTRACTCLASS \
52 virtual bool aboutToDeleteBackendObject(); \
55 * After construction of the Iface object this method is called
56 * throughout the complete class hierarchy in order to set up the
57 * properties that were already set on the public interface.
59 * An example implementation could look like this:
61 * ParentClassPrivate::setupBackendObject();
62 * m_iface->setPropertyA(d->propertyA);
63 * m_iface->setPropertyB(d->propertyB);
66 void setupBackendObject();
68 #define PHONON_ABSTRACTBASE_IMPL \
69 PHONON_CLASSNAME::PHONON_CLASSNAME(PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) &dd, QObject *parent) \
75 #define PHONON_OBJECT_IMPL \
76 PHONON_CLASSNAME::PHONON_CLASSNAME(QObject *parent) \
78 MediaNode(*new PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private)()) \
81 void PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private)::createBackendObject() \
83 if (m_backendObject) \
85 Q_Q(PHONON_CLASSNAME); \
86 m_backendObject = Factory::PHONON_CONCAT_HELPER(create, PHONON_CLASSNAME)(q); \
87 if (m_backendObject) { \
88 setupBackendObject(); \
92 #define PHONON_HEIR_IMPL(parentclass) \
93 PHONON_CLASSNAME::PHONON_CLASSNAME(QObject *parent) \
94 : parentclass(*new PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private), parent) \
97 void PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private)::createBackendObject() \
99 if (m_backendObject) \
101 Q_Q(PHONON_CLASSNAME); \
102 m_backendObject = Factory::PHONON_CONCAT_HELPER(create, PHONON_CLASSNAME)(q); \
103 if (m_backendObject) { \
104 setupBackendObject(); \
108 #define BACKEND_GET(returnType, returnVar, methodName) \
109 QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar))
110 #define BACKEND_GET1(returnType, returnVar, methodName, varType1, var1) \
111 QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar), Q_ARG(varType1, var1))
112 #define BACKEND_GET2(returnType, returnVar, methodName, varType1, var1, varType2, var2) \
113 QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar), Q_ARG(varType1, var1), Q_ARG(varType2, var2))
114 #define BACKEND_CALL(methodName) \
115 QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection)
116 #define BACKEND_CALL1(methodName, varType1, var1) \
117 QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_ARG(varType1, var1))
118 #define BACKEND_CALL2(methodName, varType1, var1, varType2, var2) \
119 QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_ARG(varType1, var1), Q_ARG(varType2, var2))
121 #define pBACKEND_GET(returnType, returnVar, methodName) \
122 QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar))
123 #define pBACKEND_GET1(returnType, returnVar, methodName, varType1, var1) \
124 QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar), Q_ARG(varType1, var1))
125 #define pBACKEND_GET2(returnType, returnVar, methodName, varType1, var1, varType2, var2) \
126 QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar), Q_ARG(varType1, var1), Q_ARG(varType2, var2))
127 #define pBACKEND_CALL(methodName) \
128 QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection)
129 #define pBACKEND_CALL1(methodName, varType1, var1) \
130 QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_ARG(varType1, var1))
131 #define pBACKEND_CALL2(methodName, varType1, var1, varType2, var2) \
132 QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_ARG(varType1, var1), Q_ARG(varType2, var2))
142 /// All template arguments are valid
143 template<typename T
> struct IsValid
{ enum { Result
= true }; };
145 template<> struct IsValid
<NoIface
> { enum { Result
= false }; };
147 template<class T
> inline T
my_cast(QObject
*o
) { return qobject_cast
<T
>(o
); }
148 template<class T
> inline T
my_cast(const QObject
*o
) { return qobject_cast
<T
>(o
); }
150 template<> inline NoIface
*my_cast
<NoIface
*>(QObject
*) { return 0; }
151 template<> inline NoIface
*my_cast
<NoIface
*>(const QObject
*) { return 0; }
152 } // anonymous namespace
157 * \brief Helper class to cast the backend object to the correct version of the interface.
159 * Additions to the backend interfaces cannot be done by adding virtual methods as that would
160 * break the binary interface. So the old class is renamed and a new class with the old name
161 * inheriting the old class is added, containing all the new virtual methods.
167 virtual ~FooInterface() {}
168 virtual oldMethod() = 0;
170 Q_DECLARE_INTERFACE(FooInterface, "FooInterface0.phonon.kde.org")
177 virtual ~FooInterface0() {}
178 virtual oldMethod() = 0;
180 class FooInterface : public FooInterface0
183 virtual newMethod() = 0;
185 Q_DECLARE_INTERFACE(FooInterface0, "FooInterface0.phonon.kde.org")
186 Q_DECLARE_INTERFACE(FooInterface, "FooInterface1.phonon.kde.org")
189 * With this, backends compiled against the old header can be qobject_casted to FooInterface0,
190 * but not to FooInterface. On the other hand backends compiled against the new header (they first
191 * need to implement newMethod) can only be qobject_casted to FooInterface but not to
192 * FooInterface0. (The qobject_cast relies on the string in Q_DECLARE_INTERFACE and not the
193 * class name which is why it behaves that way.)
195 * Now, in order to call oldMethod, the code needs to try to cast to both FooInterface and
196 * FooInterface0 (new backends will work with the former, old backends with the latter) and then
197 * if one of them in non-zero call oldMethod on it.
199 * To call newMethod only a cast to FooInterface needs to be done.
201 * The Iface class does all this for you for up to three (for now) interface revisions. Just
202 * create an object like this:
204 Iface<FooInterface0, FooInterface> iface0(d);
208 Iface<FooInterface> iface(d);
214 * This becomes a bit more convenient if you add macros like this:
216 #define IFACES1 FooInterface
217 #define IFACES0 FooInterface0, IFACES1
219 * which you can use like this:
221 Iface<IFACES0> iface0(d);
225 Iface<IFACES1> iface(d);
230 * With the next revision you can then change the macros to
232 #define IFACES2 FooInterface
233 #define IFACES1 FooInterface1, IFACES2
234 #define IFACES0 FooInterface0, IFACES1
237 * \author Matthias Kretz <kretz@kde.org>
239 template<class T0
, class T1
= NoIface
, class T2
= NoIface
>
243 static inline T0
*cast(MediaNodePrivate
*const d
)
245 if (IsValid
<T1
>::Result
) {
247 if (IsValid
<T2
>::Result
) {
248 ret
= reinterpret_cast<T0
*>(my_cast
<T2
*>(d
->m_backendObject
));
251 ret
= reinterpret_cast<T0
*>(my_cast
<T1
*>(d
->m_backendObject
));
254 return qobject_cast
<T0
*>(d
->m_backendObject
);
257 static inline const T0
*cast(const MediaNodePrivate
*const d
)
259 if (IsValid
<T1
>::Result
) {
261 if (IsValid
<T2
>::Result
) {
262 ret
= reinterpret_cast<const T0
*>(my_cast
<T2
*>(d
->m_backendObject
));
265 ret
= reinterpret_cast<const T0
*>(my_cast
<T1
*>(d
->m_backendObject
));
268 return qobject_cast
<T0
*>(d
->m_backendObject
);
271 inline Iface(MediaNodePrivate
*const d
) : iface(cast(d
)) {}
272 inline operator T0
*() { return iface
; }
273 inline operator const T0
*() const { return iface
; }
274 inline T0
*operator->() { Q_ASSERT(iface
); return iface
; }
275 inline const T0
*operator->() const { Q_ASSERT(iface
); return iface
; }
280 template<class T0
, class T1
= NoIface
, class T2
= NoIface
>
284 inline ConstIface(const MediaNodePrivate
*const d
) : iface(Iface
<T0
, T1
, T2
>::cast(d
)) {}
285 inline operator const T0
*() const { return iface
; }
286 inline const T0
*operator->() const { Q_ASSERT(iface
); return iface
; }
288 const T0
*const iface
;
290 } // namespace Phonon
294 #define INTERFACE_CALL(function) \
295 Iface<PHONON_INTERFACENAME >::cast(d)->function
297 #define pINTERFACE_CALL(function) \
298 Iface<PHONON_INTERFACENAME >::cast(this)->function
300 #define PHONON_GETTER(rettype, name, retdefault) \
301 rettype PHONON_CLASSNAME::name() const \
303 const PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
304 if (!d->m_backendObject) \
307 BACKEND_GET(rettype, ret, #name); \
311 #define PHONON_INTERFACE_GETTER(rettype, name, retdefault) \
312 rettype PHONON_CLASSNAME::name() const \
314 const PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
315 if (!d->m_backendObject) \
317 return Iface<PHONON_INTERFACENAME >::cast(d)->name(); \
320 #define PHONON_GETTER1(rettype, name, retdefault, argtype1, argvar1) \
321 rettype PHONON_CLASSNAME::name(argtype1 argvar1) const \
323 const PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
324 if (!d->m_backendObject) \
327 BACKEND_GET1(rettype, ret, #name, const QObject *, argvar1->k_ptr->backendObject()); \
331 #define PHONON_INTERFACE_GETTER1(rettype, name, retdefault, argtype1, argvar1) \
332 rettype PHONON_CLASSNAME::name(argtype1 argvar1) const \
334 const PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
335 if (!d->m_backendObject) \
337 return Iface<PHONON_INTERFACENAME >::cast(d)->name(argvar1->k_ptr->backendObject()); \
340 #define PHONON_SETTER(functionname, privatevar, argtype1) \
341 void PHONON_CLASSNAME::functionname(argtype1 x) \
343 PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
345 if (k_ptr->backendObject()) { \
346 BACKEND_CALL1(#functionname, argtype1, x); \
350 #define PHONON_INTERFACE_SETTER(functionname, privatevar, argtype1) \
351 void PHONON_CLASSNAME::functionname(argtype1 x) \
353 PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
355 if (k_ptr->backendObject()) { \
356 Iface<PHONON_INTERFACENAME >::cast(d)->functionname(x); \
360 #ifndef METATYPE_QLIST_INT_DEFINED
361 #define METATYPE_QLIST_INT_DEFINED
362 // Want this exactly once, see phonondefs_p.h kcm/outputdevicechoice.cpp
363 Q_DECLARE_METATYPE(QList
<int>)
366 #endif // PHONONDEFS_P_H