1 /***************************************************************************
2 **
3 ** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
4 ** Contact: https://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qqnxglobal.h"
41 
42 #include "qqnxintegration.h"
43 #include "qqnxscreeneventthread.h"
44 #include "qqnxnativeinterface.h"
45 #include "qqnxrasterbackingstore.h"
46 #include "qqnxscreen.h"
47 #include "qqnxscreeneventhandler.h"
48 #include "qqnxwindow.h"
49 #include "qqnxnavigatoreventhandler.h"
50 #include "qqnxabstractnavigator.h"
51 #include "qqnxabstractvirtualkeyboard.h"
52 #include "qqnxservices.h"
53 
54 #include "qqnxforeignwindow.h"
55 #include "qqnxrasterwindow.h"
56 #if !defined(QT_NO_OPENGL)
57 #include "qqnxeglwindow.h"
58 #endif
59 
60 #if QT_CONFIG(qqnx_pps)
61 #include "qqnxnavigatorpps.h"
62 #include "qqnxnavigatoreventnotifier.h"
63 #include "qqnxvirtualkeyboardpps.h"
64 #endif
65 
66 #if QT_CONFIG(qqnx_pps)
67 #  include "qqnxbuttoneventnotifier.h"
68 #  include "qqnxclipboard.h"
69 #  if QT_CONFIG(qqnx_imf)
70 #    include "qqnxinputcontext_imf.h"
71 #  else
72 #    include "qqnxinputcontext_noimf.h"
73 #  endif
74 #endif
75 
76 #include <qpa/qplatforminputcontextfactory_p.h>
77 #include <qpa/qplatforminputcontext.h>
78 
79 #include "private/qgenericunixfontdatabase_p.h"
80 #include "private/qgenericunixeventdispatcher_p.h"
81 
82 #include <qpa/qplatformwindow.h>
83 #include <qpa/qwindowsysteminterface.h>
84 
85 #include <QtGui/private/qguiapplication_p.h>
86 
87 #if !defined(QT_NO_OPENGL)
88 #include "qqnxglcontext.h"
89 #include <QtGui/QOpenGLContext>
90 #endif
91 
92 #include <private/qsimpledrag_p.h>
93 
94 #include <QtCore/QDebug>
95 #include <QtCore/QJsonDocument>
96 #include <QtCore/QJsonObject>
97 #include <QtCore/QJsonArray>
98 #include <QtCore/QFile>
99 #include <errno.h>
100 
101 #if defined(QQNXINTEGRATION_DEBUG)
102 #define qIntegrationDebug qDebug
103 #else
104 #define qIntegrationDebug QT_NO_QDEBUG_MACRO
105 #endif
106 
107 QT_BEGIN_NAMESPACE
108 
109 QQnxIntegration *QQnxIntegration::ms_instance;
110 
parseOptions(const QStringList & paramList)111 static inline QQnxIntegration::Options parseOptions(const QStringList &paramList)
112 {
113     QQnxIntegration::Options options = QQnxIntegration::NoOptions;
114     if (!paramList.contains(QLatin1String("no-fullscreen"))) {
115         options |= QQnxIntegration::FullScreenApplication;
116     }
117 
118     if (paramList.contains(QLatin1String("flush-screen-context"))) {
119         options |= QQnxIntegration::AlwaysFlushScreenContext;
120     }
121 
122     if (paramList.contains(QLatin1String("rootwindow"))) {
123         options |= QQnxIntegration::RootWindow;
124     }
125 
126     if (!paramList.contains(QLatin1String("disable-EGL_KHR_surfaceless_context"))) {
127         options |= QQnxIntegration::SurfacelessEGLContext;
128     }
129 
130     return options;
131 }
132 
getContextCapabilities(const QStringList & paramList)133 static inline int getContextCapabilities(const QStringList &paramList)
134 {
135     QString contextCapabilitiesPrefix = QStringLiteral("screen-context-capabilities=");
136     int contextCapabilities = SCREEN_APPLICATION_CONTEXT;
137     for (const QString &param : paramList) {
138         if (param.startsWith(contextCapabilitiesPrefix)) {
139             QStringRef value = param.midRef(contextCapabilitiesPrefix.length());
140             bool ok = false;
141             contextCapabilities = value.toInt(&ok, 0);
142             if (!ok)
143                 contextCapabilities = SCREEN_APPLICATION_CONTEXT;
144         }
145     }
146     return contextCapabilities;
147 }
148 
QQnxIntegration(const QStringList & paramList)149 QQnxIntegration::QQnxIntegration(const QStringList &paramList)
150     : QPlatformIntegration()
151     , m_screenContextId(256, 0)
152     , m_screenEventThread(0)
153     , m_navigatorEventHandler(new QQnxNavigatorEventHandler())
154     , m_virtualKeyboard(0)
155 #if QT_CONFIG(qqnx_pps)
156     , m_navigatorEventNotifier(0)
157     , m_inputContext(0)
158     , m_buttonsNotifier(new QQnxButtonEventNotifier())
159 #endif
160     , m_qpaInputContext(0)
161     , m_services(0)
162     , m_fontDatabase(new QGenericUnixFontDatabase())
163     , m_eventDispatcher(createUnixEventDispatcher())
164     , m_nativeInterface(new QQnxNativeInterface(this))
165     , m_screenEventHandler(new QQnxScreenEventHandler(this))
166 #if !defined(QT_NO_CLIPBOARD)
167     , m_clipboard(0)
168 #endif
169     , m_navigator(0)
170 #if QT_CONFIG(draganddrop)
171     , m_drag(new QSimpleDrag())
172 #endif
173 #if QT_CONFIG(opengl)
174     , m_eglDisplay(EGL_NO_DISPLAY)
175 #endif
176 {
177     ms_instance = this;
178     m_options = parseOptions(paramList);
179     qIntegrationDebug();
180 
181     // Open connection to QNX composition manager
182     if (screen_create_context(&m_screenContext, getContextCapabilities(paramList))) {
183         qFatal("%s - Screen: Failed to create screen context - Error: %s (%i)",
184                Q_FUNC_INFO, strerror(errno), errno);
185     }
186     screen_get_context_property_cv(m_screenContext,
187                                    SCREEN_PROPERTY_ID,
188                                    m_screenContextId.size(),
189                                    m_screenContextId.data());
190     m_screenContextId.resize(strlen(m_screenContextId.constData()));
191 
192 #if QT_CONFIG(qqnx_pps)
193     // Create/start navigator event notifier
194     m_navigatorEventNotifier = new QQnxNavigatorEventNotifier(m_navigatorEventHandler);
195 
196     // delay invocation of start() to the time the event loop is up and running
197     // needed to have the QThread internals of the main thread properly initialized
198     QMetaObject::invokeMethod(m_navigatorEventNotifier, "start", Qt::QueuedConnection);
199 #endif
200 
201 #if QT_CONFIG(opengl)
202     createEglDisplay();
203 #endif
204 
205     // Create/start event thread
206     m_screenEventThread = new QQnxScreenEventThread(m_screenContext);
207     m_screenEventHandler->setScreenEventThread(m_screenEventThread);
208     m_screenEventThread->start();
209 
210     m_qpaInputContext = QPlatformInputContextFactory::create();
211 
212 #if QT_CONFIG(qqnx_pps)
213     if (!m_qpaInputContext) {
214         // Create/start the keyboard class.
215         m_virtualKeyboard = new QQnxVirtualKeyboardPps();
216 
217         // delay invocation of start() to the time the event loop is up and running
218         // needed to have the QThread internals of the main thread properly initialized
219         QMetaObject::invokeMethod(m_virtualKeyboard, "start", Qt::QueuedConnection);
220     }
221 #endif
222 
223 #if QT_CONFIG(qqnx_pps)
224     m_navigator = new QQnxNavigatorPps();
225 #endif
226 
227     // Create services handling class
228     if (m_navigator)
229         m_services = new QQnxServices(m_navigator);
230 
231     createDisplays();
232 
233     if (m_virtualKeyboard) {
234         // TODO check if we need to do this for all screens or only the primary one
235         QObject::connect(m_virtualKeyboard, SIGNAL(heightChanged(int)),
236                          primaryDisplay(), SLOT(keyboardHeightChanged(int)));
237 
238 #if QT_CONFIG(qqnx_pps)
239         // Set up the input context
240         m_inputContext = new QQnxInputContext(this, *m_virtualKeyboard);
241 #if QT_CONFIG(qqnx_imf)
242         m_screenEventHandler->addScreenEventFilter(m_inputContext);
243 #endif
244 #endif
245     }
246 
247 #if QT_CONFIG(qqnx_pps)
248     // delay invocation of start() to the time the event loop is up and running
249     // needed to have the QThread internals of the main thread properly initialized
250     QMetaObject::invokeMethod(m_buttonsNotifier, "start", Qt::QueuedConnection);
251 #endif
252 }
253 
~QQnxIntegration()254 QQnxIntegration::~QQnxIntegration()
255 {
256     qIntegrationDebug("platform plugin shutdown begin");
257     delete m_nativeInterface;
258 
259 #if QT_CONFIG(draganddrop)
260     // Destroy the drag object
261     delete m_drag;
262 #endif
263 
264 #if !defined(QT_NO_CLIPBOARD)
265     // Delete the clipboard
266     delete m_clipboard;
267 #endif
268 
269     // Stop/destroy navigator event notifier
270 #if QT_CONFIG(qqnx_pps)
271     delete m_navigatorEventNotifier;
272 #endif
273     delete m_navigatorEventHandler;
274 
275     // Stop/destroy screen event thread
276     delete m_screenEventThread;
277 
278     // In case the event-dispatcher was never transferred to QCoreApplication
279     delete m_eventDispatcher;
280 
281     delete m_screenEventHandler;
282 
283     // Destroy all displays
284     destroyDisplays();
285 
286     // Close connection to QNX composition manager
287     screen_destroy_context(m_screenContext);
288 
289 #if QT_CONFIG(opengl)
290     destroyEglDisplay();
291 #endif
292 
293 #if QT_CONFIG(qqnx_pps)
294     // Destroy the hardware button notifier
295     delete m_buttonsNotifier;
296 
297     // Destroy input context
298     delete m_inputContext;
299 #endif
300     delete m_qpaInputContext;
301 
302     // Destroy the keyboard class.
303     delete m_virtualKeyboard;
304 
305     // Destroy services class
306     delete m_services;
307 
308     // Destroy navigator interface
309     delete m_navigator;
310 
311     ms_instance = nullptr;
312 
313     qIntegrationDebug("platform plugin shutdown end");
314 }
315 
hasCapability(QPlatformIntegration::Capability cap) const316 bool QQnxIntegration::hasCapability(QPlatformIntegration::Capability cap) const
317 {
318     qIntegrationDebug();
319     switch (cap) {
320     case MultipleWindows:
321     case ForeignWindows:
322     case ThreadedPixmaps:
323         return true;
324 #if !defined(QT_NO_OPENGL)
325     case OpenGL:
326     case ThreadedOpenGL:
327     case BufferQueueingOpenGL:
328         return true;
329 #endif
330     default:
331         return QPlatformIntegration::hasCapability(cap);
332     }
333 }
334 
createForeignWindow(QWindow * window,WId nativeHandle) const335 QPlatformWindow *QQnxIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const
336 {
337     screen_window_t screenWindow = reinterpret_cast<screen_window_t>(nativeHandle);
338     if (this->window(screenWindow)) {
339         qWarning() << "QWindow already created for foreign window"
340                    << screenWindow;
341         return nullptr;
342     }
343 
344     return new QQnxForeignWindow(window, m_screenContext, screenWindow);
345 }
346 
createPlatformWindow(QWindow * window) const347 QPlatformWindow *QQnxIntegration::createPlatformWindow(QWindow *window) const
348 {
349     qIntegrationDebug();
350     QSurface::SurfaceType surfaceType = window->surfaceType();
351     const bool needRootWindow = options() & RootWindow;
352     switch (surfaceType) {
353     case QSurface::RasterSurface:
354         return new QQnxRasterWindow(window, m_screenContext, needRootWindow);
355 #if !defined(QT_NO_OPENGL)
356     case QSurface::OpenGLSurface:
357         return new QQnxEglWindow(window, m_screenContext, needRootWindow);
358 #endif
359     default:
360         qFatal("QQnxWindow: unsupported window API");
361     }
362     return 0;
363 }
364 
createPlatformBackingStore(QWindow * window) const365 QPlatformBackingStore *QQnxIntegration::createPlatformBackingStore(QWindow *window) const
366 {
367     qIntegrationDebug();
368     return new QQnxRasterBackingStore(window);
369 }
370 
371 #if !defined(QT_NO_OPENGL)
createPlatformOpenGLContext(QOpenGLContext * context) const372 QPlatformOpenGLContext *QQnxIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
373 {
374     qIntegrationDebug();
375 
376     // Get color channel sizes from window format
377     QSurfaceFormat format = context->format();
378     int alphaSize = format.alphaBufferSize();
379     int redSize = format.redBufferSize();
380     int greenSize = format.greenBufferSize();
381     int blueSize = format.blueBufferSize();
382 
383     // Check if all channels are don't care
384     if (alphaSize == -1 && redSize == -1 && greenSize == -1 && blueSize == -1) {
385         // Set color channels based on depth of window's screen
386         QQnxScreen *screen = static_cast<QQnxScreen*>(context->screen()->handle());
387         int depth = screen->depth();
388         if (depth == 32) {
389             // SCREEN_FORMAT_RGBA8888
390             alphaSize = 8;
391             redSize = 8;
392             greenSize = 8;
393             blueSize = 8;
394         } else {
395             // SCREEN_FORMAT_RGB565
396             alphaSize = 0;
397             redSize = 5;
398             greenSize = 6;
399             blueSize = 5;
400         }
401     } else {
402         // Choose best match based on supported pixel formats
403         if (alphaSize <= 0 && redSize <= 5 && greenSize <= 6 && blueSize <= 5) {
404             // SCREEN_FORMAT_RGB565
405             alphaSize = 0;
406             redSize = 5;
407             greenSize = 6;
408             blueSize = 5;
409         } else {
410             // SCREEN_FORMAT_RGBA8888
411             alphaSize = 8;
412             redSize = 8;
413             greenSize = 8;
414             blueSize = 8;
415         }
416     }
417 
418     // Update color channel sizes in window format
419     format.setAlphaBufferSize(alphaSize);
420     format.setRedBufferSize(redSize);
421     format.setGreenBufferSize(greenSize);
422     format.setBlueBufferSize(blueSize);
423     context->setFormat(format);
424 
425     QQnxGLContext *ctx = new QQnxGLContext(context->format(), context->shareHandle());
426     return ctx;
427 }
428 #endif
429 
inputContext() const430 QPlatformInputContext *QQnxIntegration::inputContext() const
431 {
432     qIntegrationDebug();
433     if (m_qpaInputContext)
434         return m_qpaInputContext;
435     return m_inputContext;
436 }
437 
moveToScreen(QWindow * window,int screen)438 void QQnxIntegration::moveToScreen(QWindow *window, int screen)
439 {
440     qIntegrationDebug() << "w =" << window << ", s =" << screen;
441 
442     // get platform window used by widget
443     QQnxWindow *platformWindow = static_cast<QQnxWindow *>(window->handle());
444 
445     // lookup platform screen by index
446     QQnxScreen *platformScreen = m_screens.at(screen);
447 
448     // move the platform window to the platform screen
449     platformWindow->setScreen(platformScreen);
450 }
451 
createEventDispatcher() const452 QAbstractEventDispatcher *QQnxIntegration::createEventDispatcher() const
453 {
454     qIntegrationDebug();
455 
456     // We transfer ownersip of the event-dispatcher to QtCoreApplication
457     QAbstractEventDispatcher *eventDispatcher = m_eventDispatcher;
458     m_eventDispatcher = 0;
459 
460     return eventDispatcher;
461 }
462 
nativeInterface() const463 QPlatformNativeInterface *QQnxIntegration::nativeInterface() const
464 {
465     return m_nativeInterface;
466 }
467 
468 #if !defined(QT_NO_CLIPBOARD)
clipboard() const469 QPlatformClipboard *QQnxIntegration::clipboard() const
470 {
471     qIntegrationDebug();
472 
473 #if QT_CONFIG(qqnx_pps)
474     if (!m_clipboard)
475         m_clipboard = new QQnxClipboard;
476 #endif
477     return m_clipboard;
478 }
479 #endif
480 
481 #if QT_CONFIG(draganddrop)
drag() const482 QPlatformDrag *QQnxIntegration::drag() const
483 {
484     return m_drag;
485 }
486 #endif
487 
styleHint(QPlatformIntegration::StyleHint hint) const488 QVariant QQnxIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
489 {
490     qIntegrationDebug();
491     if ((hint == ShowIsFullScreen) && (m_options & FullScreenApplication))
492         return true;
493 
494     return QPlatformIntegration::styleHint(hint);
495 }
496 
services() const497 QPlatformServices * QQnxIntegration::services() const
498 {
499     return m_services;
500 }
501 
window(screen_window_t qnxWindow) const502 QWindow *QQnxIntegration::window(screen_window_t qnxWindow) const
503 {
504     qIntegrationDebug();
505     QMutexLocker locker(&m_windowMapperMutex);
506     Q_UNUSED(locker);
507     return m_windowMapper.value(qnxWindow, 0);
508 }
509 
addWindow(screen_window_t qnxWindow,QWindow * window)510 void QQnxIntegration::addWindow(screen_window_t qnxWindow, QWindow *window)
511 {
512     qIntegrationDebug();
513     QMutexLocker locker(&m_windowMapperMutex);
514     Q_UNUSED(locker);
515     m_windowMapper.insert(qnxWindow, window);
516 }
517 
removeWindow(screen_window_t qnxWindow)518 void QQnxIntegration::removeWindow(screen_window_t qnxWindow)
519 {
520     qIntegrationDebug();
521     QMutexLocker locker(&m_windowMapperMutex);
522     Q_UNUSED(locker);
523     m_windowMapper.remove(qnxWindow);
524 }
525 
526 /*!
527   Get display ID for given \a display
528 
529   Returns -1 for failure, otherwise returns display ID
530  */
getIdOfDisplay(screen_display_t display)531 static int getIdOfDisplay(screen_display_t display)
532 {
533     int displayId;
534     if (screen_get_display_property_iv(display,
535                                        SCREEN_PROPERTY_ID,
536                                        &displayId) == 0) {
537         return displayId;
538     }
539     return -1;
540 }
541 
542 /*!
543   Read JSON configuration file for the QNX display order
544 
545   Returns true if file was read successfully and fills \a requestedDisplays
546  */
getRequestedDisplays(QJsonArray & requestedDisplays)547 static bool getRequestedDisplays(QJsonArray &requestedDisplays)
548 {
549    // Check if display configuration file is provided
550     QByteArray json = qgetenv("QT_QPA_QNX_DISPLAY_CONFIG");
551     if (json.isEmpty())
552         return false;
553 
554     // Check if configuration file exists
555     QFile file(QString::fromUtf8(json));
556     if (!file.open(QFile::ReadOnly)) {
557         qWarning() << "Could not open config file" << json << "for reading";
558         return false;
559     }
560 
561     // Read config file and check it's json
562     const QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
563     if (!doc.isObject()) {
564         qWarning() << "Invalid config file" << json
565                    << "- no top-level JSON object";
566         return false;
567     }
568 
569     // Read the requested display order
570     const QJsonObject object = doc.object();
571     requestedDisplays = object.value(QLatin1String("displayOrder")).toArray();
572 
573     return true;
574 }
575 
576 /*!
577   Match \a availableDisplays with display order defined in a json file
578   pointed to by QT_QPA_QNX_DISPLAY_CONFIG. Display order must use same
579   identifiers as defined for displays in graphics.conf. Number of
580   available displays must be specified in \a displayCount
581 
582   An example configuration is below:
583   \badcode
584     {
585       "displayOrder": [ 3, 1 ]
586     }
587   \endcode
588 
589   Returns ordered list of displays. If no order was specified, returns
590   displays in the same order as in the original list.
591 */
sortDisplays(screen_display_t * availableDisplays,int displayCount)592 QList<screen_display_t *> QQnxIntegration::sortDisplays(screen_display_t *availableDisplays, int displayCount)
593 {
594     // Intermediate list for sorting
595     QList<screen_display_t *> allDisplays;
596     for (int i = 0; i < displayCount; i++)
597         allDisplays.append(&availableDisplays[i]);
598 
599     // Read requested display order if available
600     QJsonArray requestedDisplays;
601     if (!getRequestedDisplays(requestedDisplays))
602         return allDisplays;
603 
604     // Go through all the requested displays IDs
605     QList<screen_display_t *> orderedDisplays;
606     for (const QJsonValue &value : qAsConst(requestedDisplays)) {
607         int requestedValue = value.toInt();
608 
609         // Move all displays with matching ID from the intermediate list
610         // to the beginning of the ordered list
611         for (auto it = allDisplays.begin(), end = allDisplays.end(); it != end; ++it) {
612             screen_display_t *display = *it;
613             if (getIdOfDisplay(*display) == requestedValue) {
614                 orderedDisplays.append(display);
615                 allDisplays.erase(it);
616                 break;
617             }
618         }
619     }
620 
621     // Place all unordered displays to the end of list
622     orderedDisplays.append(allDisplays);
623 
624     return orderedDisplays;
625 }
626 
createDisplays()627 void QQnxIntegration::createDisplays()
628 {
629     qIntegrationDebug();
630     // Query number of displays
631     int displayCount = 0;
632     int result = screen_get_context_property_iv(m_screenContext, SCREEN_PROPERTY_DISPLAY_COUNT,
633                                                 &displayCount);
634     Q_SCREEN_CRITICALERROR(result, "Failed to query display count");
635 
636     if (Q_UNLIKELY(displayCount < 1)) {
637         // Never happens, even if there's no display, libscreen returns 1
638         qFatal("QQnxIntegration: displayCount=%d", displayCount);
639     }
640 
641     // Get all displays
642     screen_display_t *displays = (screen_display_t *)alloca(sizeof(screen_display_t) * displayCount);
643     result = screen_get_context_property_pv(m_screenContext, SCREEN_PROPERTY_DISPLAYS,
644                                             (void **)displays);
645     QList<screen_display_t *> orderedDisplays = sortDisplays(displays, displayCount);
646     Q_SCREEN_CRITICALERROR(result, "Failed to query displays");
647 
648     // If it's primary, we create a QScreen for it even if it's not attached
649     // since Qt will dereference QGuiApplication::primaryScreen()
650     createDisplay(*orderedDisplays[0], /*isPrimary=*/true);
651 
652     for (int i=1; i<displayCount; i++) {
653         int isAttached = 1;
654         result = screen_get_display_property_iv(*orderedDisplays[i], SCREEN_PROPERTY_ATTACHED,
655                                                 &isAttached);
656         Q_SCREEN_CHECKERROR(result, "Failed to query display attachment");
657 
658         if (!isAttached) {
659             qIntegrationDebug("Skipping non-attached display %d", i);
660             continue;
661         }
662 
663         qIntegrationDebug("Creating screen for display %d", i);
664         createDisplay(*orderedDisplays[i], /*isPrimary=*/false);
665     } // of displays iteration
666 }
667 
createDisplay(screen_display_t display,bool isPrimary)668 void QQnxIntegration::createDisplay(screen_display_t display, bool isPrimary)
669 {
670     QQnxScreen *screen = new QQnxScreen(m_screenContext, display, isPrimary);
671     m_screens.append(screen);
672     QWindowSystemInterface::handleScreenAdded(screen);
673     screen->adjustOrientation();
674 
675     QObject::connect(m_screenEventHandler, SIGNAL(newWindowCreated(void*)),
676                      screen, SLOT(newWindowCreated(void*)));
677     QObject::connect(m_screenEventHandler, SIGNAL(windowClosed(void*)),
678                      screen, SLOT(windowClosed(void*)));
679 
680     QObject::connect(m_navigatorEventHandler, SIGNAL(rotationChanged(int)), screen, SLOT(setRotation(int)));
681     QObject::connect(m_navigatorEventHandler, SIGNAL(windowGroupActivated(QByteArray)), screen, SLOT(activateWindowGroup(QByteArray)));
682     QObject::connect(m_navigatorEventHandler, SIGNAL(windowGroupDeactivated(QByteArray)), screen, SLOT(deactivateWindowGroup(QByteArray)));
683     QObject::connect(m_navigatorEventHandler, SIGNAL(windowGroupStateChanged(QByteArray,Qt::WindowState)),
684             screen, SLOT(windowGroupStateChanged(QByteArray,Qt::WindowState)));
685 }
686 
removeDisplay(QQnxScreen * screen)687 void QQnxIntegration::removeDisplay(QQnxScreen *screen)
688 {
689     Q_CHECK_PTR(screen);
690     Q_ASSERT(m_screens.contains(screen));
691     m_screens.removeAll(screen);
692     QWindowSystemInterface::handleScreenRemoved(screen);
693 }
694 
destroyDisplays()695 void QQnxIntegration::destroyDisplays()
696 {
697     qIntegrationDebug();
698     Q_FOREACH (QQnxScreen *screen, m_screens) {
699         QWindowSystemInterface::handleScreenRemoved(screen);
700     }
701     m_screens.clear();
702 }
703 
screenForNative(screen_display_t qnxScreen) const704 QQnxScreen *QQnxIntegration::screenForNative(screen_display_t qnxScreen) const
705 {
706     Q_FOREACH (QQnxScreen *screen, m_screens) {
707         if (screen->nativeDisplay() == qnxScreen)
708             return screen;
709     }
710 
711     return 0;
712 }
713 
primaryDisplay() const714 QQnxScreen *QQnxIntegration::primaryDisplay() const
715 {
716     return m_screens.first();
717 }
718 
options() const719 QQnxIntegration::Options QQnxIntegration::options() const
720 {
721     return m_options;
722 }
723 
screenContext()724 screen_context_t QQnxIntegration::screenContext()
725 {
726     return m_screenContext;
727 }
728 
screenContextId()729 QByteArray QQnxIntegration::screenContextId()
730 {
731     return m_screenContextId;
732 }
733 
navigatorEventHandler()734 QQnxNavigatorEventHandler *QQnxIntegration::navigatorEventHandler()
735 {
736     return m_navigatorEventHandler;
737 }
738 
supportsNavigatorEvents() const739 bool QQnxIntegration::supportsNavigatorEvents() const
740 {
741     // If QQNX_PPS is defined then we have navigator
742     return m_navigator != 0;
743 }
744 
745 #if QT_CONFIG(opengl)
createEglDisplay()746 void QQnxIntegration::createEglDisplay()
747 {
748     qIntegrationDebug();
749 
750     // Initialize connection to EGL
751     m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
752     if (Q_UNLIKELY(m_eglDisplay == EGL_NO_DISPLAY))
753         qFatal("QQnxiIntegration: failed to obtain EGL display: %x", eglGetError());
754 
755     EGLBoolean eglResult = eglInitialize(m_eglDisplay, 0, 0);
756     if (Q_UNLIKELY(eglResult != EGL_TRUE))
757         qFatal("QQnxIntegration: failed to initialize EGL display, err=%d", eglGetError());
758 }
759 
destroyEglDisplay()760 void QQnxIntegration::destroyEglDisplay()
761 {
762     qIntegrationDebug();
763 
764     // Close connection to EGL
765     eglTerminate(m_eglDisplay);
766 }
767 #endif
768 
769 QT_END_NAMESPACE
770