+ , width(w)
+ , height(h)
+ , d(new DrawingWindowPrivate(this, f))
+{
+ d->initialize();
+}
+
+DrawingWindow::~DrawingWindow()
+{
+ delete d;
+}
+
+void DrawingWindow::setColor(float red, float green, float blue)
+{
+ d->fgColor.setRgbF(red, green, blue);
+ QPen pen(d->painter->pen());
+ pen.setColor(d->fgColor);
+ d->painter->setPen(pen);
+}
+
+void DrawingWindow::setBgColor(float red, float green, float blue)
+{
+ d->bgColor.setRgbF(red, green, blue);
+}
+
+void DrawingWindow::clearGraph()
+{
+ d->safeLock(d->imageMutex);
+ d->painter->fillRect(d->image->rect(), d->bgColor);
+ d->dirty();
+ d->safeUnlock(d->imageMutex);
+}
+
+void DrawingWindow::drawPoint(int x, int y)
+{
+ d->safeLock(d->imageMutex);
+ d->painter->drawPoint(x, y);
+ d->dirty(x, y);
+ d->safeUnlock(d->imageMutex);
+}
+
+void DrawingWindow::drawLine(int x1, int y1, int x2, int y2)
+{
+ d->safeLock(d->imageMutex);
+ d->painter->drawLine(x1, y1, x2, y2);
+ d->dirty(x1, y1, x2, y2);
+ d->safeUnlock(d->imageMutex);
+}
+
+void DrawingWindow::drawRect(int x1, int y1, int x2, int y2)
+{
+ QRect r;
+ r.setCoords(x1, y1, x2, y2);
+ r = r.normalized();
+ d->safeLock(d->imageMutex);
+ d->painter->drawRect(r);
+ r.adjust(0, 0, 1, 1);
+ d->dirty(r);
+ d->safeUnlock(d->imageMutex);
+}
+
+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;
+}
+
+void DrawingWindow::sleep(unsigned long secs)
+{
+ DrawingThread::sleep(secs);
+}
+
+void DrawingWindow::msleep(unsigned long msecs)
+{
+ DrawingThread::msleep(msecs);
+}
+
+void DrawingWindow::usleep(unsigned long usecs)
+{
+ DrawingThread::usleep(usecs);
+}
+
+void DrawingWindow::closeEvent(QCloseEvent *ev)
+{
+ d->timer.stop();
+ d->thread->terminate();
+ d->paintCondition.wakeAll();
+ QWidget::closeEvent(ev);
+ d->thread->wait();
+}
+
+void DrawingWindow::paintEvent(QPaintEvent *ev)
+{
+ QPainter widgetPainter(this);
+ d->imageMutex.lock();
+ QImage imageCopy(*d->image);
+ 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)
+{
+ d->timer.start(d->paintInterval, this);
+ d->thread->start_once(QThread::IdlePriority);
+ QWidget::showEvent(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->timer.start(d->paintInterval, this);
+ } else {
+ QWidget::timerEvent(ev);
+ }
+}
+
+//--- DrawingWindowPrivate ---------------------------------------------
+
+DrawingWindowPrivate::DrawingWindowPrivate(DrawingWindow *w,
+ DrawingWindow::ThreadFunction f)
+ : q(w)
+ , lockCount(0)
+ , image(new QImage(q->width, q->height, QImage::Format_RGB32))
+ , painter(new QPainter(image))
+ , thread(new DrawingThread(*q, f))