1 #include "DrawingWindow.h"
2 #include <QApplication>
11 #include <QTimerEvent>
12 #include <QWaitCondition>
14 class DrawingThread: public QThread {
16 DrawingThread(DrawingWindow &w, DrawingWindow::ThreadFunction f);
17 void start_once(Priority priority = InheritPriority);
23 DrawingWindow &drawingWindow;
24 DrawingWindow::ThreadFunction threadFunction;
27 friend class DrawingWindow;
28 friend class DrawingWindowPrivate;
31 class DrawingWindowPrivate {
33 static const int paintInterval = 33;
35 DrawingWindow * const q;
40 QWaitCondition syncCondition;
53 DrawingThread *thread;
55 DrawingWindowPrivate(DrawingWindow *w,
56 DrawingWindow::ThreadFunction f);
57 ~DrawingWindowPrivate();
63 void safeLock(QMutex &mutex);
64 void safeUnlock(QMutex &mutex);
67 void dirty(int x, int y);
68 void dirty(int x1, int y1, int x2, int y2);
69 void dirty(const QRect &rect);
74 //--- DrawingWindow ----------------------------------------------------
76 DrawingWindow::DrawingWindow(ThreadFunction f, int w, int h)
80 , d(new DrawingWindowPrivate(this, f))
85 DrawingWindow::DrawingWindow(QWidget *parent,
86 ThreadFunction f, int w, int h)
90 , d(new DrawingWindowPrivate(this, f))
95 DrawingWindow::DrawingWindow(QWidget *parent, Qt::WindowFlags flags,
96 ThreadFunction f, int w, int h)
97 : QWidget(parent, flags)
100 , d(new DrawingWindowPrivate(this, f))
105 DrawingWindow::~DrawingWindow()
110 void DrawingWindow::setColor(float red, float green, float blue)
112 d->fgColor.setRgbF(red, green, blue);
116 void DrawingWindow::setColor(const char *name)
118 d->fgColor.setNamedColor(name);
122 void DrawingWindow::setBgColor(float red, float green, float blue)
124 d->bgColor.setRgbF(red, green, blue);
127 void DrawingWindow::setBgColor(const char *name)
129 d->bgColor.setNamedColor(name);
132 void DrawingWindow::clearGraph()
134 d->safeLock(d->imageMutex);
135 d->painter->fillRect(d->image->rect(), d->bgColor);
137 d->safeUnlock(d->imageMutex);
140 void DrawingWindow::drawPoint(int x, int y)
142 d->safeLock(d->imageMutex);
143 d->painter->drawPoint(x, y);
145 d->safeUnlock(d->imageMutex);
148 void DrawingWindow::drawLine(int x1, int y1, int x2, int y2)
150 d->safeLock(d->imageMutex);
151 d->painter->drawLine(x1, y1, x2, y2);
152 d->dirty(x1, y1, x2, y2);
153 d->safeUnlock(d->imageMutex);
156 void DrawingWindow::drawRect(int x1, int y1, int x2, int y2)
159 r.setCoords(x1, y1, x2 - 1, y2 - 1);
161 d->safeLock(d->imageMutex);
162 d->painter->drawRect(r);
163 r.adjust(0, 0, 1, 1);
165 d->safeUnlock(d->imageMutex);
168 void DrawingWindow::fillRect(int x1, int y1, int x2, int y2)
170 d->painter->setBrush(d->fgColor);
171 drawRect(x1, y1, x2, y2);
172 d->painter->setBrush(Qt::NoBrush);
175 void DrawingWindow::drawCircle(int x, int y, int r)
178 rect.setCoords(x - r, y - r, x + r - 1, y + r - 1);
179 d->safeLock(d->imageMutex);
180 d->painter->drawEllipse(rect);
181 rect.adjust(0, 0, 1, 1);
183 d->safeUnlock(d->imageMutex);
186 void DrawingWindow::fillCircle(int x, int y, int r)
188 d->painter->setBrush(d->fgColor);
190 d->painter->setBrush(Qt::NoBrush);
193 bool DrawingWindow::sync(unsigned long time)
196 d->safeLock(d->syncMutex);
197 if (d->terminateThread) {
200 qApp->postEvent(this, new QEvent(QEvent::User));
201 synced = d->syncCondition.wait(&d->syncMutex, time);
203 d->safeUnlock(d->syncMutex);
207 void DrawingWindow::sleep(unsigned long secs)
209 DrawingThread::sleep(secs);
212 void DrawingWindow::msleep(unsigned long msecs)
214 DrawingThread::msleep(msecs);
217 void DrawingWindow::usleep(unsigned long usecs)
219 DrawingThread::usleep(usecs);
222 void DrawingWindow::closeEvent(QCloseEvent *ev)
225 d->thread->terminate();
227 d->terminateThread = true; // this flag is needed for the case
228 // where the following wakeAll() call
229 // occurs between the
230 // setTerminationEnable(false) and the
231 // mutex lock in safeLock() called
233 d->syncCondition.wakeAll();
234 d->syncMutex.unlock();
235 QWidget::closeEvent(ev);
239 void DrawingWindow::customEvent(QEvent *)
242 qApp->sendPostedEvents(this, QEvent::UpdateLater);
243 qApp->sendPostedEvents(this, QEvent::UpdateRequest);
244 qApp->sendPostedEvents(this, QEvent::Paint);
245 qApp->processEvents(QEventLoop::ExcludeUserInputEvents |
246 QEventLoop::ExcludeSocketNotifiers |
247 QEventLoop::DeferredDeletion |
248 QEventLoop::X11ExcludeTimers);
252 d->syncCondition.wakeAll();
253 d->syncMutex.unlock();
256 void DrawingWindow::keyPressEvent(QKeyEvent *ev)
271 void DrawingWindow::paintEvent(QPaintEvent *ev)
273 QPainter widgetPainter(this);
274 d->imageMutex.lock();
275 QImage imageCopy(*d->image);
276 d->imageMutex.unlock();
277 QRect rect = ev->rect();
278 widgetPainter.drawImage(rect, imageCopy, rect);
281 void DrawingWindow::showEvent(QShowEvent *ev)
283 d->timer.start(d->paintInterval, this);
284 d->thread->start_once(QThread::IdlePriority);
285 QWidget::showEvent(ev);
288 void DrawingWindow::timerEvent(QTimerEvent *ev)
290 if (ev->timerId() == d->timer.timerId()) {
292 d->timer.start(d->paintInterval, this);
294 QWidget::timerEvent(ev);
298 //--- DrawingWindowPrivate ---------------------------------------------
300 DrawingWindowPrivate::DrawingWindowPrivate(DrawingWindow *w,
301 DrawingWindow::ThreadFunction f)
303 , terminateThread(false)
305 , image(new QImage(q->width, q->height, QImage::Format_RGB32))
306 , painter(new QPainter(image))
307 , thread(new DrawingThread(*q, f))
311 void DrawingWindowPrivate::initialize()
313 q->setFocusPolicy(Qt::StrongFocus);
314 q->setFixedSize(image->size());
315 q->setAttribute(Qt::WA_OpaquePaintEvent);
318 q->setColor("black");
319 q->setBgColor("white");
325 DrawingWindowPrivate::~DrawingWindowPrivate()
333 void DrawingWindowPrivate::applyColor()
335 QPen pen(painter->pen());
336 pen.setColor(fgColor);
337 painter->setPen(pen);
341 void DrawingWindowPrivate::safeLock(QMutex &mutex)
343 if (lockCount++ == 0)
344 thread->setTerminationEnabled(false);
349 void DrawingWindowPrivate::safeUnlock(QMutex &mutex)
352 if (--lockCount == 0)
353 thread->setTerminationEnabled(true);
357 void DrawingWindowPrivate::dirty()
360 dirtyRect = image->rect();
364 void DrawingWindowPrivate::dirty(int x, int y)
366 dirty(QRect(x, y, 1, 1));
370 void DrawingWindowPrivate::dirty(int x1, int y1, int x2, int y2)
373 r.setCoords(x1, y1, x2, y2);
374 dirty(r.normalized());
377 void DrawingWindowPrivate::dirty(const QRect &rect)
387 void DrawingWindowPrivate::update()
390 bool dirty = dirtyFlag;
391 QRect rect = dirtyRect;
398 //--- DrawingThread ----------------------------------------------------
400 DrawingThread::DrawingThread(DrawingWindow &w, DrawingWindow::ThreadFunction f)
403 , started_once(false)
407 void DrawingThread::start_once(Priority priority)
415 void DrawingThread::run()
417 threadFunction(drawingWindow);