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)
159 d->safeLock(d->syncMutex);
160 qApp->postEvent(this, new QEvent(QEvent::User));
161 bool synced = d->syncCondition.wait(&d->syncMutex, time);
162 d->safeUnlock(d->syncMutex);
166 void DrawingWindow::sleep(unsigned long secs)
168 DrawingThread::sleep(secs);
171 void DrawingWindow::msleep(unsigned long msecs)
173 DrawingThread::msleep(msecs);
176 void DrawingWindow::usleep(unsigned long usecs)
178 DrawingThread::usleep(usecs);
181 void DrawingWindow::closeEvent(QCloseEvent *ev)
184 d->thread->terminate();
186 d->syncCondition.wakeAll();
187 d->syncMutex.unlock();
188 QWidget::closeEvent(ev);
192 void DrawingWindow::customEvent(QEvent *)
196 qApp->sendPostedEvents(this, QEvent::UpdateLater);
197 qApp->sendPostedEvents(this, QEvent::UpdateRequest);
198 qApp->sendPostedEvents(this, QEvent::Paint);
199 if (0) { // Disabled because this can lead to
200 // dead-lock if a close event is
202 qApp->processEvents(QEventLoop::ExcludeUserInputEvents |
203 QEventLoop::ExcludeSocketNotifiers |
204 QEventLoop::DeferredDeletion |
205 QEventLoop::X11ExcludeTimers);
209 d->syncCondition.wakeAll();
210 d->syncMutex.unlock();
213 void DrawingWindow::keyPressEvent(QKeyEvent *ev)
228 void DrawingWindow::paintEvent(QPaintEvent *ev)
230 QPainter widgetPainter(this);
231 d->imageMutex.lock();
232 QImage imageCopy(*d->image);
233 d->imageMutex.unlock();
234 QRect rect = ev->rect();
235 widgetPainter.drawImage(rect, imageCopy, rect);
238 void DrawingWindow::showEvent(QShowEvent *ev)
240 d->timer.start(d->paintInterval, this);
241 d->thread->start_once(QThread::IdlePriority);
242 QWidget::showEvent(ev);
245 void DrawingWindow::timerEvent(QTimerEvent *ev)
247 if (ev->timerId() == d->timer.timerId()) {
249 d->timer.start(d->paintInterval, this);
251 QWidget::timerEvent(ev);
255 //--- DrawingWindowPrivate ---------------------------------------------
257 DrawingWindowPrivate::DrawingWindowPrivate(DrawingWindow *w,
258 DrawingWindow::ThreadFunction f)
261 , image(new QImage(q->width, q->height, QImage::Format_RGB32))
262 , painter(new QPainter(image))
263 , thread(new DrawingThread(*q, f))
267 void DrawingWindowPrivate::initialize()
269 q->setFocusPolicy(Qt::StrongFocus);
270 q->setFixedSize(image->size());
271 q->setAttribute(Qt::WA_OpaquePaintEvent);
274 q->setColor(0.0, 0.0, 0.0); // black
275 q->setBgColor(1.0, 1.0, 1.0); // white
281 DrawingWindowPrivate::~DrawingWindowPrivate()
289 void DrawingWindowPrivate::safeLock(QMutex &mutex)
291 if (lockCount++ == 0)
292 thread->setTerminationEnabled(false);
297 void DrawingWindowPrivate::safeUnlock(QMutex &mutex)
300 if (--lockCount == 0)
301 thread->setTerminationEnabled(true);
305 void DrawingWindowPrivate::dirty()
308 dirtyRect = image->rect();
312 void DrawingWindowPrivate::dirty(int x, int y)
314 dirty(QRect(x, y, 1, 1));
318 void DrawingWindowPrivate::dirty(int x1, int y1, int x2, int y2)
321 r.setCoords(x1, y1, x2, y2);
322 dirty(r.normalized());
325 void DrawingWindowPrivate::dirty(const QRect &rect)
335 void DrawingWindowPrivate::update()
338 bool dirty = dirtyFlag;
339 QRect rect = dirtyRect;
346 //--- DrawingThread ----------------------------------------------------
348 DrawingThread::DrawingThread(DrawingWindow &w, DrawingWindow::ThreadFunction f)
351 , started_once(false)
355 void DrawingThread::start_once(Priority priority)
363 void DrawingThread::run()
365 threadFunction(drawingWindow);