QNX: Enable threaded OpenGL rendering on QNX
[profile/ivi/qtbase.git] / src / plugins / platforms / qnx / qqnxintegration.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 "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 #if defined(Q_OS_BLACKBERRY)
55 #include "qqnxbpseventfilter.h"
56 #include "qqnxnavigatorbps.h"
57 #include "qqnxtheme.h"
58 #include "qqnxvirtualkeyboardbps.h"
59 #elif defined(QQNX_PPS)
60 #include "qqnxnavigatorpps.h"
61 #include "qqnxvirtualkeyboardpps.h"
62 #endif
63
64 #if defined(QQNX_PPS)
65 #  include "qqnxnavigatoreventnotifier.h"
66 #  include "qqnxclipboard.h"
67
68 #  if defined(QQNX_IMF)
69 #    include "qqnxinputcontext_imf.h"
70 #  else
71 #    include "qqnxinputcontext_noimf.h"
72 #  endif
73 #endif
74
75 #include "private/qgenericunixfontdatabase_p.h"
76
77 #if defined(Q_OS_BLACKBERRY)
78 #include "qqnxeventdispatcher_blackberry.h"
79 #else
80 #include "private/qgenericunixeventdispatcher_p.h"
81 #endif
82
83 #include <qpa/qplatformwindow.h>
84 #include <QtGui/QWindowSystemInterface>
85
86 #if !defined(QT_NO_OPENGL)
87 #include "qqnxglbackingstore.h"
88 #include "qqnxglcontext.h"
89
90 #include <QtGui/QOpenGLContext>
91 #endif
92
93 #include <QtCore/QDebug>
94 #include <QtCore/QHash>
95
96 #include <errno.h>
97
98 #ifdef QQNXINTEGRATION_DEBUG
99 #define qIntegrationDebug qDebug
100 #else
101 #define qIntegrationDebug QT_NO_QDEBUG_MACRO
102 #endif
103
104 QT_BEGIN_NAMESPACE
105
106 QQnxWindowMapper QQnxIntegration::ms_windowMapper;
107 QMutex QQnxIntegration::ms_windowMapperMutex;
108
109 QQnxIntegration::QQnxIntegration()
110     : QPlatformIntegration()
111     , m_screenEventThread(0)
112     , m_navigatorEventHandler(new QQnxNavigatorEventHandler())
113     , m_virtualKeyboard(0)
114 #if defined(QQNX_PPS)
115     , m_navigatorEventNotifier(0)
116     , m_inputContext(0)
117 #endif
118     , m_services(0)
119     , m_fontDatabase(new QGenericUnixFontDatabase())
120 #if !defined(QT_NO_OPENGL)
121     , m_paintUsingOpenGL(false)
122 #endif
123 #if defined(Q_OS_BLACKBERRY)
124     , m_eventDispatcher(new QQnxEventDispatcherBlackberry())
125     , m_bpsEventFilter(0)
126 #else
127     , m_eventDispatcher(createUnixEventDispatcher())
128 #endif
129     , m_nativeInterface(new QQnxNativeInterface())
130     , m_screenEventHandler(new QQnxScreenEventHandler())
131 #if !defined(QT_NO_CLIPBOARD)
132     , m_clipboard(0)
133 #endif
134 {
135     qIntegrationDebug() << Q_FUNC_INFO;
136     // Open connection to QNX composition manager
137     errno = 0;
138     int result = screen_create_context(&m_screenContext, SCREEN_APPLICATION_CONTEXT);
139     if (result != 0) {
140         qFatal("QQnx: failed to connect to composition manager, errno=%d", errno);
141     }
142
143     // Not on BlackBerry, it has specialised event dispatcher which also handles navigator events
144 #if !defined(Q_OS_BLACKBERRY) && defined(QQNX_PPS)
145     // Create/start navigator event notifier
146     m_navigatorEventNotifier = new QQnxNavigatorEventNotifier(m_navigatorEventHandler);
147
148     // delay invocation of start() to the time the event loop is up and running
149     // needed to have the QThread internals of the main thread properly initialized
150     QMetaObject::invokeMethod(m_navigatorEventNotifier, "start", Qt::QueuedConnection);
151 #endif
152
153 #if !defined(QT_NO_OPENGL)
154     // Initialize global OpenGL resources
155     QQnxGLContext::initialize();
156 #endif
157
158     // Create/start event thread
159 #if defined(QQNX_SCREENEVENTTHREAD)
160     m_screenEventThread = new QQnxScreenEventThread(m_screenContext, m_screenEventHandler);
161     m_screenEventThread->start();
162 #endif
163
164     // Not on BlackBerry, it has specialised event dispatcher which also handles virtual keyboard events
165 #if !defined(Q_OS_BLACKBERRY) && defined(QQNX_PPS)
166     // Create/start the keyboard class.
167     m_virtualKeyboard = new QQnxVirtualKeyboardPps();
168
169     // delay invocation of start() to the time the event loop is up and running
170     // needed to have the QThread internals of the main thread properly initialized
171     QMetaObject::invokeMethod(m_virtualKeyboard, "start", Qt::QueuedConnection);
172 #endif
173
174 #if defined(Q_OS_BLACKBERRY)
175     m_navigator = new QQnxNavigatorBps();
176 #elif defined(QQNX_PPS)
177     m_navigator = new QQnxNavigatorPps();
178 #endif
179
180     // Create services handling class
181     if (m_navigator)
182         m_services = new QQnxServices(m_navigator);
183
184 #if defined(Q_OS_BLACKBERRY)
185     QQnxVirtualKeyboardBps* virtualKeyboardBps = new QQnxVirtualKeyboardBps;
186     m_bpsEventFilter = new QQnxBpsEventFilter(m_navigatorEventHandler,
187             (m_screenEventThread ? 0 : m_screenEventHandler), virtualKeyboardBps);
188     m_bpsEventFilter->installOnEventDispatcher(m_eventDispatcher);
189
190     m_virtualKeyboard = virtualKeyboardBps;
191 #endif
192
193     // Create displays for all possible screens (which may not be attached). We have to do this
194     // *after* the call to m_bpsEventFilter->installOnEventDispatcher(m_eventDispatcher). The
195     // reason for this is that we have to be registered for NAVIGATOR events before we create the
196     // QQnxScreen objects, and hence the QQnxRootWindow's. It is when the NAVIGATOR service sees
197     // the window creation that it starts sending us messages which results in a race if we
198     // create the displays first.
199     createDisplays();
200
201 #if !defined(QQNX_SCREENEVENTTHREAD) && defined(Q_OS_BLACKBERRY)
202     // Register for screen domain events with bps
203     Q_FOREACH (QQnxScreen *screen, m_screens)
204         m_bpsEventFilter->registerForScreenEvents(screen);
205 #endif
206
207     if (m_virtualKeyboard) {
208         // TODO check if we need to do this for all screens or only the primary one
209         QObject::connect(m_virtualKeyboard, SIGNAL(heightChanged(int)),
210                          primaryDisplay(), SLOT(keyboardHeightChanged(int)));
211
212 #if defined(QQNX_PPS)
213         // Set up the input context
214         m_inputContext = new QQnxInputContext(*m_virtualKeyboard);
215 #endif
216     }
217
218 }
219
220 QQnxIntegration::~QQnxIntegration()
221 {
222     qIntegrationDebug() << Q_FUNC_INFO << "platform plugin shutdown begin";
223     delete m_nativeInterface;
224
225 #if defined(QQNX_PPS)
226     // Destroy input context
227     delete m_inputContext;
228 #endif
229
230     // Destroy the keyboard class.
231     delete m_virtualKeyboard;
232
233 #if !defined(QT_NO_CLIPBOARD)
234     // Delete the clipboard
235     delete m_clipboard;
236 #endif
237
238     // Stop/destroy navigator event notifier
239 #if defined(QQNX_PPS)
240     delete m_navigatorEventNotifier;
241 #endif
242     delete m_navigatorEventHandler;
243
244 #if defined(QQNX_SCREENEVENTTHREAD)
245     // Stop/destroy screen event thread
246     delete m_screenEventThread;
247 #elif defined(Q_OS_BLACKBERRY)
248     Q_FOREACH (QQnxScreen *screen, m_screens)
249         m_bpsEventFilter->unregisterForScreenEvents(screen);
250 #endif
251
252 #if defined(Q_OS_BLACKBERRY)
253     delete m_bpsEventFilter;
254 #endif
255
256     delete m_screenEventHandler;
257
258     // Destroy all displays
259     destroyDisplays();
260
261     // Close connection to QNX composition manager
262     screen_destroy_context(m_screenContext);
263
264 #if !defined(QT_NO_OPENGL)
265     // Cleanup global OpenGL resources
266     QQnxGLContext::shutdown();
267 #endif
268
269     // Destroy services class
270     delete m_services;
271
272     // Destroy navigator interface
273     delete m_navigator;
274
275     qIntegrationDebug() << Q_FUNC_INFO << "platform plugin shutdown end";
276 }
277
278 bool QQnxIntegration::hasCapability(QPlatformIntegration::Capability cap) const
279 {
280     qIntegrationDebug() << Q_FUNC_INFO;
281     switch (cap) {
282     case ThreadedPixmaps:
283         return true;
284 #if defined(QT_OPENGL_ES)
285     case OpenGL:
286     case ThreadedOpenGL:
287     case BufferQueueingOpenGL:
288         return true;
289 #endif
290     default:
291         return QPlatformIntegration::hasCapability(cap);
292     }
293 }
294
295 QPlatformWindow *QQnxIntegration::createPlatformWindow(QWindow *window) const
296 {
297     qIntegrationDebug() << Q_FUNC_INFO;
298     return new QQnxWindow(window, m_screenContext);
299 }
300
301 QPlatformBackingStore *QQnxIntegration::createPlatformBackingStore(QWindow *window) const
302 {
303     qIntegrationDebug() << Q_FUNC_INFO;
304 #if !defined(QT_NO_OPENGL)
305     if (paintUsingOpenGL())
306         return new QQnxGLBackingStore(window);
307     else
308 #endif
309         return new QQnxRasterBackingStore(window);
310 }
311
312 #if !defined(QT_NO_OPENGL)
313 QPlatformOpenGLContext *QQnxIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
314 {
315     qIntegrationDebug() << Q_FUNC_INFO;
316     return new QQnxGLContext(context);
317 }
318 #endif
319
320 #if defined(QQNX_PPS)
321 QPlatformInputContext *QQnxIntegration::inputContext() const
322 {
323     qIntegrationDebug() << Q_FUNC_INFO;
324     return m_inputContext;
325 }
326 #endif
327
328 void QQnxIntegration::moveToScreen(QWindow *window, int screen)
329 {
330     qIntegrationDebug() << Q_FUNC_INFO << "w =" << window << ", s =" << screen;
331
332     // get platform window used by widget
333     QQnxWindow *platformWindow = static_cast<QQnxWindow *>(window->handle());
334
335     // lookup platform screen by index
336     QQnxScreen *platformScreen = m_screens.at(screen);
337
338     // move the platform window to the platform screen
339     platformWindow->setScreen(platformScreen);
340 }
341
342 QAbstractEventDispatcher *QQnxIntegration::guiThreadEventDispatcher() const
343 {
344     qIntegrationDebug() << Q_FUNC_INFO;
345     return m_eventDispatcher;
346 }
347
348 QPlatformNativeInterface *QQnxIntegration::nativeInterface() const
349 {
350     return m_nativeInterface;
351 }
352
353 #if !defined(QT_NO_CLIPBOARD)
354 QPlatformClipboard *QQnxIntegration::clipboard() const
355 {
356     qIntegrationDebug() << Q_FUNC_INFO;
357
358 #if defined(QQNX_PPS)
359     if (!m_clipboard) {
360         m_clipboard = new QQnxClipboard;
361     }
362 #endif
363     return m_clipboard;
364 }
365 #endif
366
367 QVariant QQnxIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
368 {
369     qIntegrationDebug() << Q_FUNC_INFO;
370     if (hint == ShowIsFullScreen)
371         return true;
372
373     return QPlatformIntegration::styleHint(hint);
374 }
375
376 QPlatformServices * QQnxIntegration::services() const
377 {
378     return m_services;
379 }
380
381 #if defined(Q_OS_BLACKBERRY)
382 QStringList QQnxIntegration::themeNames() const
383 {
384     return QStringList(QQnxTheme::name());
385 }
386
387 QPlatformTheme *QQnxIntegration::createPlatformTheme(const QString &name) const
388 {
389     qIntegrationDebug() << Q_FUNC_INFO << "name =" << name;
390     if (name == QQnxTheme::name())
391         return new QQnxTheme(m_fontDatabase, m_bpsEventFilter);
392     return QPlatformIntegration::createPlatformTheme(name);
393 }
394 #endif
395
396 QWindow *QQnxIntegration::window(screen_window_t qnxWindow)
397 {
398     qIntegrationDebug() << Q_FUNC_INFO;
399     QMutexLocker locker(&ms_windowMapperMutex);
400     Q_UNUSED(locker);
401     return ms_windowMapper.value(qnxWindow, 0);
402 }
403
404 void QQnxIntegration::addWindow(screen_window_t qnxWindow, QWindow *window)
405 {
406     qIntegrationDebug() << Q_FUNC_INFO;
407     QMutexLocker locker(&ms_windowMapperMutex);
408     Q_UNUSED(locker);
409     ms_windowMapper.insert(qnxWindow, window);
410 }
411
412 void QQnxIntegration::removeWindow(screen_window_t qnxWindow)
413 {
414     qIntegrationDebug() << Q_FUNC_INFO;
415     QMutexLocker locker(&ms_windowMapperMutex);
416     Q_UNUSED(locker);
417     ms_windowMapper.remove(qnxWindow);
418 }
419
420 void QQnxIntegration::createDisplays()
421 {
422     qIntegrationDebug() << Q_FUNC_INFO;
423     // Query number of displays
424     errno = 0;
425     int displayCount;
426     int result = screen_get_context_property_iv(m_screenContext, SCREEN_PROPERTY_DISPLAY_COUNT, &displayCount);
427     if (result != 0) {
428         qFatal("QQnxIntegration: failed to query display count, errno=%d", errno);
429     }
430
431     // Get all displays
432     errno = 0;
433     screen_display_t *displays = (screen_display_t *)alloca(sizeof(screen_display_t) * displayCount);
434     result = screen_get_context_property_pv(m_screenContext, SCREEN_PROPERTY_DISPLAYS, (void **)displays);
435     if (result != 0) {
436         qFatal("QQnxIntegration: failed to query displays, errno=%d", errno);
437     }
438
439     for (int i=0; i<displayCount; i++) {
440         qIntegrationDebug() << Q_FUNC_INFO << "Creating screen for display" << i;
441         QQnxScreen *screen = new QQnxScreen(m_screenContext, displays[i], i==0);
442         m_screens.append(screen);
443         screenAdded(screen);
444
445         QObject::connect(m_screenEventHandler, SIGNAL(newWindowCreated(void *)),
446                          screen, SLOT(newWindowCreated(void *)));
447         QObject::connect(m_screenEventHandler, SIGNAL(windowClosed(void *)),
448                          screen, SLOT(windowClosed(void *)));
449
450         QObject::connect(m_navigatorEventHandler, SIGNAL(rotationChanged(int)), screen, SLOT(setRotation(int)));
451         QObject::connect(m_navigatorEventHandler, SIGNAL(windowGroupActivated(QByteArray)), screen, SLOT(activateWindowGroup(QByteArray)));
452         QObject::connect(m_navigatorEventHandler, SIGNAL(windowGroupDeactivated(QByteArray)), screen, SLOT(deactivateWindowGroup(QByteArray)));
453     }
454 }
455
456 void QQnxIntegration::destroyDisplays()
457 {
458     qIntegrationDebug() << Q_FUNC_INFO;
459     qDeleteAll(m_screens);
460     m_screens.clear();
461 }
462
463 QQnxScreen *QQnxIntegration::primaryDisplay() const
464 {
465     return m_screens.first();
466 }
467
468 QT_END_NAMESPACE