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