File indexing completed on 2025-02-09 05:31:51
0001 /* 0002 Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org> 0003 Copyright (C) 2011 Harald Sitter <sitter@kde.org> 0004 0005 This library is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU Lesser General Public 0007 License as published by the Free Software Foundation; either 0008 version 2.1 of the License, or (at your option) version 3, or any 0009 later version accepted by the membership of KDE e.V. (or its 0010 successor approved by the membership of KDE e.V.), Nokia Corporation 0011 (or its successors, if any) and the KDE Free Qt Foundation, which shall 0012 act as a proxy defined in Section 6 of version 3 of the license. 0013 0014 This library is distributed in the hope that it will be useful, 0015 but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0017 Lesser General Public License for more details. 0018 0019 You should have received a copy of the GNU Lesser General Public 0020 License along with this library. If not, see <http://www.gnu.org/licenses/>. 0021 */ 0022 0023 #ifndef PHONONDEFS_P_H 0024 #define PHONONDEFS_P_H 0025 0026 #include <QMetaType> 0027 #include "medianode_p.h" 0028 #include "phononpimpl_p.h" 0029 0030 #define PHONON_CONCAT_HELPER_INTERNAL(x, y) x ## y 0031 #define PHONON_CONCAT_HELPER(x, y) PHONON_CONCAT_HELPER_INTERNAL(x, y) 0032 0033 #define PHONON_PRIVATECLASS \ 0034 protected: \ 0035 virtual bool aboutToDeleteBackendObject() override; \ 0036 virtual void createBackendObject() override; \ 0037 /** 0038 * \internal 0039 * After construction of the Iface object this method is called 0040 * throughout the complete class hierarchy in order to set up the 0041 * properties that were already set on the public interface. 0042 * 0043 * An example implementation could look like this: 0044 * \code 0045 * ParentClassPrivate::setupBackendObject(); 0046 * m_iface->setPropertyA(d->propertyA); 0047 * m_iface->setPropertyB(d->propertyB); 0048 * \endcode 0049 */ \ 0050 void setupBackendObject(); 0051 0052 #define PHONON_PRIVATEABSTRACTCLASS \ 0053 protected: \ 0054 virtual bool aboutToDeleteBackendObject() override; \ 0055 /** 0056 * \internal 0057 * After construction of the Iface object this method is called 0058 * throughout the complete class hierarchy in order to set up the 0059 * properties that were already set on the public interface. 0060 * 0061 * An example implementation could look like this: 0062 * \code 0063 * ParentClassPrivate::setupBackendObject(); 0064 * m_iface->setPropertyA(d->propertyA); 0065 * m_iface->setPropertyB(d->propertyB); 0066 * \endcode 0067 */ \ 0068 void setupBackendObject(); 0069 0070 #define PHONON_ABSTRACTBASE_IMPL \ 0071 PHONON_CLASSNAME::PHONON_CLASSNAME(PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) &dd, QObject *parent) \ 0072 : QObject(parent), \ 0073 MediaNode(dd) \ 0074 { \ 0075 } 0076 0077 #define PHONON_OBJECT_IMPL \ 0078 PHONON_CLASSNAME::PHONON_CLASSNAME(QObject *parent) \ 0079 : QObject(parent), \ 0080 MediaNode(*new PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private)()) \ 0081 { \ 0082 } \ 0083 void PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private)::createBackendObject() \ 0084 { \ 0085 if (m_backendObject) \ 0086 return; \ 0087 P_Q(PHONON_CLASSNAME); \ 0088 m_backendObject = Factory::PHONON_CONCAT_HELPER(create, PHONON_CLASSNAME)(q); \ 0089 if (m_backendObject) { \ 0090 setupBackendObject(); \ 0091 } \ 0092 } 0093 0094 #define PHONON_HEIR_IMPL(parentclass) \ 0095 PHONON_CLASSNAME::PHONON_CLASSNAME(QObject *parent) \ 0096 : parentclass(*new PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private), parent) \ 0097 { \ 0098 } \ 0099 void PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private)::createBackendObject() \ 0100 { \ 0101 if (m_backendObject) \ 0102 return; \ 0103 P_Q(PHONON_CLASSNAME); \ 0104 m_backendObject = Factory::PHONON_CONCAT_HELPER(create, PHONON_CLASSNAME)(q); \ 0105 if (m_backendObject) { \ 0106 setupBackendObject(); \ 0107 } \ 0108 } 0109 0110 #define BACKEND_GET(returnType, returnVar, methodName) \ 0111 QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar)) 0112 #define BACKEND_GET1(returnType, returnVar, methodName, varType1, var1) \ 0113 QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar), Q_ARG(varType1, var1)) 0114 #define BACKEND_GET2(returnType, returnVar, methodName, varType1, var1, varType2, var2) \ 0115 QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar), Q_ARG(varType1, var1), Q_ARG(varType2, var2)) 0116 #define BACKEND_CALL(methodName) \ 0117 QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection) 0118 #define BACKEND_CALL1(methodName, varType1, var1) \ 0119 QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_ARG(varType1, var1)) 0120 #define BACKEND_CALL2(methodName, varType1, var1, varType2, var2) \ 0121 QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_ARG(varType1, var1), Q_ARG(varType2, var2)) 0122 0123 #define pBACKEND_GET(returnType, returnVar, methodName) \ 0124 QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar)) 0125 #define pBACKEND_GET1(returnType, returnVar, methodName, varType1, var1) \ 0126 QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar), Q_ARG(varType1, var1)) 0127 #define pBACKEND_GET2(returnType, returnVar, methodName, varType1, var1, varType2, var2) \ 0128 QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar), Q_ARG(varType1, var1), Q_ARG(varType2, var2)) 0129 #define pBACKEND_CALL(methodName) \ 0130 QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection) 0131 #define pBACKEND_CALL1(methodName, varType1, var1) \ 0132 QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_ARG(varType1, var1)) 0133 #define pBACKEND_CALL2(methodName, varType1, var1, varType2, var2) \ 0134 QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_ARG(varType1, var1), Q_ARG(varType2, var2)) 0135 0136 namespace Phonon 0137 { 0138 namespace 0139 { 0140 class NoIface; 0141 0142 /// All template arguments are valid 0143 template<typename T> struct IsValid { enum { Result = true }; }; 0144 /// except NoIface 0145 template<> struct IsValid<NoIface> { enum { Result = false }; }; 0146 0147 template<class T> inline T my_cast(QObject *o) { return qobject_cast<T>(o); } 0148 template<class T> inline T my_cast(const QObject *o) { return qobject_cast<T>(o); } 0149 0150 template<> inline NoIface *my_cast<NoIface *>(QObject *) { return nullptr; } 0151 template<> inline NoIface *my_cast<NoIface *>(const QObject *) { return nullptr; } 0152 } // anonymous namespace 0153 0154 /** 0155 * \internal 0156 * 0157 * \brief Helper class to cast the backend object to the correct version of the interface. 0158 * 0159 * Additions to the backend interfaces cannot be done by adding virtual methods as that would 0160 * break the binary interface. So the old class is renamed and a new class with the old name 0161 * inheriting the old class is added, containing all the new virtual methods. 0162 * Example: 0163 * \code 0164 class FooInterface 0165 { 0166 public: 0167 virtual ~FooInterface() {} 0168 virtual oldMethod() = 0; 0169 }; 0170 Q_DECLARE_INTERFACE(FooInterface, "FooInterface0.phonon.kde.org") 0171 * \endcode 0172 * becomes 0173 * \code 0174 class FooInterface0 0175 { 0176 public: 0177 virtual ~FooInterface0() {} 0178 virtual oldMethod() = 0; 0179 }; 0180 class FooInterface : public FooInterface0 0181 { 0182 public: 0183 virtual newMethod() = 0; 0184 }; 0185 Q_DECLARE_INTERFACE(FooInterface0, "FooInterface0.phonon.kde.org") 0186 Q_DECLARE_INTERFACE(FooInterface, "FooInterface1.phonon.kde.org") 0187 * \endcode 0188 * 0189 * With this, backends compiled against the old header can be qobject_casted to FooInterface0, 0190 * but not to FooInterface. On the other hand backends compiled against the new header (they first 0191 * need to implement newMethod) can only be qobject_casted to FooInterface but not to 0192 * FooInterface0. (The qobject_cast relies on the string in Q_DECLARE_INTERFACE and not the 0193 * class name which is why it behaves that way.) 0194 * 0195 * Now, in order to call oldMethod, the code needs to try to cast to both FooInterface and 0196 * FooInterface0 (new backends will work with the former, old backends with the latter) and then 0197 * if one of them in non-zero call oldMethod on it. 0198 * 0199 * To call newMethod only a cast to FooInterface needs to be done. 0200 * 0201 * The Iface class does all this for you for up to three (for now) interface revisions. Just 0202 * create an object like this: 0203 * \code 0204 Iface<FooInterface0, FooInterface> iface0(d); 0205 if (iface0) { 0206 iface0->oldMethod(); 0207 } 0208 Iface<FooInterface> iface(d); 0209 if (iface) { 0210 iface->newMethod(); 0211 } 0212 * \endcode 0213 * 0214 * This becomes a bit more convenient if you add macros like this: 0215 * \code 0216 #define IFACES1 FooInterface 0217 #define IFACES0 FooInterface0, IFACES1 0218 * \endcode 0219 * which you can use like this: 0220 * \code 0221 Iface<IFACES0> iface0(d); 0222 if (iface0) { 0223 iface0->oldMethod(); 0224 } 0225 Iface<IFACES1> iface(d); 0226 if (iface) { 0227 iface->newMethod(); 0228 } 0229 * \endcode 0230 * With the next revision you can then change the macros to 0231 * \code 0232 #define IFACES2 FooInterface 0233 #define IFACES1 FooInterface1, IFACES2 0234 #define IFACES0 FooInterface0, IFACES1 0235 * \endcode 0236 * 0237 * \author Matthias Kretz <kretz@kde.org> 0238 */ 0239 template<class T0, class T1 = NoIface, class T2 = NoIface, class T3 = NoIface, class T4 = NoIface> 0240 class Iface 0241 { 0242 public: 0243 static inline T0 *cast(MediaNodePrivate *const d) 0244 { 0245 if (IsValid<T1>::Result) { 0246 T0 *ret; 0247 if (IsValid<T2>::Result) { 0248 ret = reinterpret_cast<T0 *>(my_cast<T2 *>(d->m_backendObject)); 0249 if (ret) return ret; 0250 if (IsValid<T3>::Result) { 0251 ret = reinterpret_cast<T0 *>(my_cast<T3 *>(d->m_backendObject)); 0252 if (ret) return ret; 0253 if (IsValid<T4>::Result) { 0254 ret = reinterpret_cast<T0 *>(my_cast<T4 *>(d->m_backendObject)); 0255 if (ret) return ret; 0256 } 0257 } 0258 } 0259 ret = reinterpret_cast<T0 *>(my_cast<T1 *>(d->m_backendObject)); 0260 if (ret) return ret; 0261 } 0262 return qobject_cast<T0 *>(d->m_backendObject); 0263 } 0264 0265 static inline const T0 *cast(const MediaNodePrivate *const d) 0266 { 0267 if (IsValid<T1>::Result) { 0268 const T0 *ret; 0269 if (IsValid<T2>::Result) { 0270 ret = reinterpret_cast<const T0 *>(my_cast<T2 *>(d->m_backendObject)); 0271 if (ret) return ret; 0272 if (IsValid<T3>::Result) { 0273 ret = reinterpret_cast<const T0 *>(my_cast<T3 *>(d->m_backendObject)); 0274 if (ret) return ret; 0275 if (IsValid<T4>::Result) { 0276 ret = reinterpret_cast<const T0 *>(my_cast<T4 *>(d->m_backendObject)); 0277 if (ret) return ret; 0278 } 0279 } 0280 } 0281 ret = reinterpret_cast<const T0 *>(my_cast<T1 *>(d->m_backendObject)); 0282 if (ret) return ret; 0283 } 0284 return qobject_cast<T0 *>(d->m_backendObject); 0285 } 0286 0287 inline Iface(MediaNodePrivate *const d) : iface(cast(d)) {} 0288 inline operator T0 *() { return iface; } 0289 inline operator const T0 *() const { return iface; } 0290 inline T0 *operator->() { Q_ASSERT(iface); return iface; } 0291 inline const T0 *operator->() const { Q_ASSERT(iface); return iface; } 0292 private: 0293 T0 *const iface; 0294 }; 0295 0296 template<class T0, class T1 = NoIface, class T2 = NoIface, class T3 = NoIface, class T4 = NoIface> 0297 class ConstIface 0298 { 0299 public: 0300 inline ConstIface(const MediaNodePrivate *const d) : iface(Iface<T0, T1, T2, T3, T4>::cast(d)) {} 0301 inline operator const T0 *() const { return iface; } 0302 inline const T0 *operator->() const { Q_ASSERT(iface); return iface; } 0303 private: 0304 const T0 *const iface; 0305 }; 0306 } // namespace Phonon 0307 0308 #define INTERFACE_CALL(function) \ 0309 Iface<PHONON_INTERFACENAME >::cast(d)->function 0310 0311 #define pINTERFACE_CALL(function) \ 0312 Iface<PHONON_INTERFACENAME >::cast(this)->function 0313 0314 #define PHONON_GETTER(rettype, name, retdefault) \ 0315 rettype PHONON_CLASSNAME::name() const \ 0316 { \ 0317 const PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \ 0318 if (!d->m_backendObject) \ 0319 return retdefault; \ 0320 rettype ret; \ 0321 BACKEND_GET(rettype, ret, #name); \ 0322 return ret; \ 0323 } 0324 0325 #define PHONON_INTERFACE_GETTER(rettype, name, retdefault) \ 0326 rettype PHONON_CLASSNAME::name() const \ 0327 { \ 0328 const PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \ 0329 if (!d->m_backendObject) \ 0330 return retdefault; \ 0331 return Iface<PHONON_INTERFACENAME >::cast(d)->name(); \ 0332 } 0333 0334 #define PHONON_GETTER1(rettype, name, retdefault, argtype1, argvar1) \ 0335 rettype PHONON_CLASSNAME::name(argtype1 argvar1) const \ 0336 { \ 0337 const PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \ 0338 if (!d->m_backendObject) \ 0339 return retdefault; \ 0340 rettype ret; \ 0341 BACKEND_GET1(rettype, ret, #name, const QObject *, argvar1->k_ptr->backendObject()); \ 0342 return ret; \ 0343 } 0344 0345 #define PHONON_INTERFACE_GETTER1(rettype, name, retdefault, argtype1, argvar1) \ 0346 rettype PHONON_CLASSNAME::name(argtype1 argvar1) const \ 0347 { \ 0348 const PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \ 0349 if (!d->m_backendObject) \ 0350 return retdefault; \ 0351 return Iface<PHONON_INTERFACENAME >::cast(d)->name(argvar1->k_ptr->backendObject()); \ 0352 } 0353 0354 #define PHONON_SETTER(functionname, privatevar, argtype1) \ 0355 void PHONON_CLASSNAME::functionname(argtype1 x) \ 0356 { \ 0357 PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \ 0358 d->privatevar = x; \ 0359 if (k_ptr->backendObject()) { \ 0360 BACKEND_CALL1(#functionname, argtype1, x); \ 0361 } \ 0362 } 0363 0364 #define PHONON_INTERFACE_SETTER(functionname, privatevar, argtype1) \ 0365 void PHONON_CLASSNAME::functionname(argtype1 x) \ 0366 { \ 0367 PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \ 0368 d->privatevar = x; \ 0369 if (k_ptr->backendObject()) { \ 0370 Iface<PHONON_INTERFACENAME >::cast(d)->functionname(x); \ 0371 } \ 0372 } 0373 0374 #ifndef METATYPE_QLIST_INT_DEFINED 0375 #define METATYPE_QLIST_INT_DEFINED 0376 // Want this exactly once, see phonondefs_p.h kcm/outputdevicechoice.cpp 0377 Q_DECLARE_METATYPE(QList<int>) 0378 #endif 0379 0380 #endif // PHONONDEFS_P_H