mirror of
https://github.com/QuasarApp/qca.git
synced 2025-05-07 08:19:33 +00:00
make SyncThread public
svn path=/trunk/kdesupport/qca/; revision=604527
This commit is contained in:
parent
0fb9275d6a
commit
3f52cfa037
@ -35,13 +35,46 @@
|
||||
#ifndef QCA_SUPPORT_H
|
||||
#define QCA_SUPPORT_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include <QObject>
|
||||
#include <QVariant>
|
||||
#include <QVariantList>
|
||||
#include <QList>
|
||||
#include <QMetaObject>
|
||||
#include <QThread>
|
||||
#include "qca_export.h"
|
||||
#include "qca_tools.h"
|
||||
|
||||
namespace QCA
|
||||
{
|
||||
QCA_EXPORT QByteArray methodReturnType(const QMetaObject *obj, const QByteArray &method, const QList<QByteArray> argTypes);
|
||||
QCA_EXPORT bool invokeMethodWithVariants(QObject *obj, const QByteArray &method, const QVariantList &args, QVariant *ret, Qt::ConnectionType type = Qt::AutoConnection);
|
||||
|
||||
class QCA_EXPORT SyncThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SyncThread(QObject *parent = 0);
|
||||
~SyncThread();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
QVariant call(QObject *obj, const QByteArray &method, const QVariantList &args = QVariantList(), bool *ok = 0);
|
||||
|
||||
protected:
|
||||
virtual void atStart() = 0;
|
||||
virtual void atEnd() = 0;
|
||||
|
||||
// reimplemented
|
||||
virtual void run();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
friend class Private;
|
||||
Private *d;
|
||||
};
|
||||
|
||||
class QCA_EXPORT Synchronizer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -50,7 +50,9 @@ PUBLIC_HEADERS += \
|
||||
HEADERS += $$PRIVATE_HEADERS $$PUBLIC_HEADERS
|
||||
|
||||
# do support first
|
||||
SOURCES += $$QCA_CPP/support/synchronizer.cpp
|
||||
SOURCES += \
|
||||
$$QCA_CPP/support/syncthread.cpp \
|
||||
$$QCA_CPP/support/synchronizer.cpp
|
||||
include($$QCA_SRCBASE/support/dirwatch/dirwatch.pri)
|
||||
|
||||
SOURCES += \
|
||||
|
@ -19,6 +19,9 @@
|
||||
|
||||
#include "qca_support.h"
|
||||
|
||||
#include <QtCore>
|
||||
#include "qpipe.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
# include <windows.h>
|
||||
#else
|
||||
@ -27,206 +30,8 @@
|
||||
# include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "qpipe.h"
|
||||
|
||||
namespace QCA {
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// SyncThread
|
||||
//----------------------------------------------------------------------------
|
||||
static QByteArray getReturnType(const QMetaObject *obj, const QByteArray &method, const QList<QByteArray> argTypes)
|
||||
{
|
||||
for(int n = 0; n < obj->methodCount(); ++n)
|
||||
{
|
||||
QMetaMethod m = obj->method(n);
|
||||
QByteArray sig = m.signature();
|
||||
int offset = sig.indexOf('(');
|
||||
if(offset == -1)
|
||||
continue;
|
||||
QByteArray name = sig.mid(0, offset);
|
||||
if(name != method)
|
||||
continue;
|
||||
if(m.parameterTypes() != argTypes)
|
||||
continue;
|
||||
|
||||
return m.typeName();
|
||||
}
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
static bool invokeMethodWithVariants(QObject *obj, const QByteArray &method, const QVariantList &args, QVariant *ret, Qt::ConnectionType type = Qt::AutoConnection)
|
||||
{
|
||||
// QMetaObject::invokeMethod() has a 10 argument maximum
|
||||
if(args.count() > 10)
|
||||
return false;
|
||||
|
||||
QList<QByteArray> argTypes;
|
||||
for(int n = 0; n < args.count(); ++n)
|
||||
argTypes += args[n].typeName();
|
||||
|
||||
// get return type
|
||||
int metatype = 0;
|
||||
QByteArray retTypeName = getReturnType(obj->metaObject(), method, argTypes);
|
||||
if(!retTypeName.isEmpty())
|
||||
{
|
||||
metatype = QMetaType::type(retTypeName.data());
|
||||
if(metatype == 0) // lookup failed
|
||||
return false;
|
||||
}
|
||||
|
||||
QGenericArgument arg[10];
|
||||
for(int n = 0; n < args.count(); ++n)
|
||||
arg[n] = QGenericArgument(args[n].typeName(), args[n].constData());
|
||||
|
||||
QGenericReturnArgument retarg;
|
||||
QVariant retval;
|
||||
if(metatype != 0)
|
||||
{
|
||||
retval = QVariant(metatype, (const void *)0);
|
||||
retarg = QGenericReturnArgument(retval.typeName(), retval.data());
|
||||
}
|
||||
|
||||
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]))
|
||||
return false;
|
||||
|
||||
if(retval.isValid() && ret)
|
||||
*ret = retval;
|
||||
return true;
|
||||
}
|
||||
|
||||
class SyncThreadAgent;
|
||||
|
||||
class SyncThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QMutex m;
|
||||
QWaitCondition w;
|
||||
QEventLoop *loop;
|
||||
SyncThreadAgent *agent;
|
||||
bool last_success;
|
||||
QVariant last_ret;
|
||||
|
||||
public:
|
||||
SyncThread(QObject *parent = 0);
|
||||
~SyncThread();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
QVariant call(QObject *obj, const char *method, const QVariantList &args = QVariantList(), bool *ok = 0);
|
||||
|
||||
protected:
|
||||
virtual void run();
|
||||
virtual void atStart() = 0;
|
||||
virtual void atEnd() = 0;
|
||||
|
||||
private slots:
|
||||
void agent_started();
|
||||
void agent_call_ret(bool success, const QVariant &ret);
|
||||
};
|
||||
|
||||
class SyncThreadAgent : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SyncThreadAgent(QObject *parent = 0) : QObject(parent)
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "started", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
signals:
|
||||
void started();
|
||||
void call_ret(bool success, const QVariant &ret);
|
||||
|
||||
public slots:
|
||||
void call_do(QObject *obj, const QByteArray &method, const QVariantList &args)
|
||||
{
|
||||
QVariant ret;
|
||||
bool ok = invokeMethodWithVariants(obj, method, args, &ret, Qt::DirectConnection);
|
||||
emit call_ret(ok, ret);
|
||||
}
|
||||
};
|
||||
|
||||
SyncThread::SyncThread(QObject *parent)
|
||||
:QThread(parent)
|
||||
{
|
||||
qRegisterMetaType<QVariant>("QVariant");
|
||||
qRegisterMetaType<QVariantList>("QVariantList");
|
||||
|
||||
loop = 0;
|
||||
agent = 0;
|
||||
}
|
||||
|
||||
SyncThread::~SyncThread()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void SyncThread::start()
|
||||
{
|
||||
QMutexLocker locker(&m);
|
||||
Q_ASSERT(!loop);
|
||||
QThread::start();
|
||||
w.wait(&m);
|
||||
}
|
||||
|
||||
void SyncThread::stop()
|
||||
{
|
||||
QMutexLocker locker(&m);
|
||||
if(!loop)
|
||||
return;
|
||||
QMetaObject::invokeMethod(loop, "quit");
|
||||
w.wait(&m);
|
||||
wait();
|
||||
}
|
||||
|
||||
QVariant SyncThread::call(QObject *obj, const char *method, const QVariantList &args, bool *ok)
|
||||
{
|
||||
QMutexLocker locker(&m);
|
||||
Q_ASSERT(QMetaObject::invokeMethod(agent, "call_do", Qt::QueuedConnection,
|
||||
Q_ARG(QObject*, obj), Q_ARG(QByteArray, QByteArray(method)), Q_ARG(QVariantList, args)));
|
||||
w.wait(&m);
|
||||
if(ok)
|
||||
*ok = last_success;
|
||||
QVariant v = last_ret;
|
||||
last_ret = QVariant();
|
||||
return v;
|
||||
}
|
||||
|
||||
void SyncThread::run()
|
||||
{
|
||||
m.lock();
|
||||
loop = new QEventLoop;
|
||||
agent = new SyncThreadAgent;
|
||||
connect(agent, SIGNAL(started()), SLOT(agent_started()), Qt::DirectConnection);
|
||||
connect(agent, SIGNAL(call_ret(bool, const QVariant &)), SLOT(agent_call_ret(bool, const QVariant &)), Qt::DirectConnection);
|
||||
loop->exec();
|
||||
m.lock();
|
||||
atEnd();
|
||||
delete agent;
|
||||
delete loop;
|
||||
agent = 0;
|
||||
loop = 0;
|
||||
w.wakeOne();
|
||||
m.unlock();
|
||||
}
|
||||
|
||||
void SyncThread::agent_started()
|
||||
{
|
||||
atStart();
|
||||
w.wakeOne();
|
||||
m.unlock();
|
||||
}
|
||||
|
||||
void SyncThread::agent_call_ret(bool success, const QVariant &ret)
|
||||
{
|
||||
QMutexLocker locker(&m);
|
||||
last_success = success;
|
||||
last_ret = ret;
|
||||
w.wakeOne();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ConsoleWorker
|
||||
//----------------------------------------------------------------------------
|
||||
|
216
src/support/syncthread.cpp
Normal file
216
src/support/syncthread.cpp
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Justin Karneges <justin@affinix.com>
|
||||
*
|
||||
* 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) any later version.
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qca_support.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace QCA {
|
||||
|
||||
QByteArray methodReturnType(const QMetaObject *obj, const QByteArray &method, const QList<QByteArray> argTypes)
|
||||
{
|
||||
for(int n = 0; n < obj->methodCount(); ++n)
|
||||
{
|
||||
QMetaMethod m = obj->method(n);
|
||||
QByteArray sig = m.signature();
|
||||
int offset = sig.indexOf('(');
|
||||
if(offset == -1)
|
||||
continue;
|
||||
QByteArray name = sig.mid(0, offset);
|
||||
if(name != method)
|
||||
continue;
|
||||
if(m.parameterTypes() != argTypes)
|
||||
continue;
|
||||
|
||||
return m.typeName();
|
||||
}
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
bool invokeMethodWithVariants(QObject *obj, const QByteArray &method, const QVariantList &args, QVariant *ret, Qt::ConnectionType type)
|
||||
{
|
||||
// QMetaObject::invokeMethod() has a 10 argument maximum
|
||||
if(args.count() > 10)
|
||||
return false;
|
||||
|
||||
QList<QByteArray> argTypes;
|
||||
for(int n = 0; n < args.count(); ++n)
|
||||
argTypes += args[n].typeName();
|
||||
|
||||
// get return type
|
||||
int metatype = 0;
|
||||
QByteArray retTypeName = methodReturnType(obj->metaObject(), method, argTypes);
|
||||
if(!retTypeName.isEmpty())
|
||||
{
|
||||
metatype = QMetaType::type(retTypeName.data());
|
||||
if(metatype == 0) // lookup failed
|
||||
return false;
|
||||
}
|
||||
|
||||
QGenericArgument arg[10];
|
||||
for(int n = 0; n < args.count(); ++n)
|
||||
arg[n] = QGenericArgument(args[n].typeName(), args[n].constData());
|
||||
|
||||
QGenericReturnArgument retarg;
|
||||
QVariant retval;
|
||||
if(metatype != 0)
|
||||
{
|
||||
retval = QVariant(metatype, (const void *)0);
|
||||
retarg = QGenericReturnArgument(retval.typeName(), retval.data());
|
||||
}
|
||||
|
||||
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]))
|
||||
return false;
|
||||
|
||||
if(retval.isValid() && ret)
|
||||
*ret = retval;
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// SyncThread
|
||||
//----------------------------------------------------------------------------
|
||||
class SyncThreadAgent;
|
||||
|
||||
class SyncThread::Private : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SyncThread *q;
|
||||
QMutex m;
|
||||
QWaitCondition w;
|
||||
QEventLoop *loop;
|
||||
SyncThreadAgent *agent;
|
||||
bool last_success;
|
||||
QVariant last_ret;
|
||||
|
||||
Private(SyncThread *_q) : QObject(_q), q(_q)
|
||||
{
|
||||
loop = 0;
|
||||
agent = 0;
|
||||
}
|
||||
|
||||
private slots:
|
||||
void agent_started();
|
||||
void agent_call_ret(bool success, const QVariant &ret);
|
||||
};
|
||||
|
||||
class SyncThreadAgent : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SyncThreadAgent(QObject *parent = 0) : QObject(parent)
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "started", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
signals:
|
||||
void started();
|
||||
void call_ret(bool success, const QVariant &ret);
|
||||
|
||||
public slots:
|
||||
void call_do(QObject *obj, const QByteArray &method, const QVariantList &args)
|
||||
{
|
||||
QVariant ret;
|
||||
bool ok = invokeMethodWithVariants(obj, method, args, &ret, Qt::DirectConnection);
|
||||
emit call_ret(ok, ret);
|
||||
}
|
||||
};
|
||||
|
||||
SyncThread::SyncThread(QObject *parent)
|
||||
:QThread(parent)
|
||||
{
|
||||
d = new Private(this);
|
||||
qRegisterMetaType<QVariant>("QVariant");
|
||||
qRegisterMetaType<QVariantList>("QVariantList");
|
||||
}
|
||||
|
||||
SyncThread::~SyncThread()
|
||||
{
|
||||
stop();
|
||||
delete d;
|
||||
}
|
||||
|
||||
void SyncThread::start()
|
||||
{
|
||||
QMutexLocker locker(&d->m);
|
||||
Q_ASSERT(!d->loop);
|
||||
QThread::start();
|
||||
d->w.wait(&d->m);
|
||||
}
|
||||
|
||||
void SyncThread::stop()
|
||||
{
|
||||
QMutexLocker locker(&d->m);
|
||||
if(!d->loop)
|
||||
return;
|
||||
QMetaObject::invokeMethod(d->loop, "quit");
|
||||
d->w.wait(&d->m);
|
||||
wait();
|
||||
}
|
||||
|
||||
QVariant SyncThread::call(QObject *obj, const QByteArray &method, const QVariantList &args, bool *ok)
|
||||
{
|
||||
QMutexLocker locker(&d->m);
|
||||
Q_ASSERT(QMetaObject::invokeMethod(d->agent, "call_do", Qt::QueuedConnection,
|
||||
Q_ARG(QObject*, obj), Q_ARG(QByteArray, QByteArray(method)), Q_ARG(QVariantList, args)));
|
||||
d->w.wait(&d->m);
|
||||
if(ok)
|
||||
*ok = d->last_success;
|
||||
QVariant v = d->last_ret;
|
||||
d->last_ret = QVariant();
|
||||
return v;
|
||||
}
|
||||
|
||||
void SyncThread::run()
|
||||
{
|
||||
d->m.lock();
|
||||
d->loop = new QEventLoop;
|
||||
d->agent = new SyncThreadAgent;
|
||||
connect(d->agent, SIGNAL(started()), d, SLOT(agent_started()), Qt::DirectConnection);
|
||||
connect(d->agent, SIGNAL(call_ret(bool, const QVariant &)), d, SLOT(agent_call_ret(bool, const QVariant &)), Qt::DirectConnection);
|
||||
d->loop->exec();
|
||||
d->m.lock();
|
||||
atEnd();
|
||||
delete d->agent;
|
||||
delete d->loop;
|
||||
d->agent = 0;
|
||||
d->loop = 0;
|
||||
d->w.wakeOne();
|
||||
d->m.unlock();
|
||||
}
|
||||
|
||||
void SyncThread::Private::agent_started()
|
||||
{
|
||||
q->atStart();
|
||||
w.wakeOne();
|
||||
m.unlock();
|
||||
}
|
||||
|
||||
void SyncThread::Private::agent_call_ret(bool success, const QVariant &ret)
|
||||
{
|
||||
QMutexLocker locker(&m);
|
||||
last_success = success;
|
||||
last_ret = ret;
|
||||
w.wakeOne();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "syncthread.moc"
|
Loading…
x
Reference in New Issue
Block a user