1 /***************************************************************************
3 ** Copyright (C) 2011 - 2012 Research In Motion
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the plugins of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qqnxwindow.h"
43 #include "qqnxglcontext.h"
44 #include "qqnxintegration.h"
45 #include "qqnxscreen.h"
47 #include <QtGui/QWindow>
48 #include <QtGui/QWindowSystemInterface>
50 #include <QtCore/QDebug>
56 QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context)
57 : QPlatformWindow(window),
58 m_screenContext(context),
60 m_currentBufferIndex(-1),
61 m_previousBufferIndex(-1),
62 m_platformOpenGLContext(0),
67 #if defined(QQNXWINDOW_DEBUG)
68 qDebug() << Q_FUNC_INFO << "window =" << window << ", size =" << window->size();
72 // Create child QNX window
74 result = screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW);
76 qFatal("QQnxWindow: failed to create window, errno=%d", errno);
79 // Set window buffer usage based on rendering API
81 QSurface::SurfaceType surfaceType = window->surfaceType();
82 switch (surfaceType) {
83 case QSurface::RasterSurface:
84 val = SCREEN_USAGE_NATIVE | SCREEN_USAGE_READ | SCREEN_USAGE_WRITE;
86 case QSurface::OpenGLSurface:
87 val = SCREEN_USAGE_OPENGL_ES2;
90 qFatal("QQnxWindow: unsupported window API");
95 result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_USAGE, &val);
97 qFatal("QQnxWindow: failed to set window buffer usage, errno=%d", errno);
100 // Alpha channel is always pre-multiplied if present
102 val = SCREEN_PRE_MULTIPLIED_ALPHA;
103 result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ALPHA_MODE, &val);
105 qFatal("QQnxWindow: failed to set window alpha mode, errno=%d", errno);
108 // Make the window opaque
110 val = SCREEN_TRANSPARENCY_NONE;
111 result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_TRANSPARENCY, &val);
113 qFatal("QQnxWindow: failed to set window transparency, errno=%d", errno);
116 // Set the window swap interval
119 result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SWAP_INTERVAL, &val);
121 qFatal("QQnxWindow: failed to set window swap interval, errno=%d", errno);
124 setScreen(static_cast<QQnxScreen *>(window->screen()->handle()));
126 // Add window to plugin's window mapper
127 QQnxIntegration::addWindow(m_window, window);
130 QQnxWindow::~QQnxWindow()
132 #if defined(QQNXWINDOW_DEBUG)
133 qDebug() << Q_FUNC_INFO << "window =" << window();
135 // Remove from plugin's window mapper
136 QQnxIntegration::removeWindow(m_window);
138 // Remove from parent's Hierarchy.
140 m_screen->updateHierarchy();
142 // We shouldn't allow this case unless QT allows it. Does it? Or should we send the
143 // handleCloseEvent on all children when this window is deleted?
144 if (m_childWindows.size() > 0)
145 qFatal("QQnxWindow: window destroyed before children!");
147 // Cleanup QNX window and its buffers
148 screen_destroy_window(m_window);
151 void QQnxWindow::setGeometry(const QRect &rect)
153 #if defined(QQNXWINDOW_DEBUG)
154 qDebug() << Q_FUNC_INFO << "window =" << window() << ", (" << rect.x() << "," << rect.y() << "," << rect.width() << "," << rect.height() << ")";
157 QRect oldGeometry = geometry();
159 // Call base class method
160 QPlatformWindow::setGeometry(rect);
162 // Set window geometry equal to widget geometry
167 int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, val);
169 qFatal("QQnxWindow: failed to set window position, errno=%d", errno);
173 val[0] = rect.width();
174 val[1] = rect.height();
175 result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val);
177 qFatal("QQnxWindow: failed to set window size, errno=%d", errno);
180 // Set viewport size equal to window size
182 result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val);
184 qFatal("QQnxWindow: failed to set window source size, errno=%d", errno);
187 // Now move all children.
189 if (!oldGeometry.isEmpty()) {
190 offset = rect.topLeft();
191 offset -= oldGeometry.topLeft();
193 QList<QQnxWindow*>::iterator it;
194 for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) {
195 (*it)->setOffset(offset);
200 void QQnxWindow::setOffset(const QPoint &offset)
202 #if defined(QQNXWINDOW_DEBUG)
203 qDebug() << Q_FUNC_INFO << "window =" << window();
205 // Move self and then children.
206 QRect newGeometry = geometry();
207 newGeometry.translate(offset);
209 // Call the base class
210 QPlatformWindow::setGeometry(newGeometry);
215 val[0] = newGeometry.x();
216 val[1] = newGeometry.y();
217 int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, val);
219 qFatal("QQnxWindow: failed to set window position, errno=%d", errno);
222 QList<QQnxWindow*>::iterator it;
223 for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) {
224 (*it)->setOffset(offset);
228 void QQnxWindow::setVisible(bool visible)
230 #if defined(QQNXWINDOW_DEBUG)
231 qDebug() << Q_FUNC_INFO << "window =" << window() << "visible =" << visible;
236 QQnxWindow *root = this;
237 while (root->m_parentWindow)
238 root = root->m_parentWindow;
240 root->updateVisibility(root->m_visible);
242 window()->requestActivateWindow();
244 if (window()->isTopLevel() && visible)
245 QWindowSystemInterface::handleExposeEvent(window(), window()->geometry());
248 void QQnxWindow::updateVisibility(bool parentVisible)
250 #if defined(QQNXWINDOW_DEBUG)
251 qDebug() << Q_FUNC_INFO << "parentVisible =" << parentVisible << "window =" << window();
253 // Set window visibility
255 int val = (m_visible && parentVisible) ? 1 : 0;
256 int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_VISIBLE, &val);
258 qFatal("QQnxWindow: failed to set window visibility, errno=%d", errno);
261 QList<QQnxWindow *>::iterator it;
262 for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) {
263 (*it)->updateVisibility(m_visible && parentVisible);
267 void QQnxWindow::setOpacity(qreal level)
269 #if defined(QQNXWINDOW_DEBUG)
270 qDebug() << Q_FUNC_INFO << "window =" << window() << "opacity =" << level;
272 // Set window global alpha
274 int val = (int)(level * 255);
275 int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_GLOBAL_ALPHA, &val);
277 qFatal("QQnxWindow: failed to set window global alpha, errno=%d", errno);
280 // TODO: How to handle children of this window? If we change all the visibilities, then
281 // the transparency will look wrong...
284 bool QQnxWindow::isExposed() const
289 void QQnxWindow::setBufferSize(const QSize &size)
291 #if defined(QQNXWINDOW_DEBUG)
292 qDebug() << Q_FUNC_INFO << "window =" << window() << "size =" << size;
294 // Set window buffer size
296 int val[2] = { size.width(), size.height() };
297 int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BUFFER_SIZE, val);
299 qFatal("QQnxWindow: failed to set window buffer size, errno=%d", errno);
302 // Create window buffers if they do not exist
304 // Get pixel format from EGL config if using OpenGL;
305 // otherwise inherit pixel format of window's screen
306 if (m_platformOpenGLContext != 0) {
307 val[0] = platformWindowFormatToNativeFormat(m_platformOpenGLContext->format());
309 val[0] = m_screen->nativeFormat();
313 result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, val);
315 qFatal("QQnxWindow: failed to set window pixel format, errno=%d", errno);
319 result = screen_create_window_buffers(m_window, MAX_BUFFER_COUNT);
321 qFatal("QQnxWindow: failed to create window buffers, errno=%d", errno);
325 // Cache new buffer size
328 // Buffers were destroyed; reacquire them
329 m_currentBufferIndex = -1;
330 m_previousDirty = QRegion();
331 m_scrolled = QRegion();
334 QQnxBuffer &QQnxWindow::renderBuffer()
336 #if defined(QQNXWINDOW_DEBUG)
337 qDebug() << Q_FUNC_INFO << "window =" << window();
339 // Check if render buffer is invalid
340 if (m_currentBufferIndex == -1) {
341 // Get all buffers available for rendering
343 screen_buffer_t buffers[MAX_BUFFER_COUNT];
344 int result = screen_get_window_property_pv(m_window, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)buffers);
346 qFatal("QQnxWindow: failed to query window buffers, errno=%d", errno);
350 for (int i = 0; i < MAX_BUFFER_COUNT; ++i) {
351 m_buffers[i] = QQnxBuffer(buffers[i]);
354 // Use the first available render buffer
355 m_currentBufferIndex = 0;
356 m_previousBufferIndex = -1;
359 return m_buffers[m_currentBufferIndex];
362 void QQnxWindow::scroll(const QRegion ®ion, int dx, int dy, bool flush)
364 #if defined(QQNXWINDOW_DEBUG)
365 qDebug() << Q_FUNC_INFO << "window =" << window();
367 copyBack(region, dx, dy, flush);
368 m_scrolled += region;
371 void QQnxWindow::post(const QRegion &dirty)
373 // Check if render buffer exists and something was rendered
374 if (m_currentBufferIndex != -1 && !dirty.isEmpty()) {
375 #if defined(QQNXWINDOW_DEBUG)
376 qDebug() << "QQnxWindow::post - window =" << window();
378 QQnxBuffer ¤tBuffer = m_buffers[m_currentBufferIndex];
380 // Copy unmodified region from old render buffer to new render buffer;
381 // required to allow partial updates
382 QRegion preserve = m_previousDirty - dirty - m_scrolled;
383 copyBack(preserve, 0, 0);
385 // Calculate region that changed
386 QRegion modified = preserve + dirty + m_scrolled;
387 QRect rect = modified.boundingRect();
388 int dirtyRect[4] = { rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height() };
390 // Update the display with contents of render buffer
392 int result = screen_post_window(m_window, currentBuffer.nativeBuffer(), 1, dirtyRect, 0);
394 qFatal("QQnxWindow: failed to post window buffer, errno=%d", errno);
397 // Advance to next nender buffer
398 m_previousBufferIndex = m_currentBufferIndex++;
399 if (m_currentBufferIndex >= MAX_BUFFER_COUNT) {
400 m_currentBufferIndex = 0;
403 // Save modified region and clear scrolled region
404 m_previousDirty = dirty;
405 m_scrolled = QRegion();
407 // Notify screen that window posted
409 m_screen->onWindowPost(this);
414 void QQnxWindow::setScreen(QQnxScreen *platformScreen)
416 #if defined(QQNXWINDOW_DEBUG)
417 qDebug() << Q_FUNC_INFO << "window =" << window() << "platformScreen =" << platformScreen;
420 if (m_screen == platformScreen)
424 m_screen->removeWindow(this);
425 platformScreen->addWindow(this);
426 m_screen = platformScreen;
428 // Move window to proper screen/display
430 screen_display_t display = platformScreen->nativeDisplay();
431 int result = screen_set_window_property_pv(m_window, SCREEN_PROPERTY_DISPLAY, (void **)&display);
433 qFatal("QQnxWindow: failed to set window display, errno=%d", errno);
436 // Add window to display's window group
438 result = screen_join_window_group(m_window, platformScreen->windowGroupName());
440 qFatal("QQnxWindow: failed to join window group, errno=%d", errno);
443 QList<QQnxWindow*>::iterator it;
444 for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) {
445 // Only subwindows and tooltips need necessarily be moved to another display with the window.
446 if ((window()->windowType() & Qt::WindowType_Mask) == Qt::SubWindow ||
447 (window()->windowType() & Qt::WindowType_Mask) == Qt::ToolTip)
448 (*it)->setScreen(platformScreen);
451 m_screen->updateHierarchy();
454 void QQnxWindow::removeFromParent()
456 #if defined(QQNXWINDOW_DEBUG)
457 qDebug() << Q_FUNC_INFO << "window =" << window();
459 // Remove from old Hierarchy position
460 if (m_parentWindow) {
461 if (m_parentWindow->m_childWindows.removeAll(this))
464 qFatal("QQnxWindow: Window Hierarchy broken; window has parent, but parent hasn't got child.");
466 m_screen->removeWindow(this);
470 void QQnxWindow::setParent(const QPlatformWindow *window)
472 #if defined(QQNXWINDOW_DEBUG)
473 qDebug() << Q_FUNC_INFO << "window =" << this->window() << "platformWindow =" << window;
475 // Cast away the const, we need to modify the hierarchy.
476 QQnxWindow *newParent = 0;
479 newParent = static_cast<QQnxWindow*>((QPlatformWindow *)window);
481 if (newParent == m_parentWindow)
485 m_parentWindow = newParent;
487 // Add to new hierarchy position.
488 if (m_parentWindow) {
489 if (m_parentWindow->m_screen != m_screen)
490 setScreen(m_parentWindow->m_screen);
492 m_parentWindow->m_childWindows.push_back(this);
494 m_screen->addWindow(this);
497 m_screen->updateHierarchy();
500 void QQnxWindow::raise()
502 #if defined(QQNXWINDOW_DEBUG)
503 qDebug() << Q_FUNC_INFO << "window =" << window();
506 QQnxWindow *oldParent = m_parentWindow;
509 oldParent->m_childWindows.push_back(this);
511 m_screen->raiseWindow(this);
514 m_screen->updateHierarchy();
517 void QQnxWindow::lower()
519 #if defined(QQNXWINDOW_DEBUG)
520 qDebug() << Q_FUNC_INFO << "window =" << window();
523 QQnxWindow *oldParent = m_parentWindow;
526 oldParent->m_childWindows.push_front(this);
528 m_screen->lowerWindow(this);
531 m_screen->updateHierarchy();
534 void QQnxWindow::requestActivateWindow()
536 #if defined(QQNXWINDOW_DEBUG)
537 qDebug() << Q_FUNC_INFO << "window =" << window();
540 // TODO: Tell screen to set keyboard focus to this window.
542 // Notify that we gained focus.
546 void QQnxWindow::gainedFocus()
548 #if defined(QQNXWINDOW_DEBUG)
549 qDebug() << Q_FUNC_INFO << "window =" << window();
553 QWindowSystemInterface::handleWindowActivated(window());
556 void QQnxWindow::setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext)
558 // This function does not take ownership of the platform gl context.
559 // It is owned by the frontend QOpenGLContext
560 m_platformOpenGLContext = platformOpenGLContext;
563 QQnxWindow *QQnxWindow::findWindow(screen_window_t windowHandle)
565 if (m_window == windowHandle)
568 Q_FOREACH (QQnxWindow *window, m_childWindows) {
569 QQnxWindow * const result = window->findWindow(windowHandle);
577 void QQnxWindow::updateZorder(int &topZorder)
580 int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ZORDER, &topZorder);
584 qFatal("QQnxWindow: failed to set window z-order=%d, errno=%d, mWindow=%p", topZorder, errno, m_window);
586 QList<QQnxWindow*>::const_iterator it;
588 for (it = m_childWindows.begin(); it != m_childWindows.end(); it++)
589 (*it)->updateZorder(topZorder);
592 void QQnxWindow::copyBack(const QRegion ®ion, int dx, int dy, bool flush)
594 #if defined(QQNXWINDOW_DEBUG)
595 qDebug() << Q_FUNC_INFO << "window =" << window();
599 // Abort if previous buffer is invalid
600 if (m_previousBufferIndex == -1) {
604 // Abort if nothing to copy
605 if (region.isEmpty()) {
609 QQnxBuffer ¤tBuffer = m_buffers[m_currentBufferIndex];
610 QQnxBuffer &previousBuffer = m_buffers[m_previousBufferIndex];
612 // Break down region into non-overlapping rectangles
613 QVector<QRect> rects = region.rects();
614 for (int i = rects.size() - 1; i >= 0; i--) {
615 // Clip rectangle to bounds of target
616 QRect rect = rects[i].intersected( currentBuffer.rect() );
621 // Setup blit operation
622 int attribs[] = { SCREEN_BLIT_SOURCE_X, rect.x(),
623 SCREEN_BLIT_SOURCE_Y, rect.y(),
624 SCREEN_BLIT_SOURCE_WIDTH, rect.width(),
625 SCREEN_BLIT_SOURCE_HEIGHT, rect.height(),
626 SCREEN_BLIT_DESTINATION_X, rect.x() + dx,
627 SCREEN_BLIT_DESTINATION_Y, rect.y() + dy,
628 SCREEN_BLIT_DESTINATION_WIDTH, rect.width(),
629 SCREEN_BLIT_DESTINATION_HEIGHT, rect.height(),
632 // Queue blit operation
634 result = screen_blit(m_screenContext, currentBuffer.nativeBuffer(), previousBuffer.nativeBuffer(), attribs);
636 qFatal("QQnxWindow: failed to blit buffers, errno=%d", errno);
640 // Check if flush requested
642 // Wait for all blits to complete
644 result = screen_flush_blits(m_screenContext, SCREEN_WAIT_IDLE);
646 qFatal("QQnxWindow: failed to flush blits, errno=%d", errno);
649 // Buffer was modified outside the CPU
650 currentBuffer.invalidateInCache();
654 int QQnxWindow::platformWindowFormatToNativeFormat(const QSurfaceFormat &format)
656 #if defined(QQNXWINDOW_DEBUG)
657 qDebug() << Q_FUNC_INFO;
659 // Extract size of colour channels from window format
660 int redSize = format.redBufferSize();
662 qFatal("QQnxWindow: red size not defined");
665 int greenSize = format.greenBufferSize();
666 if (greenSize == -1) {
667 qFatal("QQnxWindow: green size not defined");
670 int blueSize = format.blueBufferSize();
671 if (blueSize == -1) {
672 qFatal("QQnxWindow: blue size not defined");
675 // select matching native format
676 if (redSize == 5 && greenSize == 6 && blueSize == 5) {
677 return SCREEN_FORMAT_RGB565;
678 } else if (redSize == 8 && greenSize == 8 && blueSize == 8) {
679 return SCREEN_FORMAT_RGBA8888;
681 qFatal("QQnxWindow: unsupported pixel format");