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();
61 void safeLock(QMutex &mutex);
62 void safeUnlock(QMutex &mutex);
65 void dirty(int x, int y);
66 void dirty(int x1, int y1, int x2, int y2);
67 void dirty(const QRect &rect);
72 //--- DrawingWindow ----------------------------------------------------
74 DrawingWindow::DrawingWindow(ThreadFunction f, int w, int h)
78 , d(new DrawingWindowPrivate(this, f))
83 DrawingWindow::DrawingWindow(QWidget *parent,
84 ThreadFunction f, int w, int h)
88 , d(new DrawingWindowPrivate(this, f))
93 DrawingWindow::DrawingWindow(QWidget *parent, Qt::WindowFlags flags,
94 ThreadFunction f, int w, int h)
95 : QWidget(parent, flags)
98 , d(new DrawingWindowPrivate(this, f))
103 DrawingWindow::~DrawingWindow()
108 void DrawingWindow::setColor(float red, float green, float blue)
110 d->fgColor.setRgbF(red, green, blue);
111 QPen pen(d->painter->pen());
112 pen.setColor(d->fgColor);
113 d->painter->setPen(pen);
116 void DrawingWindow::setBgColor(float red, float green, float blue)
118 d->bgColor.setRgbF(red, green, blue);
121 void DrawingWindow::clearGraph()
123 d->safeLock(d->imageMutex);
124 d->painter->fillRect(d->image->rect(), d->bgColor);
126 d->safeUnlock(d->imageMutex);
129 void DrawingWindow::drawPoint(int x, int y)
131 d->safeLock(d->imageMutex);
132 d->painter->drawPoint(x, y);
134 d->safeUnlock(d->imageMutex);
137 void DrawingWindow::drawLine(int x1, int y1, int x2, int y2)
139 d->safeLock(d->imageMutex);
140 d->painter->drawLine(x1, y1, x2, y2);
141 d->dirty(x1, y1, x2, y2);
142 d->safeUnlock(d->imageMutex);
145 void DrawingWindow::drawRect(int x1, int y1, int x2, int y2)
148 r.setCoords(x1, y1, x2, y2);
150 d->safeLock(d->imageMutex);
151 d->painter->drawRect(r);
152 r.adjust(0, 0, 1, 1);
154 d->safeUnlock(d->imageMutex);
157 bool DrawingWindow::sync(unsigned long time)
160 d->safeLock(d->syncMutex);
161 if (d->terminateThread) {
164 qApp->postEvent(this, new QEvent(QEvent::User));
165 synced = d->syncCondition.wait(&d->syncMutex, time);
167 d->safeUnlock(d->syncMutex);
171 void DrawingWindow::sleep(unsigned long secs)
173 DrawingThread::sleep(secs);
176 void DrawingWindow::msleep(unsigned long msecs)
178 DrawingThread::msleep(msecs);
181 void DrawingWindow::usleep(unsigned long usecs)
183 DrawingThread::usleep(usecs);
186 void DrawingWindow::closeEvent(QCloseEvent *ev)
189 d->thread->terminate();
191 d->terminateThread = true; // this flag is needed for the case
192 // where the following wakeAll() call
193 // occurs between the
194 // setTerminationEnable(false) and the
195 // mutex lock in safeLock() called
197 d->syncCondition.wakeAll();
198 d->syncMutex.unlock();
199 QWidget::closeEvent(ev);
203 void DrawingWindow::customEvent(QEvent *)
206 qApp->sendPostedEvents(this, QEvent::UpdateLater);
207 qApp->sendPostedEvents(this, QEvent::UpdateRequest);
208 qApp->sendPostedEvents(this, QEvent::Paint);
209 qApp->processEvents(QEventLoop::ExcludeUserInputEvents |
210 QEventLoop::ExcludeSocketNotifiers |
211 QEventLoop::DeferredDeletion |
212 QEventLoop::X11ExcludeTimers);
216 d->syncCondition.wakeAll();
217 d->syncMutex.unlock();
220 void DrawingWindow::keyPressEvent(QKeyEvent *ev)
235 void DrawingWindow::paintEvent(QPaintEvent *ev)
237 QPainter widgetPainter(this);
238 d->imageMutex.lock();
239 QImage imageCopy(*d->image);
240 d->imageMutex.unlock();
241 QRect rect = ev->rect();
242 widgetPainter.drawImage(rect, imageCopy, rect);
245 void DrawingWindow::showEvent(QShowEvent *ev)
247 d->timer.start(d->paintInterval, this);
248 d->thread->start_once(QThread::IdlePriority);
249 QWidget::showEvent(ev);
252 void DrawingWindow::timerEvent(QTimerEvent *ev)
254 if (ev->timerId() == d->timer.timerId()) {
256 d->timer.start(d->paintInterval, this);
258 QWidget::timerEvent(ev);
262 //--- DrawingWindowPrivate ---------------------------------------------
264 DrawingWindowPrivate::DrawingWindowPrivate(DrawingWindow *w,
265 DrawingWindow::ThreadFunction f)
267 , terminateThread(false)
269 , image(new QImage(q->width, q->height, QImage::Format_RGB32))
270 , painter(new QPainter(image))
271 , thread(new DrawingThread(*q, f))
275 void DrawingWindowPrivate::initialize()
277 q->setFocusPolicy(Qt::StrongFocus);
278 q->setFixedSize(image->size());
279 q->setAttribute(Qt::WA_OpaquePaintEvent);
282 q->setColor(0.0, 0.0, 0.0); // black
283 q->setBgColor(1.0, 1.0, 1.0); // white
289 DrawingWindowPrivate::~DrawingWindowPrivate()
297 void DrawingWindowPrivate::safeLock(QMutex &mutex)
299 if (lockCount++ == 0)
300 thread->setTerminationEnabled(false);
305 void DrawingWindowPrivate::safeUnlock(QMutex &mutex)
308 if (--lockCount == 0)
309 thread->setTerminationEnabled(true);
313 void DrawingWindowPrivate::dirty()
316 dirtyRect = image->rect();
320 void DrawingWindowPrivate::dirty(int x, int y)
322 dirty(QRect(x, y, 1, 1));
326 void DrawingWindowPrivate::dirty(int x1, int y1, int x2, int y2)
329 r.setCoords(x1, y1, x2, y2);
330 dirty(r.normalized());
333 void DrawingWindowPrivate::dirty(const QRect &rect)
343 void DrawingWindowPrivate::update()
346 bool dirty = dirtyFlag;
347 QRect rect = dirtyRect;
354 //--- DrawingThread ----------------------------------------------------
356 DrawingThread::DrawingThread(DrawingWindow &w, DrawingWindow::ThreadFunction f)
359 , started_once(false)
363 void DrawingThread::start_once(Priority priority)
371 void DrawingThread::run()
373 threadFunction(drawingWindow);