qt6-bb10/src/plugins/platforms/qnx/qqnxintegration.cpp

497 lines
14 KiB
C++

/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qqnxintegration.h"
#include "qqnxscreeneventthread.h"
#include "qqnxnativeinterface.h"
#include "qqnxrasterbackingstore.h"
#include "qqnxscreen.h"
#include "qqnxscreeneventhandler.h"
#include "qqnxwindow.h"
#include "qqnxnavigatoreventhandler.h"
#include "qqnxabstractnavigator.h"
#include "qqnxabstractvirtualkeyboard.h"
#include "qqnxservices.h"
#if defined(Q_OS_BLACKBERRY)
#include "qqnxbpseventfilter.h"
#include "qqnxnavigatorbps.h"
#include "qqnxtheme.h"
#include "qqnxvirtualkeyboardbps.h"
#elif defined(QQNX_PPS)
#include "qqnxnavigatorpps.h"
#include "qqnxvirtualkeyboardpps.h"
#endif
#if defined(QQNX_PPS)
# include "qqnxnavigatoreventnotifier.h"
# include "qqnxclipboard.h"
# if defined(QQNX_IMF)
# include "qqnxinputcontext_imf.h"
# else
# include "qqnxinputcontext_noimf.h"
# endif
#endif
#include "private/qgenericunixfontdatabase_p.h"
#if defined(Q_OS_BLACKBERRY)
#include "qqnxeventdispatcher_blackberry.h"
#else
#include "private/qgenericunixeventdispatcher_p.h"
#endif
#include <qpa/qplatformwindow.h>
#include <QtGui/QWindowSystemInterface>
#if !defined(QT_NO_OPENGL)
#include "qqnxglbackingstore.h"
#include "qqnxglcontext.h"
#include <QtGui/QOpenGLContext>
#endif
#include <QtCore/QDebug>
#include <QtCore/QHash>
#include <errno.h>
QT_BEGIN_NAMESPACE
QQnxWindowMapper QQnxIntegration::ms_windowMapper;
QMutex QQnxIntegration::ms_windowMapperMutex;
QQnxIntegration::QQnxIntegration()
: QPlatformIntegration()
, m_screenEventThread(0)
, m_navigatorEventHandler(new QQnxNavigatorEventHandler())
, m_virtualKeyboard(0)
#if defined(QQNX_PPS)
, m_navigatorEventNotifier(0)
, m_inputContext(0)
#endif
, m_services(0)
, m_fontDatabase(new QGenericUnixFontDatabase())
#if !defined(QT_NO_OPENGL)
, m_paintUsingOpenGL(false)
#endif
#if defined(Q_OS_BLACKBERRY)
, m_eventDispatcher(new QQnxEventDispatcherBlackberry())
, m_bpsEventFilter(0)
#else
, m_eventDispatcher(createUnixEventDispatcher())
#endif
, m_nativeInterface(new QQnxNativeInterface())
, m_screenEventHandler(new QQnxScreenEventHandler())
#if !defined(QT_NO_CLIPBOARD)
, m_clipboard(0)
#endif
{
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// Open connection to QNX composition manager
errno = 0;
int result = screen_create_context(&m_screenContext, SCREEN_APPLICATION_CONTEXT);
if (result != 0) {
qFatal("QQnx: failed to connect to composition manager, errno=%d", errno);
}
// Not on BlackBerry, it has specialised event dispatcher which also handles navigator events
#if !defined(Q_OS_BLACKBERRY) && defined(QQNX_PPS)
// Create/start navigator event notifier
m_navigatorEventNotifier = new QQnxNavigatorEventNotifier(m_navigatorEventHandler);
// delay invocation of start() to the time the event loop is up and running
// needed to have the QThread internals of the main thread properly initialized
QMetaObject::invokeMethod(m_navigatorEventNotifier, "start", Qt::QueuedConnection);
#endif
#if !defined(QT_NO_OPENGL)
// Initialize global OpenGL resources
QQnxGLContext::initialize();
#endif
// Create/start event thread
// Not on BlackBerry, it has specialised event dispatcher which also handles screen events
#if !defined(Q_OS_BLACKBERRY)
m_screenEventThread = new QQnxScreenEventThread(m_screenContext, m_screenEventHandler);
m_screenEventThread->start();
#endif
// Not on BlackBerry, it has specialised event dispatcher which also handles virtual keyboard events
#if !defined(Q_OS_BLACKBERRY) && defined(QQNX_PPS)
// Create/start the keyboard class.
m_virtualKeyboard = new QQnxVirtualKeyboardPps();
// delay invocation of start() to the time the event loop is up and running
// needed to have the QThread internals of the main thread properly initialized
QMetaObject::invokeMethod(m_virtualKeyboard, "start", Qt::QueuedConnection);
#endif
#if defined(Q_OS_BLACKBERRY)
m_navigator = new QQnxNavigatorBps();
#elif defined(QQNX_PPS)
m_navigator = new QQnxNavigatorPps();
#endif
// Create services handling class
if (m_navigator)
m_services = new QQnxServices(m_navigator);
#if defined(Q_OS_BLACKBERRY)
QQnxVirtualKeyboardBps* virtualKeyboardBps = new QQnxVirtualKeyboardBps;
m_bpsEventFilter = new QQnxBpsEventFilter(m_navigatorEventHandler, m_screenEventHandler, virtualKeyboardBps);
m_bpsEventFilter->installOnEventDispatcher(m_eventDispatcher);
m_virtualKeyboard = virtualKeyboardBps;
#endif
// Create displays for all possible screens (which may not be attached). We have to do this
// *after* the call to m_bpsEventFilter->installOnEventDispatcher(m_eventDispatcher). The
// reason for this is that we have to be registered for NAVIGATOR events before we create the
// QQnxScreen objects, and hence the QQnxRootWindow's. It is when the NAVIGATOR service sees
// the window creation that it starts sending us messages which results in a race if we
// create the displays first.
createDisplays();
#if defined(Q_OS_BLACKBERRY)
// Register for screen domain events with bps
Q_FOREACH (QQnxScreen *screen, m_screens)
m_bpsEventFilter->registerForScreenEvents(screen);
#endif
if (m_virtualKeyboard) {
// TODO check if we need to do this for all screens or only the primary one
QObject::connect(m_virtualKeyboard, SIGNAL(heightChanged(int)),
primaryDisplay(), SLOT(keyboardHeightChanged(int)));
#if defined(QQNX_PPS)
// Set up the input context
m_inputContext = new QQnxInputContext(*m_virtualKeyboard);
#endif
}
}
QQnxIntegration::~QQnxIntegration()
{
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << "QQnx: platform plugin shutdown begin";
#endif
delete m_nativeInterface;
#if defined(QQNX_PPS)
// Destroy input context
delete m_inputContext;
#endif
// Destroy the keyboard class.
delete m_virtualKeyboard;
#if !defined(QT_NO_CLIPBOARD)
// Delete the clipboard
delete m_clipboard;
#endif
// Stop/destroy navigator event notifier
#if defined(QQNX_PPS)
delete m_navigatorEventNotifier;
#endif
delete m_navigatorEventHandler;
#if !defined(Q_OS_BLACKBERRY)
// Stop/destroy screen event thread
delete m_screenEventThread;
#else
Q_FOREACH (QQnxScreen *screen, m_screens)
m_bpsEventFilter->unregisterForScreenEvents(screen);
delete m_bpsEventFilter;
#endif
delete m_screenEventHandler;
// Destroy all displays
destroyDisplays();
// Close connection to QNX composition manager
screen_destroy_context(m_screenContext);
#if !defined(QT_NO_OPENGL)
// Cleanup global OpenGL resources
QQnxGLContext::shutdown();
#endif
// Destroy services class
delete m_services;
// Destroy navigator interface
delete m_navigator;
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << "QQnx: platform plugin shutdown end";
#endif
}
bool QQnxIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
switch (cap) {
case ThreadedPixmaps: return true;
#if defined(QT_OPENGL_ES)
case OpenGL:
return true;
#endif
default: return QPlatformIntegration::hasCapability(cap);
}
}
QPlatformWindow *QQnxIntegration::createPlatformWindow(QWindow *window) const
{
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
return new QQnxWindow(window, m_screenContext);
}
QPlatformBackingStore *QQnxIntegration::createPlatformBackingStore(QWindow *window) const
{
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
#if !defined(QT_NO_OPENGL)
if (paintUsingOpenGL())
return new QQnxGLBackingStore(window);
else
#endif
return new QQnxRasterBackingStore(window);
}
#if !defined(QT_NO_OPENGL)
QPlatformOpenGLContext *QQnxIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
return new QQnxGLContext(context);
}
#endif
#if defined(QQNX_PPS)
QPlatformInputContext *QQnxIntegration::inputContext() const
{
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
return m_inputContext;
}
#endif
void QQnxIntegration::moveToScreen(QWindow *window, int screen)
{
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << "QQnxIntegration::moveToScreen - w=" << window << ", s=" << screen;
#endif
// get platform window used by widget
QQnxWindow *platformWindow = static_cast<QQnxWindow *>(window->handle());
// lookup platform screen by index
QQnxScreen *platformScreen = m_screens.at(screen);
// move the platform window to the platform screen
platformWindow->setScreen(platformScreen);
}
QAbstractEventDispatcher *QQnxIntegration::guiThreadEventDispatcher() const
{
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
return m_eventDispatcher;
}
QPlatformNativeInterface *QQnxIntegration::nativeInterface() const
{
return m_nativeInterface;
}
#if !defined(QT_NO_CLIPBOARD)
QPlatformClipboard *QQnxIntegration::clipboard() const
{
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
#if defined(QQNX_PPS)
if (!m_clipboard) {
m_clipboard = new QQnxClipboard;
}
#endif
return m_clipboard;
}
#endif
QVariant QQnxIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
{
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
if (hint == ShowIsFullScreen)
return true;
return QPlatformIntegration::styleHint(hint);
}
QPlatformServices * QQnxIntegration::services() const
{
return m_services;
}
#if defined(Q_OS_BLACKBERRY)
QStringList QQnxIntegration::themeNames() const
{
return QStringList(QQnxTheme::name());
}
QPlatformTheme *QQnxIntegration::createPlatformTheme(const QString &name) const
{
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO << "name =" << name;
#endif
if (name == QQnxTheme::name())
return new QQnxTheme(m_fontDatabase);
return QPlatformIntegration::createPlatformTheme(name);
}
#endif
QWindow *QQnxIntegration::window(screen_window_t qnxWindow)
{
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
QMutexLocker locker(&ms_windowMapperMutex);
Q_UNUSED(locker);
return ms_windowMapper.value(qnxWindow, 0);
}
void QQnxIntegration::addWindow(screen_window_t qnxWindow, QWindow *window)
{
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
QMutexLocker locker(&ms_windowMapperMutex);
Q_UNUSED(locker);
ms_windowMapper.insert(qnxWindow, window);
}
void QQnxIntegration::removeWindow(screen_window_t qnxWindow)
{
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
QMutexLocker locker(&ms_windowMapperMutex);
Q_UNUSED(locker);
ms_windowMapper.remove(qnxWindow);
}
void QQnxIntegration::createDisplays()
{
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// Query number of displays
errno = 0;
int displayCount;
int result = screen_get_context_property_iv(m_screenContext, SCREEN_PROPERTY_DISPLAY_COUNT, &displayCount);
if (result != 0) {
qFatal("QQnxIntegration: failed to query display count, errno=%d", errno);
}
// Get all displays
errno = 0;
screen_display_t *displays = (screen_display_t *)alloca(sizeof(screen_display_t) * displayCount);
result = screen_get_context_property_pv(m_screenContext, SCREEN_PROPERTY_DISPLAYS, (void **)displays);
if (result != 0) {
qFatal("QQnxIntegration: failed to query displays, errno=%d", errno);
}
for (int i=0; i<displayCount; i++) {
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << "QQnxIntegration::Creating screen for display " << i;
#endif
QQnxScreen *screen = new QQnxScreen(m_screenContext, displays[i], i==0);
m_screens.append(screen);
screenAdded(screen);
QObject::connect(m_screenEventHandler, SIGNAL(newWindowCreated(void *)),
screen, SLOT(newWindowCreated(void *)));
QObject::connect(m_screenEventHandler, SIGNAL(windowClosed(void *)),
screen, SLOT(windowClosed(void *)));
QObject::connect(m_navigatorEventHandler, SIGNAL(rotationChanged(int)), screen, SLOT(setRotation(int)));
QObject::connect(m_navigatorEventHandler, SIGNAL(windowGroupActivated(QByteArray)), screen, SLOT(activateWindowGroup(QByteArray)));
QObject::connect(m_navigatorEventHandler, SIGNAL(windowGroupDeactivated(QByteArray)), screen, SLOT(deactivateWindowGroup(QByteArray)));
}
}
void QQnxIntegration::destroyDisplays()
{
#if defined(QQNXINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
qDeleteAll(m_screens);
m_screens.clear();
}
QQnxScreen *QQnxIntegration::primaryDisplay() const
{
return m_screens.first();
}
QT_END_NAMESPACE