summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/phonon/phonon/phonondefs_p.h
blob: 2f67bbc67440e5aea8fa9d5a7fdab156b0a964ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
/*  This file is part of the KDE project
    Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), Digia Plc 
    (or its successors, if any) and the KDE Free Qt Foundation, which shall
    act as a proxy defined in Section 6 of version 3 of the license.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public 
    License along with this library.  If not, see <http://www.gnu.org/licenses/>.

*/

#ifndef PHONONDEFS_P_H
#define PHONONDEFS_P_H

#include <QtCore/QMetaType>
#include "medianode_p.h"

#define K_D(Class) Class##Private *const d = k_func()

#define PHONON_CONCAT_HELPER_INTERNAL(x, y) x ## y
#define PHONON_CONCAT_HELPER(x, y) PHONON_CONCAT_HELPER_INTERNAL(x, y)

#define PHONON_PRIVATECLASS \
protected: \
    virtual bool aboutToDeleteBackendObject(); \
    virtual void createBackendObject(); \
    /**
     * \internal
     * After construction of the Iface object this method is called
     * throughout the complete class hierarchy in order to set up the
     * properties that were already set on the public interface.
     *
     * An example implementation could look like this:
     * \code
     * ParentClassPrivate::setupBackendObject();
     * m_iface->setPropertyA(d->propertyA);
     * m_iface->setPropertyB(d->propertyB);
     * \endcode
     */ \
    void setupBackendObject();

#define PHONON_PRIVATEABSTRACTCLASS \
protected: \
    virtual bool aboutToDeleteBackendObject(); \
    /**
     * \internal
     * After construction of the Iface object this method is called
     * throughout the complete class hierarchy in order to set up the
     * properties that were already set on the public interface.
     *
     * An example implementation could look like this:
     * \code
     * ParentClassPrivate::setupBackendObject();
     * m_iface->setPropertyA(d->propertyA);
     * m_iface->setPropertyB(d->propertyB);
     * \endcode
     */ \
    void setupBackendObject();

#define PHONON_ABSTRACTBASE_IMPL \
PHONON_CLASSNAME::PHONON_CLASSNAME(PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) &dd, QObject *parent) \
    : QObject(parent), \
    MediaNode(dd) \
{ \
}

#define PHONON_OBJECT_IMPL \
PHONON_CLASSNAME::PHONON_CLASSNAME(QObject *parent) \
    : QObject(parent), \
    MediaNode(*new PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private)()) \
{ \
} \
void PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private)::createBackendObject() \
{ \
    if (m_backendObject) \
        return; \
    Q_Q(PHONON_CLASSNAME); \
    m_backendObject = Factory::PHONON_CONCAT_HELPER(create, PHONON_CLASSNAME)(q); \
    if (m_backendObject) { \
        setupBackendObject(); \
    } \
}

#define PHONON_HEIR_IMPL(parentclass) \
PHONON_CLASSNAME::PHONON_CLASSNAME(QObject *parent) \
    : parentclass(*new PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private), parent) \
{ \
} \
void PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private)::createBackendObject() \
{ \
    if (m_backendObject) \
        return; \
    Q_Q(PHONON_CLASSNAME); \
    m_backendObject = Factory::PHONON_CONCAT_HELPER(create, PHONON_CLASSNAME)(q); \
    if (m_backendObject) { \
        setupBackendObject(); \
    } \
}

#define BACKEND_GET(returnType, returnVar, methodName) \
QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar))
#define BACKEND_GET1(returnType, returnVar, methodName, varType1, var1) \
QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar), Q_ARG(varType1, var1))
#define BACKEND_GET2(returnType, returnVar, methodName, varType1, var1, varType2, var2) \
QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar), Q_ARG(varType1, var1), Q_ARG(varType2, var2))
#define BACKEND_CALL(methodName) \
QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection)
#define BACKEND_CALL1(methodName, varType1, var1) \
QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_ARG(varType1, var1))
#define BACKEND_CALL2(methodName, varType1, var1, varType2, var2) \
QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_ARG(varType1, var1), Q_ARG(varType2, var2))

