dd69d1500297e9e7a46c87b4543f1dc4b05e28bf
[profile/ivi/qtbase.git] / src / plugins / platforms / qnx / qqnxwindow.cpp
1 /***************************************************************************
2 **
3 ** Copyright (C) 2011 - 2012 Research In Motion
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqnxwindow.h"
43 #ifndef QT_NO_OPENGL
44 #include "qqnxglcontext.h"
45 #endif
46 #include "qqnxintegration.h"
47 #include "qqnxscreen.h"
48
49 #include <QtGui/QWindow>
50 #include <QtGui/qwindowsysteminterface.h>
51
52 #include <QtCore/QDebug>
53
54 #include <errno.h>
55
56 #ifdef QQNXWINDOW_DEBUG
57 #define qWindowDebug qDebug
58 #else
59 #define qWindowDebug QT_NO_QDEBUG_MACRO
60 #endif
61
62 QT_BEGIN_NAMESPACE
63
64 QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context)
65     : QPlatformWindow(window),
66       m_screenContext(context),
67       m_window(0),
68       m_currentBufferIndex(-1),
69       m_previousBufferIndex(-1),
70 #ifndef QT_NO_OPENGL
71       m_platformOpenGLContext(0),
72 #endif
73       m_screen(0),
74       m_parentWindow(0),
75       m_visible(true),
76       m_windowState(Qt::WindowNoState)
77 {
78     qWindowDebug() << Q_FUNC_INFO << "window =" << window << ", size =" << window->size();
79     int result;
80
81     // Create child QNX window
82     errno = 0;
83     result = screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW);
84     if (result != 0) {
85         qFatal("QQnxWindow: failed to create window, errno=%d", errno);
86     }
87
88     // Set window buffer usage based on rendering API
89     int val;
90     QSurface::SurfaceType surfaceType = window->surfaceType();
91     switch (surfaceType) {
92     case QSurface::RasterSurface:
93         val = SCREEN_USAGE_NATIVE | SCREEN_USAGE_READ | SCREEN_USAGE_WRITE;
94         break;
95     case QSurface::OpenGLSurface:
96         val = SCREEN_USAGE_OPENGL_ES2;
97         break;
98     default:
99         qFatal("QQnxWindow: unsupported window API");
100         break;
101     }
102
103     errno = 0;
104     result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_USAGE, &val);
105     if (result != 0) {
106         qFatal("QQnxWindow: failed to set window buffer usage, errno=%d", errno);
107     }
108
109     // Alpha channel is always pre-multiplied if present
110     errno = 0;
111     val = SCREEN_PRE_MULTIPLIED_ALPHA;
112     result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ALPHA_MODE, &val);
113     if (result != 0) {
114         qFatal("QQnxWindow: failed to set window alpha mode, errno=%d", errno);
115     }
116
117     // Make the window opaque
118     errno = 0;
119     val = SCREEN_TRANSPARENCY_NONE;
120     result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_TRANSPARENCY, &val);
121     if (result != 0) {
122         qFatal("QQnxWindow: failed to set window transparency, errno=%d", errno);
123     }
124
125     // Set the window swap interval
126     errno = 0;
127     val = 1;
128     result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SWAP_INTERVAL, &val);
129     if (result != 0) {
130         qFatal("QQnxWindow: failed to set window swap interval, errno=%d", errno);
131     }
132
133     setScreen(static_cast<QQnxScreen *>(window->screen()->handle()));
134
135     // Add window to plugin's window mapper
136     QQnxIntegration::addWindow(m_window, window);
137
138     // Qt never calls these setters after creating the window, so we need to do that ourselves here
139     setWindowState(window->windowState());
140     if (window->parent())
141         setParent(window->parent()->handle());
142     setGeometryHelper(window->geometry());
143     setVisible(window->isVisible());
144 }
145
146 QQnxWindow::~QQnxWindow()
147 {
148     qWindowDebug() << Q_FUNC_INFO << "window =" << window();
149     // Remove from plugin's window mapper
150     QQnxIntegration::removeWindow(m_window);
151
152     // Remove from parent's Hierarchy.
153     removeFromParent();
154     m_screen->updateHierarchy();
155
156     // We shouldn't allow this case unless QT allows it. Does it? Or should we send the
157     // handleCloseEvent on all children when this window is deleted?
158     if (m_childWindows.size() > 0)
159         qFatal("QQnxWindow: window destroyed before children!");
160
161     // Cleanup QNX window and its buffers
162     screen_destroy_window(m_window);
163 }
164
165 void QQnxWindow::setGeometry(const QRect &rect)
166 {
167     const QRect oldGeometry = setGeometryHelper(rect);
168
169     // If this is an OpenGL window we need to request that the GL context updates
170     // the EGLsurface on which it is rendering. The surface will be recreated the
171     // next time QQnxGLContext::makeCurrent() is called.
172     {
173         // We want the setting of the atomic bool in the GL context to be atomic with
174         // setting m_requestedBufferSize and therefore extended the scope to include
175         // that test.
176         const QMutexLocker locker(&m_mutex);
177         m_requestedBufferSize = rect.size();
178         if (m_platformOpenGLContext != 0 && bufferSize() != rect.size())
179             m_platformOpenGLContext->requestSurfaceChange();
180     }
181
182     // Send a geometry change event to Qt (triggers resizeEvent() in QWindow/QWidget)
183     QWindowSystemInterface::handleSynchronousGeometryChange(window(), rect);
184
185     // Now move all children.
186     if (!oldGeometry.isEmpty()) {
187         const QPoint offset = rect.topLeft() - oldGeometry.topLeft();
188         Q_FOREACH (QQnxWindow *childWindow, m_childWindows)
189             childWindow->setOffset(offset);
190     }
191 }
192
193 QRect QQnxWindow::setGeometryHelper(const QRect &rect)
194 {
195     qWindowDebug() << Q_FUNC_INFO << "window =" << window()
196                    << ", (" << rect.x() << "," << rect.y()
197                    << "," << rect.width() << "," << rect.height() << ")";
198
199     // Call base class method
200     QRect oldGeometry = QPlatformWindow::geometry();
201     QPlatformWindow::setGeometry(rect);
202
203     // Set window geometry equal to widget geometry
204     errno = 0;
205     int val[2];
206     val[0] = rect.x();
207     val[1] = rect.y();
208     int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, val);
209     if (result != 0) {
210         qFatal("QQnxWindow: failed to set window position, errno=%d", errno);
211     }
212
213     errno = 0;
214     val[0] = rect.width();
215     val[1] = rect.height();
216     result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val);
217     if (result != 0) {
218         qFatal("QQnxWindow: failed to set window size, errno=%d", errno);
219     }
220
221     // Set viewport size equal to window size
222     errno = 0;
223     result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val);
224     if (result != 0) {
225         qFatal("QQnxWindow: failed to set window source size, errno=%d", errno);
226     }
227
228     return oldGeometry;
229 }
230
231 void QQnxWindow::setOffset(const QPoint &offset)
232 {
233     qWindowDebug() << Q_FUNC_INFO << "window =" << window();
234     // Move self and then children.
235     QRect newGeometry = geometry();
236     newGeometry.translate(offset);
237
238     // Call the base class
239     QPlatformWindow::setGeometry(newGeometry);
240
241     int val[2];
242
243     errno = 0;
244     val[0] = newGeometry.x();
245     val[1] = newGeometry.y();
246     int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, val);
247     if (result != 0) {
248         qFatal("QQnxWindow: failed to set window position, errno=%d", errno);
249     }
250
251     Q_FOREACH (QQnxWindow *childWindow, m_childWindows)
252         childWindow->setOffset(offset);
253 }
254
255 void QQnxWindow::setVisible(bool visible)
256 {
257     qWindowDebug() << Q_FUNC_INFO << "window =" << window() << "visible =" << visible;
258
259     m_visible = visible;
260
261     QQnxWindow *root = this;
262     while (root->m_parentWindow)
263         root = root->m_parentWindow;
264
265     root->updateVisibility(root->m_visible);
266
267     window()->requestActivateWindow();
268
269     if (window()->isTopLevel() && visible)
270         QWindowSystemInterface::handleExposeEvent(window(), window()->geometry());
271 }
272
273 void QQnxWindow::updateVisibility(bool parentVisible)
274 {
275     qWindowDebug() << Q_FUNC_INFO << "parentVisible =" << parentVisible << "window =" << window();
276     // Set window visibility
277     errno = 0;
278     int val = (m_visible && parentVisible) ? 1 : 0;
279     int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_VISIBLE, &val);
280     if (result != 0) {
281         qFatal("QQnxWindow: failed to set window visibility, errno=%d", errno);
282     }
283
284     Q_FOREACH (QQnxWindow *childWindow, m_childWindows)
285         childWindow->updateVisibility(m_visible && parentVisible);
286 }
287
288 void QQnxWindow::setOpacity(qreal level)
289 {
290     qWindowDebug() << Q_FUNC_INFO << "window =" << window() << "opacity =" << level;
291     // Set window global alpha
292     errno = 0;
293     int val = (int)(level * 255);
294     int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_GLOBAL_ALPHA, &val);
295     if (result != 0) {
296         qFatal("QQnxWindow: failed to set window global alpha, errno=%d", errno);
297     }
298
299     // TODO: How to handle children of this window? If we change all the visibilities, then
300     //       the transparency will look wrong...
301 }
302
303 bool QQnxWindow::isExposed() const
304 {
305     return m_visible;
306 }
307
308 QSize QQnxWindow::requestedBufferSize() const
309 {
310     const QMutexLocker locker(&m_mutex);
311     return m_requestedBufferSize;
312 }
313
314 void QQnxWindow::adjustBufferSize()
315 {
316     const QSize windowSize = window()->size();
317     if (windowSize != bufferSize())
318         setBufferSize(windowSize);
319 }
320
321 void QQnxWindow::setBufferSize(const QSize &size)
322 {
323     qWindowDebug() << Q_FUNC_INFO << "window =" << window() << "size =" << size;
324
325     // Set window buffer size
326     errno = 0;
327     int val[2] = { size.width(), size.height() };
328     int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BUFFER_SIZE, val);
329     if (result != 0) {
330         qFatal("QQnxWindow: failed to set window buffer size, errno=%d", errno);
331     }
332
333     // Create window buffers if they do not exist
334     if (m_bufferSize.isEmpty()) {
335 #ifndef QT_NO_OPENGL
336         // Get pixel format from EGL config if using OpenGL;
337         // otherwise inherit pixel format of window's screen
338         if (m_platformOpenGLContext != 0) {
339             val[0] = platformWindowFormatToNativeFormat(m_platformOpenGLContext->format());
340         } else {
341             val[0] = m_screen->nativeFormat();
342         }
343 #endif
344
345         errno = 0;
346         result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, val);
347         if (result != 0) {
348             qFatal("QQnxWindow: failed to set window pixel format, errno=%d", errno);
349         }
350
351         errno = 0;
352         result = screen_create_window_buffers(m_window, MAX_BUFFER_COUNT);
353         if (result != 0) {
354             qFatal("QQnxWindow: failed to create window buffers, errno=%d", errno);
355         }
356     }
357
358     // Cache new buffer size
359     m_bufferSize = size;
360
361     // Buffers were destroyed; reacquire them
362     m_currentBufferIndex = -1;
363     m_previousDirty = QRegion();
364     m_scrolled = QRegion();
365
366     const QMutexLocker locker(&m_mutex);
367     m_requestedBufferSize = QSize();
368 }
369
370 QQnxBuffer &QQnxWindow::renderBuffer()
371 {
372     qWindowDebug() << Q_FUNC_INFO << "window =" << window();
373
374     // Check if render buffer is invalid
375     if (m_currentBufferIndex == -1) {
376         // Get all buffers available for rendering
377         errno = 0;
378         screen_buffer_t buffers[MAX_BUFFER_COUNT];
379         int result = screen_get_window_property_pv(m_window, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)buffers);
380         if (result != 0) {
381             qFatal("QQnxWindow: 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             m_buffers[i] = QQnxBuffer(buffers[i]);
387         }
388
389         // Use the first available render buffer
390         m_currentBufferIndex = 0;
391         m_previousBufferIndex = -1;
392     }
393
394     return m_buffers[m_currentBufferIndex];
395 }
396
397 void QQnxWindow::scroll(const QRegion &region, int dx, int dy, bool flush)
398 {
399     qWindowDebug() << Q_FUNC_INFO << "window =" << window();
400     blitPreviousToCurrent(region, dx, dy, flush);
401     m_scrolled += region;
402 }
403
404 void QQnxWindow::post(const QRegion &dirty)
405 {
406     // How double-buffering works
407     // --------------------------
408     //
409     // The are two buffers, the previous one and the current one.
410     // The previous buffer always contains the complete, full image of the whole window when it
411     // was last posted.
412     // The current buffer starts with the complete, full image of the second to last posting
413     // of the window.
414     //
415     // During painting, Qt paints on the current buffer. Thus, when Qt has finished painting, the
416     // current buffer contains the second to last image plus the newly painted regions.
417     // Since the second to last image is too old, we copy over the image from the previous buffer, but
418     // only for those regions that Qt didn't paint (because that would overwrite what Qt has just
419     // painted). This is the copyPreviousToCurrent() call below.
420     //
421     // After the call to copyPreviousToCurrent(), the current buffer contains the complete, full image of the
422     // whole window in its current state, and we call screen_post_window() to make the new buffer
423     // available to libscreen (called "posting"). There, only the regions that Qt painted on are
424     // posted, as nothing else has changed.
425     //
426     // After that, the previous and the current buffers are swapped, and the whole cycle starts anew.
427
428     // Check if render buffer exists and something was rendered
429     if (m_currentBufferIndex != -1 && !dirty.isEmpty()) {
430         qWindowDebug() << Q_FUNC_INFO << "window =" << window();
431         QQnxBuffer &currentBuffer = m_buffers[m_currentBufferIndex];
432
433         // Copy unmodified region from old render buffer to new render buffer;
434         // required to allow partial updates
435         QRegion preserve = m_previousDirty - dirty - m_scrolled;
436         blitPreviousToCurrent(preserve, 0, 0);
437
438         // Calculate region that changed
439         QRegion modified = preserve + dirty + m_scrolled;
440         QRect rect = modified.boundingRect();
441         int dirtyRect[4] = { rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height() };
442
443         // Update the display with contents of render buffer
444         errno = 0;
445         int result = screen_post_window(m_window, currentBuffer.nativeBuffer(), 1, dirtyRect, 0);
446         if (result != 0) {
447             qFatal("QQnxWindow: failed to post window buffer, errno=%d", errno);
448         }
449
450         // Advance to next nender buffer
451         m_previousBufferIndex = m_currentBufferIndex++;
452         if (m_currentBufferIndex >= MAX_BUFFER_COUNT) {
453             m_currentBufferIndex = 0;
454         }
455
456         // Save modified region and clear scrolled region
457         m_previousDirty = dirty;
458         m_scrolled = QRegion();
459
460         // Notify screen that window posted
461         if (m_screen != 0) {
462             m_screen->onWindowPost(this);
463         }
464     }
465 }
466
467 void QQnxWindow::setScreen(QQnxScreen *platformScreen)
468 {
469     qWindowDebug() << Q_FUNC_INFO << "window =" << window() << "platformScreen =" << platformScreen;
470
471     if (m_screen == platformScreen)
472         return;
473
474     if (m_screen)
475         m_screen->removeWindow(this);
476     platformScreen->addWindow(this);
477     m_screen = platformScreen;
478
479     // Move window to proper screen/display
480     errno = 0;
481     screen_display_t display = platformScreen->nativeDisplay();
482     int result = screen_set_window_property_pv(m_window, SCREEN_PROPERTY_DISPLAY, (void **)&display);
483     if (result != 0) {
484         qFatal("QQnxWindow: failed to set window display, errno=%d", errno);
485     }
486
487     // Add window to display's window group
488     errno = 0;
489     result = screen_join_window_group(m_window, platformScreen->windowGroupName());
490     if (result != 0) {
491         qFatal("QQnxWindow: failed to join window group, errno=%d", errno);
492     }
493
494     Q_FOREACH (QQnxWindow *childWindow, m_childWindows) {
495         // Only subwindows and tooltips need necessarily be moved to another display with the window.
496         if ((window()->windowType() & Qt::WindowType_Mask) == Qt::SubWindow ||
497             (window()->windowType() & Qt::WindowType_Mask) == Qt::ToolTip)
498             childWindow->setScreen(platformScreen);
499     }
500
501     m_screen->updateHierarchy();
502 }
503
504 void QQnxWindow::removeFromParent()
505 {
506     qWindowDebug() << Q_FUNC_INFO << "window =" << window();
507     // Remove from old Hierarchy position
508     if (m_parentWindow) {
509         if (m_parentWindow->m_childWindows.removeAll(this))
510             m_parentWindow = 0;
511         else
512             qFatal("QQnxWindow: Window Hierarchy broken; window has parent, but parent hasn't got child.");
513     } else {
514         m_screen->removeWindow(this);
515     }
516 }
517
518 void QQnxWindow::setParent(const QPlatformWindow *window)
519 {
520     qWindowDebug() << Q_FUNC_INFO << "window =" << this->window() << "platformWindow =" << window;
521     // Cast away the const, we need to modify the hierarchy.
522     QQnxWindow *newParent = 0;
523
524     if (window)
525         newParent = static_cast<QQnxWindow*>((QPlatformWindow *)window);
526
527     if (newParent == m_parentWindow)
528         return;
529
530     removeFromParent();
531     m_parentWindow = newParent;
532
533     // Add to new hierarchy position.
534     if (m_parentWindow) {
535         if (m_parentWindow->m_screen != m_screen)
536             setScreen(m_parentWindow->m_screen);
537
538         m_parentWindow->m_childWindows.push_back(this);
539     } else {
540         m_screen->addWindow(this);
541     }
542
543     m_screen->updateHierarchy();
544 }
545
546 void QQnxWindow::raise()
547 {
548     qWindowDebug() << Q_FUNC_INFO << "window =" << window();
549
550     QQnxWindow *oldParent = m_parentWindow;
551     if (oldParent) {
552         removeFromParent();
553         oldParent->m_childWindows.push_back(this);
554     } else {
555         m_screen->raiseWindow(this);
556     }
557
558     m_screen->updateHierarchy();
559 }
560
561 void QQnxWindow::lower()
562 {
563     qWindowDebug() << Q_FUNC_INFO << "window =" << window();
564
565     QQnxWindow *oldParent = m_parentWindow;
566     if (oldParent) {
567         removeFromParent();
568         oldParent->m_childWindows.push_front(this);
569     } else {
570         m_screen->lowerWindow(this);
571     }
572
573     m_screen->updateHierarchy();
574 }
575
576 void QQnxWindow::requestActivateWindow()
577 {
578     qWindowDebug() << Q_FUNC_INFO << "window =" << window();
579
580     // TODO: Tell screen to set keyboard focus to this window.
581
582     // Notify that we gained focus.
583     gainedFocus();
584 }
585
586
587 Qt::WindowState QQnxWindow::setWindowState(Qt::WindowState state)
588 {
589     qWindowDebug() << Q_FUNC_INFO << "state =" << state;
590
591     // Prevent two calls with Qt::WindowFullScreen from changing m_unmaximizedGeometry
592     if (m_windowState == state)
593         return state;
594
595     switch (state) {
596
597     // WindowMinimized is not supported - navigator does not have an API to minimize a window
598     // WindowActive is not an accepted parameter according to the docs
599     case Qt::WindowMinimized:
600     case Qt::WindowActive:
601         return m_windowState;
602
603     case Qt::WindowMaximized:
604     case Qt::WindowFullScreen:
605         m_unmaximizedGeometry = geometry();
606         setGeometry(state == Qt::WindowMaximized ? m_screen->availableGeometry() : m_screen->geometry());
607         break;
608
609     case Qt::WindowNoState:
610         if (m_unmaximizedGeometry.isValid())
611             setGeometry(m_unmaximizedGeometry);
612         break;
613     }
614
615     m_windowState = state;
616     return state;
617 }
618
619 void QQnxWindow::gainedFocus()
620 {
621     qWindowDebug() << Q_FUNC_INFO << "window =" << window();
622
623     // Got focus
624     QWindowSystemInterface::handleWindowActivated(window());
625 }
626
627 #ifndef QT_NO_OPENGL
628 void QQnxWindow::setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext)
629 {
630     // This function does not take ownership of the platform gl context.
631     // It is owned by the frontend QOpenGLContext
632     m_platformOpenGLContext = platformOpenGLContext;
633 }
634 #endif
635
636 QQnxWindow *QQnxWindow::findWindow(screen_window_t windowHandle)
637 {
638     if (m_window == windowHandle)
639         return this;
640
641     Q_FOREACH (QQnxWindow *window, m_childWindows) {
642         QQnxWindow * const result = window->findWindow(windowHandle);
643         if (result)
644             return result;
645     }
646
647     return 0;
648 }
649
650 void QQnxWindow::blitFrom(QQnxWindow *sourceWindow, const QPoint &sourceOffset, const QRegion &targetRegion)
651 {
652     if (!sourceWindow || sourceWindow->m_previousBufferIndex == -1 || targetRegion.isEmpty())
653         return;
654
655     qWindowDebug() << Q_FUNC_INFO << window() << sourceWindow->window() << sourceOffset << targetRegion;
656
657     QQnxBuffer &sourceBuffer = sourceWindow->m_buffers[sourceWindow->m_previousBufferIndex];
658     QQnxBuffer &targetBuffer = renderBuffer();
659
660     blitHelper(sourceBuffer, targetBuffer, sourceOffset, QPoint(0, 0), targetRegion, true);
661 }
662
663 void QQnxWindow::updateZorder(int &topZorder)
664 {
665     errno = 0;
666     int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ZORDER, &topZorder);
667     topZorder++;
668
669     if (result != 0)
670         qFatal("QQnxWindow: failed to set window z-order=%d, errno=%d, mWindow=%p", topZorder, errno, m_window);
671
672     Q_FOREACH (QQnxWindow *childWindow, m_childWindows)
673         childWindow->updateZorder(topZorder);
674 }
675
676 void QQnxWindow::blitHelper(QQnxBuffer &source, QQnxBuffer &target, const QPoint &sourceOffset,
677                             const QPoint &targetOffset, const QRegion &region, bool flush)
678 {
679     // Break down region into non-overlapping rectangles
680     const QVector<QRect> rects = region.rects();
681     for (int i = rects.size() - 1; i >= 0; i--) {
682         // Clip rectangle to bounds of target
683         const QRect rect = rects[i].intersected(target.rect());
684
685         if (rect.isEmpty())
686             continue;
687
688         // Setup blit operation
689         int attribs[] = { SCREEN_BLIT_SOURCE_X, rect.x() + sourceOffset.x(),
690                           SCREEN_BLIT_SOURCE_Y, rect.y() + sourceOffset.y(),
691                           SCREEN_BLIT_SOURCE_WIDTH, rect.width(),
692                           SCREEN_BLIT_SOURCE_HEIGHT, rect.height(),
693                           SCREEN_BLIT_DESTINATION_X, rect.x() + targetOffset.x(),
694                           SCREEN_BLIT_DESTINATION_Y, rect.y() + targetOffset.y(),
695                           SCREEN_BLIT_DESTINATION_WIDTH, rect.width(),
696                           SCREEN_BLIT_DESTINATION_HEIGHT, rect.height(),
697                           SCREEN_BLIT_END };
698
699         // Queue blit operation
700         errno = 0;
701         const int result = screen_blit(m_screenContext, target.nativeBuffer(),
702                                        source.nativeBuffer(), attribs);
703         if (result != 0)
704             qFatal("QQnxWindow: failed to blit buffers, errno=%d", errno);
705     }
706
707     // Check if flush requested
708     if (flush) {
709         // Wait for all blits to complete
710         errno = 0;
711         const int result = screen_flush_blits(m_screenContext, SCREEN_WAIT_IDLE);
712         if (result != 0)
713             qFatal("QQnxWindow: failed to flush blits, errno=%d", errno);
714
715         // Buffer was modified outside the CPU
716         target.invalidateInCache();
717     }
718 }
719
720 void QQnxWindow::blitPreviousToCurrent(const QRegion &region, int dx, int dy, bool flush)
721 {
722     qWindowDebug() << Q_FUNC_INFO << "window =" << window();
723
724     // Abort if previous buffer is invalid or if nothing to copy
725     if (m_previousBufferIndex == -1 || region.isEmpty())
726         return;
727
728     QQnxBuffer &currentBuffer = m_buffers[m_currentBufferIndex];
729     QQnxBuffer &previousBuffer = m_buffers[m_previousBufferIndex];
730
731     blitHelper(previousBuffer, currentBuffer, QPoint(0, 0), QPoint(dx, dy), region, flush);
732 }
733
734 int QQnxWindow::platformWindowFormatToNativeFormat(const QSurfaceFormat &format)
735 {
736     qWindowDebug() << Q_FUNC_INFO;
737     // Extract size of colour channels from window format
738     int redSize = format.redBufferSize();
739     if (redSize == -1) {
740         qFatal("QQnxWindow: red size not defined");
741     }
742
743     int greenSize = format.greenBufferSize();
744     if (greenSize == -1) {
745         qFatal("QQnxWindow: green size not defined");
746     }
747
748     int blueSize = format.blueBufferSize();
749     if (blueSize == -1) {
750         qFatal("QQnxWindow: blue size not defined");
751     }
752
753     // select matching native format
754     if (redSize == 5 && greenSize == 6 && blueSize == 5) {
755         return SCREEN_FORMAT_RGB565;
756     } else if (redSize == 8 && greenSize == 8 && blueSize == 8) {
757         return SCREEN_FORMAT_RGBA8888;
758     } else {
759         qFatal("QQnxWindow: unsupported pixel format");
760         return 0;
761     }
762 }
763
764 QT_END_NAMESPACE