1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 - 2012 Research In Motion <blackberry-qt@qnx.com>
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 // #define QBBWINDOW_DEBUG
43 
44 #include "qbbwindow.h"
45 #include "qbbglcontext.h"
46 #include "qbbscreen.h"
47 
48 #include <QtGui/QWidget>
49 #include <QDebug>
50 #include <QtGui/QPlatformWindowFormat>
51 #include <QtGui/QWindowSystemInterface>
52 
53 #include <errno.h>
54 
55 QT_BEGIN_NAMESPACE
56 
QBBWindow(QWidget * window,screen_context_t context,QBBScreen * screen)57 QBBWindow::QBBWindow(QWidget *window, screen_context_t context, QBBScreen *screen)
58     : QPlatformWindow(window),
59       mContext(context),
60       mCurrentBufferIndex(-1),
61       mPreviousBufferIndex(-1),
62       mPlatformGlContext(NULL),
63       mScreen(NULL),
64       mParent(NULL),
65       mVisible(true)
66 {
67 #if defined(QBBWINDOW_DEBUG)
68     qDebug() << "QBBWindow::QBBWindow - w=" << window << ", s=" << window->size();
69 #endif
70     int result;
71 
72     // create child QNX window
73     errno = 0;
74     result = screen_create_window_type(&mWindow, mContext, SCREEN_CHILD_WINDOW);
75     if (result != 0) {
76         qFatal("QBBWindow: failed to create window, errno=%d", errno);
77     }
78 
79     // set window buffer usage based on rendering API
80     int val;
81     QPlatformWindowFormat format = widget()->platformWindowFormat();
82     switch (format.windowApi()) {
83     case QPlatformWindowFormat::Raster:
84         val = SCREEN_USAGE_NATIVE | SCREEN_USAGE_READ | SCREEN_USAGE_WRITE;
85         break;
86     case QPlatformWindowFormat::OpenGL:
87         val = SCREEN_USAGE_OPENGL_ES2;
88         break;
89     default:
90         qFatal("QBBWindow: unsupported window API");
91         break;
92     }
93 
94     errno = 0;
95     result = screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_USAGE, &val);
96     if (result != 0) {
97         qFatal("QBBWindow: failed to set window buffer usage, errno=%d", errno);
98     }
99 
100     // alpha channel is always pre-multiplied if present
101     errno = 0;
102     val = SCREEN_PRE_MULTIPLIED_ALPHA;
103     result = screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_ALPHA_MODE, &val);
104     if (result != 0) {
105         qFatal("QBBWindow: failed to set window alpha mode, errno=%d", errno);
106     }
107 
108     // make the window opaque
109     errno = 0;
110     val = SCREEN_TRANSPARENCY_NONE;
111     result = screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_TRANSPARENCY, &val);
112     if (result != 0) {
113         qFatal("QBBWindow: failed to set window transparency, errno=%d", errno);
114     }
115 
116     // set the window swap interval
117     errno = 0;
118     val = 1;
119     result = screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_SWAP_INTERVAL, &val);
120     if (result != 0) {
121         qFatal("QBBWindow: failed to set window swap interval, errno=%d", errno);
122     }
123 
124     // Set the screen to the primary display (this is the default specified by screen).
125     setScreen(screen);
126 
127     // Qt somtimes doesn't call these setters after creating the window, so we need to do that
128     // ourselves here
129     if (window->parentWidget() && window->parentWidget()->platformWindow())
130         setParent(window->parentWidget()->platformWindow());
131     setGeometry(window->geometry());
132     setVisible(window->isVisible());
133 }
134 
~QBBWindow()135 QBBWindow::~QBBWindow()
136 {
137 #if defined(QBBWINDOW_DEBUG)
138     qDebug() << "QBBWindow::~QBBWindow - w=" << widget();
139 #endif
140 
141     // Qt should have already deleted the children before deleting the parent.
142     Q_ASSERT(mChildren.size() == 0);
143 
144     // Remove from parent's Hierarchy.
145     removeFromParent();
146     mScreen->updateHierarchy();
147 
148     // cleanup OpenGL/OpenVG context if it exists
149     if (mPlatformGlContext != NULL) {
150         delete mPlatformGlContext;
151     }
152 
153     // cleanup QNX window and its buffers
154     screen_destroy_window(mWindow);
155 }
156 
setGeometry(const QRect & rect)157 void QBBWindow::setGeometry(const QRect &rect)
158 {
159     int val[2];
160 
161 #if defined(QBBWINDOW_DEBUG)
162     qDebug() << "QBBWindow::setGeometry - w=" << widget() << ", (" << rect.x() << "," << rect.y() << "," << rect.width() << "," << rect.height() << ")";
163 #endif
164 
165     QRect oldGeometry = geometry();
166 
167     // call parent method
168     QPlatformWindow::setGeometry(rect);
169 
170     // set window geometry equal to widget geometry
171     errno = 0;
172     val[0] = rect.x();
173     val[1] = rect.y();
174     int result = screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_POSITION, val);
175     if (result != 0) {
176         qFatal("QBBWindow: failed to set window position, errno=%d", errno);
177     }
178 
179     errno = 0;
180     val[0] = rect.width();
181     val[1] = rect.height();
182     result = screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_SIZE, val);
183     if (result != 0) {
184         qFatal("QBBWindow: failed to set window size, errno=%d", errno);
185     }
186 
187     // set viewport size equal to window size
188     errno = 0;
189     result = screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_SOURCE_SIZE, val);
190     if (result != 0) {
191         qFatal("QBBWindow: failed to set window source size, errno=%d", errno);
192     }
193 
194     // Now move all children.
195     QPoint offset;
196     if (!oldGeometry.isEmpty()) {
197         offset = rect.topLeft();
198         offset -= oldGeometry.topLeft();
199 
200         QList<QBBWindow*>::iterator it;
201         for (it = mChildren.begin(); it != mChildren.end(); it++) {
202             (*it)->offset(offset);
203         }
204     }
205 }
206 
offset(const QPoint & offset)207 void QBBWindow::offset(const QPoint &offset)
208 {
209     // Move self and then children.
210     QRect newGeometry = geometry();
211     newGeometry.translate(offset);
212 
213     // call the base class
214     QPlatformWindow::setGeometry(newGeometry);
215 
216     int val[2];
217 
218     errno = 0;
219     val[0] = newGeometry.x();
220     val[1] = newGeometry.y();
221     int result = screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_POSITION, val);
222     if (result != 0) {
223         qFatal("QBBWindow: failed to set window position, errno=%d", errno);
224     }
225 
226     QList<QBBWindow*>::iterator it;
227     for (it = mChildren.begin(); it != mChildren.end(); it++) {
228         (*it)->offset(offset);
229     }
230 }
231 
setVisible(bool visible)232 void QBBWindow::setVisible(bool visible)
233 {
234 #if defined(QBBWINDOW_DEBUG)
235     qDebug() << "QBBWindow::setVisible - w=" << widget() << ", v=" << visible;
236 #endif
237 
238     mVisible = visible;
239 
240     QBBWindow* root = this;
241     while (root->mParent)
242         root = root->mParent;
243 
244     root->updateVisibility(root->mVisible);
245 
246     widget()->activateWindow();
247 
248     // Flush the context when invisible, otherwise it won't disappear immediately,
249     // but still allow navigator to capture screenshot (thumbnail) when minimized
250     if (!visible && !(widget()->windowState() & Qt::WindowMinimized))
251         screen_flush_context(mContext, 0);
252 }
253 
updateVisibility(bool parentVisible)254 void QBBWindow::updateVisibility(bool parentVisible)
255 {
256     // set window visibility
257     errno = 0;
258     int val = (mVisible && parentVisible) ? 1 : 0;
259     int result = screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_VISIBLE, &val);
260     if (result != 0) {
261         qFatal("QBBWindow: failed to set window visibility, errno=%d", errno);
262     }
263 
264     QList<QBBWindow*>::iterator it;
265     for (it = mChildren.begin(); it != mChildren.end(); it++) {
266         (*it)->updateVisibility(mVisible && parentVisible);
267     }
268 }
269 
setOpacity(qreal level)270 void QBBWindow::setOpacity(qreal level)
271 {
272 #if defined(QBBWINDOW_DEBUG)
273     qDebug() << "QBBWindow::setOpacity - w=" << widget() << ", o=" << level;
274 #endif
275 
276     // set window global alpha
277     errno = 0;
278     int val = (int)(level * 255);
279     int result = screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_GLOBAL_ALPHA, &val);
280     if (result != 0) {
281         qFatal("QBBWindow: failed to set window global alpha, errno=%d", errno);
282     }
283 
284     // TODO: How to handle children of this window? If we change all the visibilities, then
285     //       the transparency will look wrong...
286 }
287 
setBufferSize(const QSize & size)288 void QBBWindow::setBufferSize(const QSize &size)
289 {
290 #if defined(QBBWINDOW_DEBUG)
291     qDebug() << "QBBWindow::setBufferSize - w=" << widget() << ", s=" << size;
292 #endif
293 
294     // set window buffer size
295     errno = 0;
296     int val[2] = { size.width(), size.height() };
297     int result = screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_BUFFER_SIZE, val);
298     if (result != 0) {
299         qFatal("QBBWindow: failed to set window buffer size, errno=%d", errno);
300     }
301 
302     // create window buffers if they do not exist
303     if (!hasBuffers()) {
304 #if defined(QBBWINDOW_DEBUG)
305         qDebug() << "QBBWindow::setBufferSize - create buffers";
306 #endif
307 
308         // get pixel format from EGL config if using OpenGL;
309         // otherwise inherit pixel format of window's screen
310         if (mPlatformGlContext != NULL) {
311             val[0] = platformWindowFormatToNativeFormat(mPlatformGlContext->platformWindowFormat());
312         } else {
313             val[0] = mScreen->nativeFormat();
314         }
315 
316         errno = 0;
317         result = screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_FORMAT, val);
318         if (result != 0) {
319             qFatal("QBBWindow: failed to set window pixel format, errno=%d", errno);
320         }
321 
322         errno = 0;
323         result = screen_create_window_buffers(mWindow, MAX_BUFFER_COUNT);
324         if (result != 0) {
325             qFatal("QBBWindow: failed to create window buffers, errno=%d", errno);
326         }
327 
328         // check if there are any buffers available
329         int bufferCount = 0;
330         result = screen_get_window_property_iv(mWindow, SCREEN_PROPERTY_RENDER_BUFFER_COUNT, &bufferCount);
331 
332         if (result != 0) {
333             qFatal("QBBWindow: failed to query window buffer count, errno=%d", errno);
334         }
335 
336         if (bufferCount != MAX_BUFFER_COUNT) {
337             qFatal("QBBWindow: invalid buffer count. Expected = %d, got = %d", MAX_BUFFER_COUNT, bufferCount);
338         }
339     }
340 
341     // cache new buffer size
342     mBufferSize = size;
343 
344     // buffers were destroyed; reacquire them
345     mCurrentBufferIndex = -1;
346     mPreviousDirty = QRegion();
347     mScrolled = QRegion();
348 }
349 
renderBuffer()350 QBBBuffer &QBBWindow::renderBuffer()
351 {
352 #if defined(QBBWINDOW_DEBUG)
353     qDebug() << "QBBWindow::renderBuffer - w=" << widget();
354 #endif
355 
356     return buffer(BACK_BUFFER);
357 }
358 
frontBuffer()359 QBBBuffer &QBBWindow::frontBuffer()
360 {
361 #if defined(QBBWINDOW_DEBUG)
362     qDebug() << "QBBWindow::frontBuffer - w=" << widget();
363 #endif
364 
365     return buffer(FRONT_BUFFER);
366 }
367 
buffer(QBBWindow::Buffer bufferIndex)368 QBBBuffer &QBBWindow::buffer(QBBWindow::Buffer bufferIndex)
369 {
370 #if defined(QBBWINDOW_DEBUG)
371     qDebug() << "QBBWindow::buffer - w=" << widget();
372 #endif
373 
374     // check if render buffer is invalid
375     if (mCurrentBufferIndex == -1) {
376         // get all buffers available for rendering
377         errno = 0;
378         screen_buffer_t buffers[MAX_BUFFER_COUNT];
379         const int result = screen_get_window_property_pv(mWindow, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)buffers);
380         if (result != 0) {
381             qFatal("QBBWindow: failed to query window buffers, errno=%d", errno);
382         }
383 
384         // wrap each buffer
385         for (int i = 0; i < MAX_BUFFER_COUNT; i++) {
386             mBuffers[i] = QBBBuffer(buffers[i]);
387         }
388 
389         // use the first available render buffer
390         mCurrentBufferIndex = 0;
391         mPreviousBufferIndex = -1;
392     }
393 
394     if (bufferIndex == BACK_BUFFER) {
395         return mBuffers[mCurrentBufferIndex];
396     } else if (bufferIndex == FRONT_BUFFER) {
397         int buf = mCurrentBufferIndex - 1;
398 
399         if (buf < 0)
400             buf = MAX_BUFFER_COUNT - 1;
401 
402         return mBuffers[buf];
403     }
404 
405     qFatal("QBBWindow::buffer() - invalid buffer index. Aborting");
406 
407     // never happens
408     return mBuffers[mCurrentBufferIndex];
409 }
410 
scroll(const QRegion & region,int dx,int dy,bool flush)411 void QBBWindow::scroll(const QRegion &region, int dx, int dy, bool flush)
412 {
413     copyBack(region, dx, dy, flush);
414     mScrolled += region;
415 }
416 
post(const QRegion & dirty)417 void QBBWindow::post(const QRegion &dirty)
418 {
419     // check if render buffer exists and something was rendered
420     if (mCurrentBufferIndex != -1 && !dirty.isEmpty()) {
421 
422 #if defined(QBBWINDOW_DEBUG)
423         qDebug() << "QBBWindow::post - w=" << widget();
424 #endif
425         QBBBuffer &currentBuffer = mBuffers[mCurrentBufferIndex];
426 
427         // copy unmodified region from old render buffer to new render buffer;
428         // required to allow partial updates
429         QRegion preserve = mPreviousDirty - dirty - mScrolled;
430         copyBack(preserve, 0, 0);
431 
432         // calculate region that changed
433         QRegion modified = preserve + dirty + mScrolled;
434         QRect rect = modified.boundingRect();
435         int dirtyRect[4] = { rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height() };
436 
437         // update the display with contents of render buffer
438         errno = 0;
439         int result = screen_post_window(mWindow, currentBuffer.nativeBuffer(), 1, dirtyRect, 0);
440         if (result != 0) {
441             qFatal("QBBWindow: failed to post window buffer, errno=%d", errno);
442         }
443 
444         // advance to next nender buffer
445         mPreviousBufferIndex = mCurrentBufferIndex++;
446         if (mCurrentBufferIndex >= MAX_BUFFER_COUNT) {
447             mCurrentBufferIndex = 0;
448         }
449 
450         // save modified region and clear scrolled region
451         mPreviousDirty = dirty;
452         mScrolled = QRegion();
453 
454         // notify screen that window posted
455         if (mScreen != NULL) {
456             mScreen->onWindowPost(this);
457         }
458     }
459 }
460 
glContext() const461 QPlatformGLContext *QBBWindow::glContext() const
462 {
463 #if defined(QBBWINDOW_DEBUG)
464     qDebug() << "QBBWindow::glContext - w=" << widget();
465 #endif
466     // create opengl context on first access if rendering API is correct
467     QPlatformWindowFormat format = widget()->platformWindowFormat();
468     if (mPlatformGlContext == NULL && format.windowApi() == QPlatformWindowFormat::OpenGL) {
469         mPlatformGlContext = new QBBGLContext( const_cast<QBBWindow*>(this) );
470     }
471     return mPlatformGlContext;
472 }
473 
setScreen(QBBScreen * platformScreen)474 void QBBWindow::setScreen(QBBScreen *platformScreen)
475 {
476 #if defined(QBBWINDOW_DEBUG)
477     qDebug() << "QBBWindow::setScreen - w=" << widget();
478 #endif
479 
480     if (mScreen == platformScreen)
481         return;
482 
483     if (mScreen)
484         mScreen->removeWindow(this);
485     platformScreen->addWindow(this);
486     mScreen = platformScreen;
487 
488     // The display may not have a root (desktop) window yet so we must ensure that one has been
489     // created before we can join its group or get its native display property.
490     mScreen->ensureDisplayCreated();
491 
492     // move window to proper display
493     errno = 0;
494     screen_display_t display = platformScreen->nativeDisplay();
495     int result = screen_set_window_property_pv(mWindow, SCREEN_PROPERTY_DISPLAY, (void **)&display);
496     if (result != 0) {
497         qFatal("QBBWindow: failed to set window display, errno=%d", errno);
498     }
499 
500     // add window to display's window group
501     errno = 0;
502     result = screen_join_window_group(mWindow, platformScreen->windowGroupName());
503     if (result != 0) {
504         qFatal("QBBWindow: failed to join window group, errno=%d", errno);
505     }
506 
507     QList<QBBWindow*>::iterator it;
508     for (it = mChildren.begin(); it != mChildren.end(); it++) {
509         // Only subwindows and tooltips need necessarily be moved to another display with
510         // the window.
511         if ((widget()->windowType() & Qt::WindowType_Mask) == Qt::SubWindow ||
512             (widget()->windowType() & Qt::WindowType_Mask) == Qt::ToolTip)
513             (*it)->setScreen(platformScreen);
514     }
515 
516     mScreen->updateHierarchy();
517 }
518 
removeFromParent()519 void QBBWindow::removeFromParent()
520 {
521     // Remove from old Hierarchy position
522     if (mParent) {
523         if (mParent->mChildren.removeAll(this))
524             mParent = 0;
525         else
526             qFatal("QBBWindow: Window Hierarchy broken; window has parent, but parent hasn't got child.");
527     } else {
528         mScreen->removeWindow(this);
529     }
530 }
531 
setParent(const QPlatformWindow * window)532 void QBBWindow::setParent(const QPlatformWindow *window)
533 {
534 #if defined(QBBWINDOW_DEBUG)
535     qDebug() << "QBBWindow::setParent - w=" << widget() << " p=" << window;
536 #endif
537 
538     // Cast away the const, we need to modify the Hierarchy.
539     QBBWindow* newParent = 0;
540 
541     if (window)
542         newParent = static_cast<QBBWindow*>((QPlatformWindow *)window);
543 
544     if (newParent == mParent)
545         return;
546 
547     removeFromParent();
548     mParent = newParent;
549 
550     // Add to new Hierarchy position.
551     if (mParent) {
552         if (mParent->mScreen != mScreen)
553             setScreen(mParent->mScreen);
554 
555         mParent->mChildren.push_back(this);
556     } else {
557         mScreen->addWindow(this);
558     }
559 
560     mScreen->updateHierarchy();
561 }
562 
raise()563 void QBBWindow::raise()
564 {
565 #if defined(QBBWINDOW_DEBUG)
566     qDebug() << "QBBWindow::raise - w=" << widget();
567 #endif
568 
569     if (mParent) {
570         mParent->mChildren.removeAll(this);
571         mParent->mChildren.push_back(this);
572     } else {
573         mScreen->raiseWindow(this);
574     }
575 
576     mScreen->updateHierarchy();
577 }
578 
lower()579 void QBBWindow::lower()
580 {
581 #if defined(QBBWINDOW_DEBUG)
582     qDebug() << "QBBWindow::lower - w=" << widget();
583 #endif
584 
585     if (mParent) {
586         mParent->mChildren.removeAll(this);
587         mParent->mChildren.push_front(this);
588     } else {
589         mScreen->lowerWindow(this);
590     }
591 
592     mScreen->updateHierarchy();
593 }
594 
requestActivateWindow()595 void QBBWindow::requestActivateWindow()
596 {
597 #if defined(QBBWINDOW_DEBUG)
598     qDebug() << "QBBWindow::requestActivateWindow - w=" << widget();
599 #endif
600 
601     // TODO: Tell screen to set keyboard focus to this window.
602 
603     // Notify that we gained focus.
604     gainedFocus();
605 }
606 
gainedFocus()607 void QBBWindow::gainedFocus()
608 {
609 #if defined(QBBWINDOW_DEBUG)
610     qDebug() << "QBBWindow::gainedFocus - w=" << widget();
611 #endif
612 
613     // Got focus
614     QWindowSystemInterface::handleWindowActivated(widget());
615 }
616 
findWindow(screen_window_t windowHandle)617 QBBWindow *QBBWindow::findWindow(screen_window_t windowHandle)
618 {
619     if (mWindow == windowHandle)
620         return this;
621 
622     Q_FOREACH (QBBWindow *window, mChildren) {
623         QBBWindow * const result = window->findWindow(windowHandle);
624         if (result)
625             return result;
626     }
627 
628     return 0;
629 }
630 
updateZorder(int & topZorder)631 void QBBWindow::updateZorder(int &topZorder)
632 {
633     errno = 0;
634     int result = screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_ZORDER, &topZorder);
635     topZorder++;
636 
637     if (result != 0)
638         qFatal("QBBWindow: failed to set window z-order=%d, errno=%d, mWindow=0x%08x", topZorder, errno, mWindow);
639 
640     QList<QBBWindow*>::const_iterator it;
641 
642     for (it = mChildren.begin(); it != mChildren.end(); it++)
643         (*it)->updateZorder(topZorder);
644 }
645 
copyBack(const QRegion & region,int dx,int dy,bool flush)646 void QBBWindow::copyBack(const QRegion &region, int dx, int dy, bool flush)
647 {
648     int result;
649 
650     // abort if previous buffer is invalid
651     if (mPreviousBufferIndex == -1) {
652         return;
653     }
654 
655     // abort if nothing to copy
656     if (region.isEmpty()) {
657         return;
658     }
659 
660     QBBBuffer &currentBuffer = mBuffers[mCurrentBufferIndex];
661     QBBBuffer &previousBuffer = mBuffers[mPreviousBufferIndex];
662 
663     // break down region into non-overlapping rectangles
664     QVector<QRect> rects = region.rects();
665     for (int i = rects.size() - 1; i >= 0; i--) {
666 
667         // clip rectangle to bounds of target
668         QRect rect = rects[i].intersected( currentBuffer.rect() );
669 
670         if (rect.isEmpty())
671             continue;
672 
673         // setup blit operation
674         int attribs[] = { SCREEN_BLIT_SOURCE_X, rect.x(),
675                           SCREEN_BLIT_SOURCE_Y, rect.y(),
676                           SCREEN_BLIT_SOURCE_WIDTH, rect.width(),
677                           SCREEN_BLIT_SOURCE_HEIGHT, rect.height(),
678                           SCREEN_BLIT_DESTINATION_X, rect.x() + dx,
679                           SCREEN_BLIT_DESTINATION_Y, rect.y() + dy,
680                           SCREEN_BLIT_DESTINATION_WIDTH, rect.width(),
681                           SCREEN_BLIT_DESTINATION_HEIGHT, rect.height(),
682                           SCREEN_BLIT_END };
683 
684         // queue blit operation
685         errno = 0;
686         result = screen_blit(mContext, currentBuffer.nativeBuffer(), previousBuffer.nativeBuffer(), attribs);
687         if (result != 0) {
688             qFatal("QBBWindow: failed to blit buffers, errno=%d", errno);
689         }
690     }
691 
692     // check if flush requested
693     if (flush) {
694 
695         // wait for all blits to complete
696         errno = 0;
697         result = screen_flush_blits(mContext, SCREEN_WAIT_IDLE);
698         if (result != 0) {
699             qFatal("QBBWindow: failed to flush blits, errno=%d", errno);
700         }
701 
702         // buffer was modified outside the CPU
703         currentBuffer.invalidateInCache();
704     }
705 }
706 
platformWindowFormatToNativeFormat(const QPlatformWindowFormat & format)707 int QBBWindow::platformWindowFormatToNativeFormat(const QPlatformWindowFormat &format)
708 {
709     // extract size of colour channels from window format
710     int redSize = format.redBufferSize();
711     if (redSize == -1) {
712         qFatal("QBBWindow: red size not defined");
713     }
714 
715     int greenSize = format.greenBufferSize();
716     if (greenSize == -1) {
717         qFatal("QBBWindow: green size not defined");
718     }
719 
720     int blueSize = format.blueBufferSize();
721     if (blueSize == -1) {
722         qFatal("QBBWindow: blue size not defined");
723     }
724 
725     // select matching native format
726     if (redSize == 5 && greenSize == 6 && blueSize == 5) {
727         return SCREEN_FORMAT_RGB565;
728     } else if (redSize == 8 && greenSize == 8 && blueSize == 8) {
729         return SCREEN_FORMAT_RGBA8888;
730     } else {
731         qFatal("QBBWindow: unsupported pixel format");
732         return 0;
733     }
734 }
735 
736 QT_END_NAMESPACE
737