f20fb6011fbffc5bb6993c330fca000d3e85dad0
[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: return true;
283 #if defined(QT_OPENGL_ES)
284     case OpenGL:
285         return true;
286 #endif
287     default: return QPlatformIntegration::hasCapability(cap);
288     }
289 }
290
291 QPlatformWindow *QQnxIntegration::createPlatformWindow(QWindow *window) const
292 {
293     qIntegrationDebug() << Q_FUNC_INFO;
294     return new QQnxWindow(window, m_screenContext);
295 }
296
297 QPlatformBackingStore *QQnxIntegration::createPlatformBackingStore(QWindow *window) const
298 {
299     qIntegrationDebug() << Q_FUNC_INFO;
300 #if !defined(QT_NO_OPENGL)
301     if (paintUsingOpenGL())
302         return new QQnxGLBackingStore(window);
303     else
304 #endif
305         return new QQnxRasterBackingStore(window);
306 }
307
308 #if !defined(QT_NO_OPENGL)
309 QPlatformOpenGLContext *QQnxIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
310 {
311     qIntegrationDebug() << Q_FUNC_INFO;
312     return new QQnxGLContext(context);
313 }
314 #endif
315
316 #if defined(QQNX_PPS)
317 QPlatformInputContext *QQnxIntegration::inputContext() const
318 {
319     qIntegrationDebug() << Q_FUNC_INFO;
320     return m_inputContext;
321 }
322 #endif
323
324 void QQnxIntegration::moveToScreen(QWindow *window, int screen)
325 {
326     qIntegrationDebug() << Q_FUNC_INFO << "w =" << window << ", s =" << screen;
327
328     // get platform window used by widget
329     QQnxWindow *platformWindow = static_cast<QQnxWindow *>(window->handle());
330
331     // lookup platform screen by index
332     QQnxScreen *platformScreen = m_screens.at(screen);
333
334     // move the platform window to the platform screen
335     platformWindow->setScreen(platformScreen);
336 }
337
338 QAbstractEventDispatcher *QQnxIntegration::guiThreadEventDispatcher() const
339 {
340     qIntegrationDebug() << Q_FUNC_INFO;
341     return m_eventDispatcher;
342 }
343
344 QPlatformNativeInterface *QQnxIntegration::nativeInterface() const
345 {
346     return m_nativeInterface;
347 }
348
349 #if !defined(QT_NO_CLIPBOARD)
350 QPlatformClipboard *QQnxIntegration::clipboard() const
351 {
352     qIntegrationDebug() << Q_FUNC_INFO;
353
354 #if defined(QQNX_PPS)
355     if (!m_clipboard) {
356         m_clipboard = new QQnxClipboard;
357     }
358 #endif
359     return m_clipboard;
360 }
361 #endif
362
363 QVariant QQnxIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
364 {
365     qIntegrationDebug() << Q_FUNC_INFO;
366     if (hint == ShowIsFullScreen)
367         return true;
368
369     return QPlatformIntegration::styleHint(hint);
370 }
371
372 QPlatformServices * QQnxIntegration::services() const
373 {
374     return m_services;
375 }
376
377 #if defined(Q_OS_BLACKBERRY)
378 QStringList QQnxIntegration::themeNames() const
379 {
380     return QStringList(QQnxTheme::name());
381 }
382
383 QPlatformTheme *QQnxIntegration::createPlatformTheme(const QString &name) const
384 {
385     qIntegrationDebug() << Q_FUNC_INFO << "name =" << name;
386     if (name == QQnxTheme::name())
387         return new QQnxTheme(m_fontDatabase, m_bpsEventFilter);
388     return QPlatformIntegration::createPlatformTheme(name);
389 }
390 #endif
391
392 QWindow *QQnxIntegration::window(screen_window_t qnxWindow)
393 {
394     qIntegrationDebug() << Q_FUNC_INFO;
395     QMutexLocker locker(&ms_windowMapperMutex);
396     Q_UNUSED(locker);
397     return ms_windowMapper.value(qnxWindow, 0);
398 }
399
400 void QQnxIntegration::addWindow(screen_window_t qnxWindow, QWindow *window)
401 {
402     qIntegrationDebug() << Q_FUNC_INFO;
403     QMutexLocker locker(&ms_windowMapperMutex);
404     Q_UNUSED(locker);
405     ms_windowMapper.insert(qnxWindow, window);
406 }
407
408 void QQnxIntegration::removeWindow(screen_window_t qnxWindow)
409 {
410     qIntegrationDebug() << Q_FUNC_INFO;
411     QMutexLocker locker(&ms_windowMapperMutex);
412     Q_UNUSED(locker);
413     ms_windowMapper.remove(qnxWindow);
414 }
415
416 void QQnxIntegration::createDisplays()
417 {
418     qIntegrationDebug() << Q_FUNC_INFO;
419     // Query number of displays
420     errno = 0;
421     int displayCount;
422     int result = screen_get_context_property_iv(m_screenContext, SCREEN_PROPERTY_DISPLAY_COUNT, &displayCount);
423     if (result != 0) {
424         qFatal("QQnxIntegration: failed to query display count, errno=%d", errno);
425     }
426
427     // Get all displays
428     errno = 0;
429     screen_display_t *displays = (screen_display_t *)alloca(sizeof(screen_display_t) * displayCount);
430     result = screen_get_context_property_pv(m_screenContext, SCREEN_PROPERTY_DISPLAYS, (void **)displays);
431     if (result != 0) {
432         qFatal("QQnxIntegration: failed to query displays, errno=%d", errno);
433     }
434
435     for (int i=0; i<displayCount; i++) {
436         qIntegrationDebug() << Q_FUNC_INFO << "Creating screen for display" << i;
437         QQnxScreen *screen = new QQnxScreen(m_screenContext, displays[i], i==0);
438         m_screens.append(screen);
439         screenAdded(screen);
440
441         QObject::connect(m_screenEventHandler, SIGNAL(newWindowCreated(void *)),
442                          screen, SLOT(newWindowCreated(void *)));
443         QObject::connect(m_screenEventHandler, SIGNAL(windowClosed(void *)),
444                          screen, SLOT(windowClosed(void *)));
445
446         QObject::connect(m_navigatorEventHandler, SIGNAL(rotationChanged(int)), screen, SLOT(setRotation(int)));
447         QObject::connect(m_navigatorEventHandler, SIGNAL(windowGroupActivated(QByteArray)), screen, SLOT(activateWindowGroup(QByteArray)));
448         QObject::connect(m_navigatorEventHandler, SIGNAL(windowGroupDeactivated(QByteArray)), screen, SLOT(deactivateWindowGroup(QByteArray)));
449     }
450 }
451
452 void QQnxIntegration::destroyDisplays()
453 {
454     qIntegrationDebug() << Q_FUNC_INFO;
455     qDeleteAll(m_screens);
456     m_screens.clear();
457 }
458
459 QQnxScreen *QQnxIntegration::primaryDisplay() const
460 {
461     return m_screens.first();
462 }
463
464 QT_END_NAMESPACE