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