QBasicTimer timer;
QMutex imageMutex;
- QMutex paintMutex;
- QWaitCondition paintCondition;
- bool painted;
+ QMutex syncMutex;
+ QWaitCondition syncCondition;
+ bool terminateThread;
int lockCount;
QImage *image;
void dirty(int x1, int y1, int x2, int y2);
void dirty(const QRect &rect);
+ void update();
};
//--- DrawingWindow ----------------------------------------------------
bool DrawingWindow::sync(unsigned long time)
{
- bool ret;
- d->safeLock(d->paintMutex);
- d->safeLock(d->imageMutex);
-#if 1
- d->dirty(); // xxx
-#else
- QApplication::postEvent(this, new QPaintEvent(this->rect()));
- d->dirtyFlag = false;
-#endif
- d->safeUnlock(d->imageMutex);
- ret = d->paintCondition.wait(&d->paintMutex, time);
- d->safeUnlock(d->paintMutex);
- return ret;
+ bool synced;
+ d->safeLock(d->syncMutex);
+ if (d->terminateThread) {
+ synced = false;
+ } else {
+ qApp->postEvent(this, new QEvent(QEvent::User));
+ synced = d->syncCondition.wait(&d->syncMutex, time);
+ }
+ d->safeUnlock(d->syncMutex);
+ return synced;
}
void DrawingWindow::sleep(unsigned long secs)
{
d->timer.stop();
d->thread->terminate();
- d->paintCondition.wakeAll();
+ d->syncMutex.lock();
+ d->terminateThread = true; // this flag is needed for the case
+ // where the following wakeAll() call
+ // occurs between the
+ // setTerminationEnable(false) and the
+ // mutex lock in safeLock() called
+ // from sync()
+ d->syncCondition.wakeAll();
+ d->syncMutex.unlock();
QWidget::closeEvent(ev);
d->thread->wait();
}
+void DrawingWindow::customEvent(QEvent *)
+{
+ d->update();
+ qApp->sendPostedEvents(this, QEvent::UpdateLater);
+ qApp->sendPostedEvents(this, QEvent::UpdateRequest);
+ qApp->sendPostedEvents(this, QEvent::Paint);
+ qApp->processEvents(QEventLoop::ExcludeUserInputEvents |
+ QEventLoop::ExcludeSocketNotifiers |
+ QEventLoop::DeferredDeletion |
+ QEventLoop::X11ExcludeTimers);
+ qApp->flush();
+ qApp->syncX();
+ d->syncMutex.lock();
+ d->syncCondition.wakeAll();
+ d->syncMutex.unlock();
+}
+
+void DrawingWindow::keyPressEvent(QKeyEvent *ev)
+{
+ bool accept = true;
+ switch (ev->key()) {
+ case Qt::Key_Escape:
+ close();
+ break;
+ default:
+ accept = false;
+ break;
+ }
+ if (accept)
+ ev->accept();
+}
+
void DrawingWindow::paintEvent(QPaintEvent *ev)
{
QPainter widgetPainter(this);
d->imageMutex.unlock();
QRect rect = ev->rect();
widgetPainter.drawImage(rect, imageCopy, rect);
- if (rect == this->rect()) {
- d->paintMutex.lock();
- d->paintCondition.wakeAll();
- d->paintMutex.unlock();
- }
}
void DrawingWindow::showEvent(QShowEvent *ev)
void DrawingWindow::timerEvent(QTimerEvent *ev)
{
if (ev->timerId() == d->timer.timerId()) {
- d->imageMutex.lock();
- if (d->dirtyFlag) {
- update(d->dirtyRect);
- d->dirtyFlag = false;
- }
- d->imageMutex.unlock();
+ d->update();
d->timer.start(d->paintInterval, this);
} else {
QWidget::timerEvent(ev);
DrawingWindowPrivate::DrawingWindowPrivate(DrawingWindow *w,
DrawingWindow::ThreadFunction f)
: q(w)
+ , terminateThread(false)
, lockCount(0)
, image(new QImage(q->width, q->height, QImage::Format_RGB32))
, painter(new QPainter(image))
}
}
+void DrawingWindowPrivate::update()
+{
+ imageMutex.lock();
+ bool dirty = dirtyFlag;
+ QRect rect = dirtyRect;
+ dirtyFlag = false;
+ imageMutex.unlock();
+ if (dirty)
+ q->update(rect);
+}
+
//--- DrawingThread ----------------------------------------------------
DrawingThread::DrawingThread(DrawingWindow &w, DrawingWindow::ThreadFunction f)