#define pBACKEND_GET(returnType, returnVar, methodName) \
QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar))
#define pBACKEND_GET1(returnType, returnVar, methodName, varType1, var1) \
QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar), Q_ARG(varType1, var1))
#define pBACKEND_GET2(returnType, returnVar, methodName, varType1, var1, varType2, var2) \
QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar), Q_ARG(varType1, var1), Q_ARG(varType2, var2))
#define pBACKEND_CALL(methodName) \
QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection)
#define pBACKEND_CALL1(methodName, varType1, var1) \
QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_ARG(varType1, var1))
#define pBACKEND_CALL2(methodName, varType1, var1, varType2, var2) \
QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_ARG(varType1, var1), Q_ARG(varType2, var2))

QT_BEGIN_NAMESPACE

namespace Phonon
{
    namespace
    {
        class NoIface;

        /// All template arguments are valid
        template<typename T> struct IsValid { enum { Result = true }; };
        /// except NoIface
        template<> struct IsValid<NoIface> { enum { Result = false }; };

        template<class T> inline T my_cast(QObject *o) { return qobject_cast<T>(o); }
        template<class T> inline T my_cast(const QObject *o) { return qobject_cast<T>(o); }

        template<> inline NoIface *my_cast<NoIface *>(QObject *) { return 0; }
        template<> inline NoIface *my_cast<NoIface *>(const QObject *) { return 0; }
    } // anonymous namespace

    /**
     * \internal
     *
     * \brief Helper class to cast the backend object to the correct version of the interface.
     *
     * Additions to the backend interfaces cannot be done by adding virtual methods as that would
     * break the binary interface. So the old class is renamed and a new class with the old name
     * inheriting the old class is added, containing all the new virtual methods.
     * Example:
     * \code
       class FooInterface
       {
       public:
           virtual ~FooInterface() {}
           virtual oldMethod() = 0;
       };
       Q_DECLARE_INTERFACE(FooInterface, "FooInterface0.phonon.kde.org")
     * \endcode
     * becomes
     * \code
       class FooInterface0
       {
       public:
           virtual ~FooInterface0() {}
           virtual oldMethod() = 0;
       };
       class FooInterface : public FooInterface0
       {
       public:
           virtual newMethod() = 0;
       };
       Q_DECLARE_INTERFACE(FooInterface0, "FooInterface0.phonon.kde.org")
       Q_DECLARE_INTERFACE(FooInterface,  "FooInterface1.phonon.kde.org")
     * \endcode
     *
     * With this, backends compiled against the old header can be qobject_casted to FooInterface0,
     * but not to FooInterface. On the other hand backends compiled against the new header (they first
     * need to implement newMethod) can only be qobject_casted to FooInterface but not to
     * FooInterface0. (The qobject_cast relies on the string in Q_DECLARE_INTERFACE and not the
     * class name which is why it behaves that way.)
     *
     * Now, in order to call oldMethod, the code needs to try to cast to both FooInterface and
     * FooInterface0 (new backends will work with the former, old backends with the latter) and then
     * if one of them in non-zero call oldMethod on it.
     *
     * To call newMethod only a cast to FooInterface needs to be done.
     *
     * The Iface class does all this for you for up to three (for now) interface revisions. Just
     * create an object like this:
     * \code
       Iface<FooInterface0, FooInterface> iface0(d);
       if (iface0) {
           iface0->oldMethod();
       }
       Iface<FooInterface> iface(d);
       if (iface) {
           iface->newMethod();
       }
     * \endcode
     *
     * This becomes a bit more convenient if you add macros like this:
     * \code
       #define IFACES1 FooInterface
       #define IFACES0 FooInterface0, IFACES1
     * \endcode
     * which you can use like this:
     * \code
       Iface<IFACES0> iface0(d);
       if (iface0) {
           iface0->oldMethod();
       }
       Iface<IFACES1> iface(d);
       if (iface) {
           iface->newMethod();
       }
     * \endcode
     * With the next revision you can then change the macros to
     * \code
       #define IFACES2 FooInterface
       #define IFACES1 FooInterface1, IFACES2
       #define IFACES0 FooInterface0, IFACES1
     * \endcode
     *
     * \author Matthias Kretz <kretz@kde.org>
     */
    template<class T0, class T1 = NoIface, class T2 = NoIface>
    class Iface
    {
    public:
        static inline T0 *cast(MediaNodePrivate *const d)
        {
            if (IsValid<T1>::Result) {
                T0 *ret;
                if (IsValid<T2>::Result) {
                    ret = reinterpret_cast<T0 *>(my_cast<T2 *>(d->m_backendObject));
                    if (ret) return ret;
                }
                ret = reinterpret_cast<T0 *>(my_cast<T1 *>(d->m_backendObject));
                if (ret) return ret;
            }
            return qobject_cast<T0 *>(d->m_backendObject);
        }

