2
* Copyright (C) 2005 Justin Karneges <justin@affinix.com>
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.
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.
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
20
#include "qca_support.h"
22
#include <QAbstractEventDispatcher>
23
#include <QCoreApplication>
28
#include <QWaitCondition>
30
//#define TIMERFIXER_DEBUG
34
//----------------------------------------------------------------------------
36
//----------------------------------------------------------------------------
37
class TimerFixer : public QObject
48
TimerInfo() : fixInterval(false) {}
51
TimerFixer *fixerParent;
52
QList<TimerFixer*> fixerChildren;
55
QAbstractEventDispatcher *ed;
56
QList<TimerInfo> timers;
58
static bool haveFixer(QObject *obj)
60
return (qFindChild<TimerFixer *>(obj) ? true: false);
63
TimerFixer(QObject *_target, TimerFixer *_fp = 0) : QObject(_target)
70
fixerParent->fixerChildren.append(this);
72
#ifdef TIMERFIXER_DEBUG
73
printf("TimerFixer[%p] pairing with %p (%s)\n", this, target, target->metaObject()->className());
76
target->installEventFilter(this);
78
QObjectList list = target->children();
79
for(int n = 0; n < list.count(); ++n)
86
fixerParent->fixerChildren.removeAll(this);
88
QList<TimerFixer*> list = fixerChildren;
89
for(int n = 0; n < list.count(); ++n)
93
updateTimerList(); // do this just to trip debug output
95
target->removeEventFilter(this);
97
#ifdef TIMERFIXER_DEBUG
98
printf("TimerFixer[%p] unpaired with %p (%s)\n", this, target, target->metaObject()->className());
102
virtual bool event(QEvent *e)
106
case QEvent::ThreadChange: // this happens second
107
//printf("TimerFixer[%p] self changing threads\n", this);
109
QMetaObject::invokeMethod(this, "fixTimers", Qt::QueuedConnection);
115
return QObject::event(e);
118
virtual bool eventFilter(QObject *, QEvent *e)
122
case QEvent::ChildAdded:
123
hook(((QChildEvent *)e)->child());
125
case QEvent::ChildRemoved:
126
unhook(((QChildEvent *)e)->child());
129
handleTimerEvent(((QTimerEvent *)e)->timerId());
131
case QEvent::ThreadChange: // this happens first
132
#ifdef TIMERFIXER_DEBUG
133
printf("TimerFixer[%p] target changing threads\n", this);
146
ed = QAbstractEventDispatcher::instance();
147
//printf("TimerFixer[%p] linking to dispatcher %p\n", this, ed);
148
connect(ed, SIGNAL(aboutToBlock()), SLOT(ed_aboutToBlock()));
153
//printf("TimerFixer[%p] unlinking from dispatcher %p\n", this, ed);
156
disconnect(ed, SIGNAL(aboutToBlock()), this, SLOT(ed_aboutToBlock()));
161
void ed_aboutToBlock()
163
//printf("TimerFixer[%p] aboutToBlock\n", this);
172
for(int n = 0; n < timers.count(); ++n)
174
TimerInfo &info = timers[n];
176
QThread *objectThread = target->thread();
177
QAbstractEventDispatcher *ed = QAbstractEventDispatcher::instance(objectThread);
179
int timeLeft = qMax(info.interval - info.time.elapsed(), 0);
180
info.fixInterval = true;
181
ed->unregisterTimer(info.id);
182
ed->registerTimer(info.id, timeLeft, target);
184
#ifdef TIMERFIXER_DEBUG
185
printf("TimerFixer[%p] adjusting [%d] to %d\n", this, info.id, timeLeft);
191
void hook(QObject *obj)
193
// don't watch a fixer or any object that already has one
194
if(obj == this || qobject_cast<TimerFixer *>(obj) || haveFixer(obj))
197
new TimerFixer(obj, this);
200
void unhook(QObject *obj)
203
for(int n = 0; n < fixerChildren.count(); ++n)
205
if(fixerChildren[n]->target == obj)
206
t = fixerChildren[n];
211
void handleTimerEvent(int id)
215
for(n = 0; n < timers.count(); ++n)
217
if(timers[n].id == id)
225
//printf("*** unrecognized timer [%d] activated ***\n", id);
229
TimerInfo &info = timers[n];
230
#ifdef TIMERFIXER_DEBUG
231
printf("TimerFixer[%p] timer [%d] activated!\n", this, info.id);
236
#ifdef TIMERFIXER_DEBUG
237
printf("restoring correct interval (%d)\n", info.interval);
239
info.fixInterval = false;
240
ed->unregisterTimer(info.id);
241
ed->registerTimer(info.id, info.interval, target);
247
void updateTimerList()
249
QList<QAbstractEventDispatcher::TimerInfo> edtimers;
251
edtimers = ed->registeredTimers(target);
254
for(int n = 0; n < timers.count(); ++n)
257
int id = timers[n].id;
258
for(int i = 0; i < edtimers.count(); ++i)
260
if(edtimers[i].first == id)
271
#ifdef TIMERFIXER_DEBUG
272
printf("TimerFixer[%p] timer [%d] removed\n", this, id);
278
for(int n = 0; n < edtimers.count(); ++n)
280
int id = edtimers[n].first;
282
for(int i = 0; i < timers.count(); ++i)
284
if(timers[i].id == id)
295
info.interval = edtimers[n].second;
298
#ifdef TIMERFIXER_DEBUG
299
printf("TimerFixer[%p] timer [%d] added (interval=%d)\n", this, info.id, info.interval);
306
//----------------------------------------------------------------------------
308
//----------------------------------------------------------------------------
309
class Synchronizer::Private : public QThread
324
QThread *orig_thread;
326
Private(QObject *_obj, Synchronizer *_q) : QThread(_q), q(_q)
331
fixer = new TimerFixer(obj);
366
bool waitForCondition(int msecs)
368
unsigned long time = ULONG_MAX;
372
// move object to the worker thread
374
orig_thread = QThread::currentThread();
375
q->setParent(0); // don't follow the object
376
QObject *orig_parent = obj->parent();
377
obj->setParent(0); // unparent the target or the move will fail
378
obj->moveToThread(this);
380
// tell the worker thread to start, wait for completion
383
if(!w.wait(&m, time))
387
// if we timed out, tell the worker to quit
388
QMetaObject::invokeMethod(loop, "quit");
393
// at this point the worker is done. cleanup and return
397
obj->setParent(orig_parent);
415
QEventLoop eventLoop;
419
// thread now sleeps, waiting for work
431
// run the event loop
434
// eventloop done, flush pending events
435
QCoreApplication::instance()->sendPostedEvents();
436
QCoreApplication::instance()->sendPostedEvents(0, QEvent::DeferredDelete);
438
// and move the object back
439
obj->moveToThread(orig_thread);
448
Synchronizer::Synchronizer(QObject *parent)
451
d = new Private(parent, this);
454
Synchronizer::~Synchronizer()
459
bool Synchronizer::waitForCondition(int msecs)
462
return d->waitForCondition(msecs);
465
void Synchronizer::conditionMet()
472
#include "synchronizer.moc"