~ubuntu-branches/ubuntu/quantal/psi/quantal

« back to all changes in this revision

Viewing changes to third-party/qca/qca/src/support/syncthread.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2008-04-14 18:57:30 UTC
  • mfrom: (2.1.9 hardy)
  • Revision ID: james.westby@ubuntu.com-20080414185730-528re3zp0m2hdlhi
Tags: 0.11-8
* added CONFIG -= link_prl to .pro files and removed dependencies
  which are made unnecessary by this change
* Fix segfault when closing last chat tab with qt4.4
  (This is from upstream svn, rev. 1101) (Closes: Bug#476122)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2006  Justin Karneges <justin@affinix.com>
 
3
 *
 
4
 * This library is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU Lesser General Public
 
6
 * License as published by the Free Software Foundation; either
 
7
 * version 2.1 of the License, or (at your option) any later version.
 
8
 *
 
9
 * This library is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * Lesser General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU Lesser General Public
 
15
 * License along with this library; if not, write to the Free Software
 
16
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 
17
 *
 
18
 */
 
19
 
 
20
#include "qca_support.h"
 
21
 
 
22
#include <QEventLoop>
 
23
#include <QMetaMethod>
 
24
#include <QMutexLocker>
 
25
#include <QWaitCondition>
 
26
 
 
27
namespace QCA {
 
28
 
 
29
QByteArray methodReturnType(const QMetaObject *obj, const QByteArray &method, const QList<QByteArray> argTypes)
 
30
{
 
31
        for(int n = 0; n < obj->methodCount(); ++n)
 
32
        {
 
33
                QMetaMethod m = obj->method(n);
 
34
                QByteArray sig = m.signature();
 
35
                int offset = sig.indexOf('(');
 
36
                if(offset == -1)
 
37
                        continue;
 
38
                QByteArray name = sig.mid(0, offset);
 
39
                if(name != method)
 
40
                        continue;
 
41
                if(m.parameterTypes() != argTypes)
 
42
                        continue;
 
43
 
 
44
                return m.typeName();
 
45
        }
 
46
        return QByteArray();
 
47
}
 
48
 
 
49
bool invokeMethodWithVariants(QObject *obj, const QByteArray &method, const QVariantList &args, QVariant *ret, Qt::ConnectionType type)
 
50
{
 
51
        // QMetaObject::invokeMethod() has a 10 argument maximum
 
52
        if(args.count() > 10)
 
53
                return false;
 
54
 
 
55
        QList<QByteArray> argTypes;
 
56
        for(int n = 0; n < args.count(); ++n)
 
57
                argTypes += args[n].typeName();
 
58
 
 
59
        // get return type
 
60
        int metatype = 0;
 
61
        QByteArray retTypeName = methodReturnType(obj->metaObject(), method, argTypes);
 
62
        if(!retTypeName.isEmpty())
 
63
        {
 
64
                metatype = QMetaType::type(retTypeName.data());
 
65
                if(metatype == 0) // lookup failed
 
66
                        return false;
 
67
        }
 
68
 
 
69
        QGenericArgument arg[10];
 
70
        for(int n = 0; n < args.count(); ++n)
 
71
                arg[n] = QGenericArgument(args[n].typeName(), args[n].constData());
 
72
 
 
73
        QGenericReturnArgument retarg;
 
74
        QVariant retval;
 
75
        if(metatype != 0)
 
76
        {
 
77
                retval = QVariant(metatype, (const void *)0);
 
78
                retarg = QGenericReturnArgument(retval.typeName(), retval.data());
 
79
        }
 
80
 
 
81
        if(!QMetaObject::invokeMethod(obj, method.data(), type, retarg, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9]))
 
82
                return false;
 
83
 
 
84
        if(retval.isValid() && ret)
 
85
                *ret = retval;
 
86
        return true;
 
87
}
 
88
 
 
89
//----------------------------------------------------------------------------
 
90
// SyncThread
 
91
//----------------------------------------------------------------------------
 
92
class SyncThreadAgent;
 
93
 
 
94
class SyncThread::Private : public QObject
 
95
{
 
96
        Q_OBJECT
 
97
public:
 
98
        SyncThread *q;
 
99
        QMutex m;
 
100
        QWaitCondition w;
 
101
        QEventLoop *loop;
 
102
        SyncThreadAgent *agent;
 
103
        bool last_success;
 
104
        QVariant last_ret;
 
105
 
 
106
        Private(SyncThread *_q) : QObject(_q), q(_q)
 
107
        {
 
108
                loop = 0;
 
109
                agent = 0;
 
110
        }
 
111
 
 
112
private slots:
 
113
        void agent_started();
 
114
        void agent_call_ret(bool success, const QVariant &ret);
 
115
};
 
116
 
 
117
class SyncThreadAgent : public QObject
 
118
{
 
119
        Q_OBJECT
 
120
public:
 
121
        SyncThreadAgent(QObject *parent = 0) : QObject(parent)
 
122
        {
 
123
                QMetaObject::invokeMethod(this, "started", Qt::QueuedConnection);
 
124
        }
 
125
 
 
126
signals:
 
127
        void started();
 
128
        void call_ret(bool success, const QVariant &ret);
 
129
 
 
130
public slots:
 
131
        void call_do(QObject *obj, const QByteArray &method, const QVariantList &args)
 
132
        {
 
133
                QVariant ret;
 
134
                bool ok = invokeMethodWithVariants(obj, method, args, &ret, Qt::DirectConnection);
 
135
                emit call_ret(ok, ret);
 
136
        }
 
137
};
 
138
 
 
139
SyncThread::SyncThread(QObject *parent)
 
140
:QThread(parent)
 
141
{
 
142
        d = new Private(this);
 
143
        qRegisterMetaType<QVariant>("QVariant");
 
144
        qRegisterMetaType<QVariantList>("QVariantList");
 
145
}
 
146
 
 
147
SyncThread::~SyncThread()
 
148
{
 
149
        stop();
 
150
        delete d;
 
151
}
 
152
 
 
153
void SyncThread::start()
 
154
{
 
155
        QMutexLocker locker(&d->m);
 
156
        Q_ASSERT(!d->loop);
 
157
        QThread::start();
 
158
        d->w.wait(&d->m);
 
159
}
 
160
 
 
161
void SyncThread::stop()
 
162
{
 
163
        QMutexLocker locker(&d->m);
 
164
        if(!d->loop)
 
165
                return;
 
166
        QMetaObject::invokeMethod(d->loop, "quit");
 
167
        d->w.wait(&d->m);
 
168
        wait();
 
169
}
 
170
 
 
171
QVariant SyncThread::call(QObject *obj, const QByteArray &method, const QVariantList &args, bool *ok)
 
172
{
 
173
        QMutexLocker locker(&d->m);
 
174
        bool ret;
 
175
        ret = QMetaObject::invokeMethod(d->agent, "call_do",
 
176
                Qt::QueuedConnection, Q_ARG(QObject*, obj),
 
177
                Q_ARG(QByteArray, method), Q_ARG(QVariantList, args));
 
178
        Q_ASSERT(ret);
 
179
        d->w.wait(&d->m);
 
180
        if(ok)
 
181
                *ok = d->last_success;
 
182
        QVariant v = d->last_ret;
 
183
        d->last_ret = QVariant();
 
184
        return v;
 
185
}
 
186
 
 
187
void SyncThread::run()
 
188
{
 
189
        d->m.lock();
 
190
        d->loop = new QEventLoop;
 
191
        d->agent = new SyncThreadAgent;
 
192
        connect(d->agent, SIGNAL(started()), d, SLOT(agent_started()), Qt::DirectConnection);
 
193
        connect(d->agent, SIGNAL(call_ret(bool, const QVariant &)), d, SLOT(agent_call_ret(bool, const QVariant &)), Qt::DirectConnection);
 
194
        d->loop->exec();
 
195
        d->m.lock();
 
196
        atEnd();
 
197
        delete d->agent;
 
198
        delete d->loop;
 
199
        d->agent = 0;
 
200
        d->loop = 0;
 
201
        d->w.wakeOne();
 
202
        d->m.unlock();
 
203
}
 
204
 
 
205
void SyncThread::Private::agent_started()
 
206
{
 
207
        q->atStart();
 
208
        w.wakeOne();
 
209
        m.unlock();
 
210
}
 
211
 
 
212
void SyncThread::Private::agent_call_ret(bool success, const QVariant &ret)
 
213
{
 
214
        QMutexLocker locker(&m);
 
215
        last_success = success;
 
216
        last_ret = ret;
 
217
        w.wakeOne();
 
218
}
 
219
 
 
220
}
 
221
 
 
222
#include "syncthread.moc"