        static inline const T0 *cast(const MediaNodePrivate *const d)
        {
            if (IsValid<T1>::Result) {
                const T0 *ret;
                if (IsValid<T2>::Result) {
                    ret = reinterpret_cast<const T0 *>(my_cast<T2 *>(d->m_backendObject));
                    if (ret) return ret;
                }
                ret = reinterpret_cast<const T0 *>(my_cast<T1 *>(d->m_backendObject));
                if (ret) return ret;
            }
            return qobject_cast<T0 *>(d->m_backendObject);
        }

        inline Iface(MediaNodePrivate *const d) : iface(cast(d)) {}
        inline operator       T0 *()       { return iface; }
        inline operator const T0 *() const { return iface; }
        inline       T0 *operator->()       { Q_ASSERT(iface); return iface; }
        inline const T0 *operator->() const { Q_ASSERT(iface); return iface; }
    private:
        T0 *const iface;
    };

    template<class T0, class T1 = NoIface, class T2 = NoIface>
    class ConstIface
    {
    public:
        inline ConstIface(const MediaNodePrivate *const d) : iface(Iface<T0, T1, T2>::cast(d)) {}
        inline operator const T0 *() const { return iface; }
        inline const T0 *operator->() const { Q_ASSERT(iface); return iface; }
    private:
        const T0 *const iface;
    };
} // namespace Phonon

QT_END_NAMESPACE

#define INTERFACE_CALL(function) \
Iface<PHONON_INTERFACENAME >::cast(d)->function

#define pINTERFACE_CALL(function) \
Iface<PHONON_INTERFACENAME >::cast(this)->function

#define PHONON_GETTER(rettype, name, retdefault) \
rettype PHONON_CLASSNAME::name() const \
{ \
    const PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
    if (!d->m_backendObject) \
        return retdefault; \
    rettype ret; \
    BACKEND_GET(rettype, ret, #name); \
    return ret; \
}

#define PHONON_INTERFACE_GETTER(rettype, name, retdefault) \
rettype PHONON_CLASSNAME::name() const \
{ \
    const PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
    if (!d->m_backendObject) \
        return retdefault; \
    return Iface<PHONON_INTERFACENAME >::cast(d)->name(); \
}

#define PHONON_GETTER1(rettype, name, retdefault, argtype1, argvar1) \
rettype PHONON_CLASSNAME::name(argtype1 argvar1) const \
{ \
    const PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
    if (!d->m_backendObject) \
        return retdefault; \
    rettype ret; \
    BACKEND_GET1(rettype, ret, #name, const QObject *, argvar1->k_ptr->backendObject()); \
    return ret; \
}

#define PHONON_INTERFACE_GETTER1(rettype, name, retdefault, argtype1, argvar1) \
rettype PHONON_CLASSNAME::name(argtype1 argvar1) const \
{ \
    const PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
    if (!d->m_backendObject) \
        return retdefault; \
    return Iface<PHONON_INTERFACENAME >::cast(d)->name(argvar1->k_ptr->backendObject()); \
}

#define PHONON_SETTER(functionname, privatevar, argtype1) \
void PHONON_CLASSNAME::functionname(argtype1 x) \
{ \
    PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
    d->privatevar = x; \
    if (k_ptr->backendObject()) { \
        BACKEND_CALL1(#functionname, argtype1, x); \
    } \
}

#define PHONON_INTERFACE_SETTER(functionname, privatevar, argtype1) \
void PHONON_CLASSNAME::functionname(argtype1 x) \
{ \
    PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
    d->privatevar = x; \
    if (k_ptr->backendObject()) { \
        Iface<PHONON_INTERFACENAME >::cast(d)->functionname(x); \
    } \
}

#ifndef METATYPE_QLIST_INT_DEFINED
#define METATYPE_QLIST_INT_DEFINED
// Want this exactly once, see phonondefs_p.h kcm/outputdevicechoice.cpp
Q_DECLARE_METATYPE(QList<int>)
#endif

#endif // PHONONDEFS_P_H