summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/plugins/platforms/blackberry/blackberry.pro71
-rw-r--r--src/plugins/platforms/blackberry/main.cpp72
-rw-r--r--src/plugins/platforms/blackberry/qbbbuffer.cpp165
-rw-r--r--src/plugins/platforms/blackberry/qbbbuffer.h74
-rw-r--r--src/plugins/platforms/blackberry/qbbclipboard.cpp132
-rw-r--r--src/plugins/platforms/blackberry/qbbclipboard.h67
-rw-r--r--src/plugins/platforms/blackberry/qbbeventthread.cpp559
-rw-r--r--src/plugins/platforms/blackberry/qbbeventthread.h90
-rw-r--r--src/plugins/platforms/blackberry/qbbglbackingstore.cpp189
-rw-r--r--src/plugins/platforms/blackberry/qbbglbackingstore.h95
-rw-r--r--src/plugins/platforms/blackberry/qbbglcontext.cpp356
-rw-r--r--src/plugins/platforms/blackberry/qbbglcontext.h93
-rw-r--r--src/plugins/platforms/blackberry/qbbinputcontext_imf.cpp1696
-rw-r--r--src/plugins/platforms/blackberry/qbbinputcontext_imf.h132
-rw-r--r--src/plugins/platforms/blackberry/qbbinputcontext_noimf.cpp187
-rw-r--r--src/plugins/platforms/blackberry/qbbinputcontext_noimf.h84
-rw-r--r--src/plugins/platforms/blackberry/qbbintegration.cpp293
-rw-r--r--src/plugins/platforms/blackberry/qbbintegration.h119
-rw-r--r--src/plugins/platforms/blackberry/qbbkeytranslator.h269
-rw-r--r--src/plugins/platforms/blackberry/qbbnavigatorthread.cpp279
-rw-r--r--src/plugins/platforms/blackberry/qbbnavigatorthread.h78
-rw-r--r--src/plugins/platforms/blackberry/qbbrasterbackingstore.cpp166
-rw-r--r--src/plugins/platforms/blackberry/qbbrasterbackingstore.h81
-rw-r--r--src/plugins/platforms/blackberry/qbbrootwindow.cpp257
-rw-r--r--src/plugins/platforms/blackberry/qbbrootwindow.h81
-rw-r--r--src/plugins/platforms/blackberry/qbbscreen.cpp315
-rw-r--r--src/plugins/platforms/blackberry/qbbscreen.h121
-rw-r--r--src/plugins/platforms/blackberry/qbbvirtualkeyboard.cpp500
-rw-r--r--src/plugins/platforms/blackberry/qbbvirtualkeyboard.h130
-rw-r--r--src/plugins/platforms/blackberry/qbbwindow.cpp665
-rw-r--r--src/plugins/platforms/blackberry/qbbwindow.h133
-rw-r--r--src/plugins/platforms/platforms.pro4
32 files changed, 7553 insertions, 0 deletions
diff --git a/src/plugins/platforms/blackberry/blackberry.pro b/src/plugins/platforms/blackberry/blackberry.pro
new file mode 100644
index 0000000000..94b9c5dbc8
--- /dev/null
+++ b/src/plugins/platforms/blackberry/blackberry.pro
@@ -0,0 +1,71 @@
+TARGET = blackberry
+include(../../qpluginbase.pri)
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms
+QT += opengl opengl-private platformsupport platformsupport-private widgets-private
+
+# Uncomment this to build with support for IMF once it becomes available in the BBNDK
+#CONFIG += qbb_imf
+
+# Uncomment these to enable debugging output for various aspects of the plugin
+#DEFINES += QBBBUFFER_DEBUG
+#DEFINES += QBBCLIPBOARD_DEBUG
+#DEFINES += QBBEVENTTHREAD_DEBUG
+#DEFINES += QBBGLBACKINGSTORE_DEBUG
+#DEFINES += QBBGLCONTEXT_DEBUG
+#DEFINES += QBBINPUTCONTEXT_DEBUG
+#DEFINES += QBBINPUTCONTEXT_IMF_EVENT_DEBUG
+#DEFINES += QBBINTEGRATION_DEBUG
+#DEFINES += QBBNAVIGATORTHREAD_DEBUG
+#DEFINES += QBBRASTERBACKINGSTORE_DEBUG
+#DEFINES += QBBROOTWINDOW_DEBUG
+#DEFINES += QBBSCREEN_DEBUG
+#DEFINES += QBBVIRTUALKEYBOARD_DEBUG
+#DEFINES += QBBWINDOW_DEBUG
+
+SOURCES = main.cpp \
+ qbbbuffer.cpp \
+ qbbeventthread.cpp \
+ qbbglcontext.cpp \
+ qbbglbackingstore.cpp \
+ qbbintegration.cpp \
+ qbbnavigatorthread.cpp \
+ qbbscreen.cpp \
+ qbbwindow.cpp \
+ qbbrasterbackingstore.cpp \
+ qbbvirtualkeyboard.cpp \
+ qbbclipboard.cpp \
+ qbbrootwindow.cpp
+
+HEADERS = qbbbuffer.h \
+ qbbeventthread.h \
+ qbbkeytranslator.h \
+ qbbintegration.h \
+ qbbnavigatorthread.h \
+ qbbglcontext.h \
+ qbbglbackingstore.h \
+ qbbscreen.h \
+ qbbwindow.h \
+ qbbrasterbackingstore.h \
+ qbbvirtualkeyboard.h \
+ qbbclipboard.h \
+ qbbrootwindow.h
+
+CONFIG(qbb_imf) {
+ DEFINES += QBB_IMF
+ HEADERS += qbbinputcontext_imf.h
+ SOURCES += qbbinputcontext_imf.cpp
+} else {
+ HEADERS += qbbinputcontext_noimf.h
+ SOURCES += qbbinputcontext_noimf.cpp
+}
+
+QMAKE_CXXFLAGS += -I./private
+
+LIBS += -lpps -lscreen -lEGL -lclipboard
+
+include (../../../platformsupport/eglconvenience/eglconvenience.pri)
+include (../../../platformsupport/fontdatabases/fontdatabases.pri)
+
+target.path += $$[QT_INSTALL_PLUGINS]/platforms
+INSTALLS += target
diff --git a/src/plugins/platforms/blackberry/main.cpp b/src/plugins/platforms/blackberry/main.cpp
new file mode 100644
index 0000000000..b9e09c0384
--- /dev/null
+++ b/src/plugins/platforms/blackberry/main.cpp
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** 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 <QtGui/QPlatformIntegrationPlugin>
+#include "qbbintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+class QBBIntegrationPlugin : public QPlatformIntegrationPlugin
+{
+public:
+ QStringList keys() const;
+ QPlatformIntegration *create(const QString&, const QStringList&);
+};
+
+QStringList QBBIntegrationPlugin::keys() const
+{
+ QStringList list;
+ list << QLatin1String("blackberry");
+ return list;
+}
+
+QPlatformIntegration *QBBIntegrationPlugin::create(const QString& system, const QStringList& paramList)
+{
+ Q_UNUSED(paramList);
+ if (system.toLower() == QLatin1String("blackberry"))
+ return new QBBIntegration;
+
+ return 0;
+}
+
+Q_EXPORT_PLUGIN2(blackberry, QBBIntegrationPlugin)
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/blackberry/qbbbuffer.cpp b/src/plugins/platforms/blackberry/qbbbuffer.cpp
new file mode 100644
index 0000000000..c4ac04898d
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbbuffer.cpp
@@ -0,0 +1,165 @@
+/***************************************************************************
+**
+** 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 "qbbbuffer.h"
+
+#include <QtCore/QDebug>
+
+#include <errno.h>
+#include <sys/mman.h>
+
+QT_BEGIN_NAMESPACE
+
+QBBBuffer::QBBBuffer()
+ : m_buffer(0)
+{
+#if defined(QBBBUFFER_DEBUG)
+ qDebug() << "QBBBuffer::QBBBuffer - empty";
+#endif
+}
+
+QBBBuffer::QBBBuffer(screen_buffer_t buffer)
+ : m_buffer(buffer)
+{
+#if defined(QBBBUFFER_DEBUG)
+ qDebug() << "QBBBuffer::QBBBuffer - normal";
+#endif
+
+ // Get size of buffer
+ errno = 0;
+ int size[2];
+ int result = screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_BUFFER_SIZE, size);
+ if (result != 0) {
+ qFatal("QBB: failed to query buffer size, errno=%d", errno);
+ }
+
+ // Get stride of buffer
+ errno = 0;
+ int stride;
+ result = screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_STRIDE, &stride);
+ if (result != 0) {
+ qFatal("QBB: failed to query buffer stride, errno=%d", errno);
+ }
+
+ // Get access to buffer's data
+ errno = 0;
+ uchar *dataPtr = 0;
+ result = screen_get_buffer_property_pv(buffer, SCREEN_PROPERTY_POINTER, (void **)&dataPtr);
+ if (result != 0) {
+ qFatal("QBB: failed to query buffer pointer, errno=%d", errno);
+ }
+ if (dataPtr == NULL) {
+ qFatal("QBB: buffer pointer is NULL, errno=%d", errno);
+ }
+
+ // Get format of buffer
+ errno = 0;
+ int screenFormat;
+ result = screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_FORMAT, &screenFormat);
+ if (result != 0) {
+ qFatal("QBB: failed to query buffer format, errno=%d", errno);
+ }
+
+ // Convert screen format to QImage format
+ QImage::Format imageFormat = QImage::Format_Invalid;
+ switch (screenFormat) {
+ case SCREEN_FORMAT_RGBX4444:
+ imageFormat = QImage::Format_RGB444;
+ break;
+ case SCREEN_FORMAT_RGBA4444:
+ imageFormat = QImage::Format_ARGB4444_Premultiplied;
+ break;
+ case SCREEN_FORMAT_RGBX5551:
+ imageFormat = QImage::Format_RGB555;
+ break;
+ case SCREEN_FORMAT_RGB565:
+ imageFormat = QImage::Format_RGB16;
+ break;
+ case SCREEN_FORMAT_RGBX8888:
+ imageFormat = QImage::Format_RGB32;
+ break;
+ case SCREEN_FORMAT_RGBA8888:
+ imageFormat = QImage::Format_ARGB32_Premultiplied;
+ break;
+ default:
+ qFatal("QBB: unsupported buffer format, format=%d", screenFormat);
+ }
+
+ // wrap buffer in an image
+ m_image = QImage(dataPtr, size[0], size[1], stride, imageFormat);
+}
+
+QBBBuffer::QBBBuffer(const QBBBuffer &other)
+ : m_buffer(other.m_buffer),
+ m_image(other.m_image)
+{
+#if defined(QBBBUFFER_DEBUG)
+ qDebug() << "QBBBuffer::QBBBuffer - copy";
+#endif
+}
+
+QBBBuffer::~QBBBuffer()
+{
+#if defined(QBBBUFFER_DEBUG)
+ qDebug() << "QBBBuffer::~QBBBuffer";
+#endif
+}
+
+void QBBBuffer::invalidateInCache()
+{
+#if defined(QBBBUFFER_DEBUG)
+ qDebug() << "QBBBuffer::invalidateInCache";
+#endif
+
+ // Verify native buffer exists
+ if (m_buffer == 0) {
+ qFatal("QBB: can't invalidate cache for null buffer");
+ }
+
+ // Evict buffer's data from cache
+ errno = 0;
+ int result = msync(m_image.bits(), m_image.height() * m_image.bytesPerLine(), MS_INVALIDATE | MS_CACHE_ONLY);
+ if (result != 0) {
+ qFatal("QBB: failed to invalidate cache, errno=%d", errno);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/blackberry/qbbbuffer.h b/src/plugins/platforms/blackberry/qbbbuffer.h
new file mode 100644
index 0000000000..45cedb21a8
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbbuffer.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBBBUFFER_H
+#define QBBBUFFER_H
+
+#include <QtGui/QImage>
+
+#include <screen/screen.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBBBuffer
+{
+public:
+ QBBBuffer();
+ QBBBuffer(screen_buffer_t buffer);
+ QBBBuffer(const QBBBuffer &other);
+ virtual ~QBBBuffer();
+
+ screen_buffer_t nativeBuffer() const { return m_buffer; }
+ const QImage *image() const { return (m_buffer != NULL) ? &m_image : NULL; }
+ QImage *image() { return (m_buffer != NULL) ? &m_image : NULL; }
+
+ QRect rect() const { return m_image.rect(); }
+
+ void invalidateInCache();
+
+private:
+ screen_buffer_t m_buffer;
+ QImage m_image;
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBBUFFER_H
diff --git a/src/plugins/platforms/blackberry/qbbclipboard.cpp b/src/plugins/platforms/blackberry/qbbclipboard.cpp
new file mode 100644
index 0000000000..fce016d5ee
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbclipboard.cpp
@@ -0,0 +1,132 @@
+/***************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT_NO_CLIPBOARD
+
+#include "qbbclipboard.h"
+
+#include <QtGui/QColor>
+
+#include <QtCore/QDebug>
+#include <QtCore/QStringList>
+#include <QtCore/QUrl>
+
+#include <clipboard/clipboard.h>
+#include <errno.h>
+
+QT_BEGIN_NAMESPACE
+static const char *typeList[] = {"text/html", "text/plain", "application/x-color"};
+
+QBBClipboard::QBBClipboard()
+{
+ m_mimeData = 0;
+}
+
+QBBClipboard::~QBBClipboard()
+{
+ delete m_mimeData;
+}
+
+void QBBClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
+{
+ if (mode != QClipboard::Clipboard)
+ return;
+
+ if (m_mimeData != data) {
+ delete m_mimeData;
+ m_mimeData = data;
+ }
+
+ empty_clipboard();
+
+ if (data == 0)
+ return;
+
+ QStringList format = data->formats();
+ for (int i = 0; i < format.size(); ++i) {
+ QString type = format.at(i);
+ QByteArray buf = data->data(type);
+ if (!buf.size())
+ continue;
+
+ int ret = set_clipboard_data(type.toUtf8().data(), buf.size(), buf.data());
+#if defined(QBBCLIPBOARD_DEBUG)
+ qDebug() << "QBB: set " << type.toUtf8().data() << "to clipboard, size=" << buf.size() << ";ret=" << ret;
+#else
+ Q_UNUSED(ret);
+#endif
+ }
+}
+
+void QBBClipboard::readClipboardBuff(const char *type)
+{
+ char *pbuffer;
+ if (is_clipboard_format_present(type) == 0) {
+ int size = get_clipboard_data(type, &pbuffer);
+ if (size != -1 && pbuffer) {
+ QString qtype = type;
+#if defined(QBBCLIPBOARD_DEBUG)
+ qDebug() << "QBB: clipboard has " << qtype;
+#endif
+ m_mimeData->setData(qtype, QByteArray(pbuffer, size));
+ delete pbuffer;
+ }
+ }
+}
+
+QMimeData *QBBClipboard::mimeData(QClipboard::Mode mode)
+{
+ if (mode != QClipboard::Clipboard)
+ return 0;
+
+ if (!m_mimeData)
+ m_mimeData = new QMimeData();
+
+ m_mimeData->clear();
+
+ for (int i = 0; i < 3; i++)
+ readClipboardBuff(typeList[i]);
+
+ return m_mimeData;
+}
+
+QT_END_NAMESPACE
+#endif //QT_NO_CLIPBOAR
diff --git a/src/plugins/platforms/blackberry/qbbclipboard.h b/src/plugins/platforms/blackberry/qbbclipboard.h
new file mode 100644
index 0000000000..b9de9b3e36
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbclipboard.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBBCLIPBOARD_H
+#define QBBCLIPBOARD_H
+
+#ifndef QT_NO_CLIPBOARD
+#include <QtGui/QPlatformClipboard>
+#include <QMimeData>
+
+QT_BEGIN_NAMESPACE
+
+class QBBClipboard : public QPlatformClipboard
+{
+public:
+ QBBClipboard();
+ virtual ~QBBClipboard();
+ virtual QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard);
+ virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard);
+
+private:
+ QMimeData *m_mimeData;
+ void readClipboardBuff(const char *type);
+};
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_CLIPBOARD
+#endif //QBBCLIPBOARD_H
diff --git a/src/plugins/platforms/blackberry/qbbeventthread.cpp b/src/plugins/platforms/blackberry/qbbeventthread.cpp
new file mode 100644
index 0000000000..547428d1c4
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbeventthread.cpp
@@ -0,0 +1,559 @@
+/***************************************************************************
+**
+** 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 "qbbeventthread.h"
+#include "qbbintegration.h"
+#include "qbbkeytranslator.h"
+
+#if defined(QBB_IMF)
+#include "qbbinputcontext_imf.h"
+#else
+#include "qbbinputcontext_noimf.h"
+#endif
+
+#include <QtGui/QWindow>
+#include <QtGui/QPlatformScreen>
+#include <QtGui/QGuiApplication>
+
+#include <QtCore/QDebug>
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/keycodes.h>
+
+#include <cctype>
+
+QBBEventThread::QBBEventThread(screen_context_t context, QPlatformScreen& screen)
+ : QThread(),
+ m_screenContext(context),
+ m_platformScreen(screen),
+ m_quit(false),
+ m_lastButtonState(Qt::NoButton),
+ m_lastMouseWindow(0)
+{
+ // Create a touch device
+ m_touchDevice = new QTouchDevice;
+ m_touchDevice->setType(QTouchDevice::TouchScreen);
+ m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition);
+ QWindowSystemInterface::registerTouchDevice(m_touchDevice);
+
+ // initialize array of touch points
+ for (int i = 0; i < MaximumTouchPoints; i++) {
+
+ // map array index to id
+ m_touchPoints[i].id = i;
+
+ // pressure is not supported - use default
+ m_touchPoints[i].pressure = 1.0;
+
+ // nothing touching
+ m_touchPoints[i].state = Qt::TouchPointReleased;
+ }
+}
+
+QBBEventThread::~QBBEventThread()
+{
+ // block until thread terminates
+ shutdown();
+}
+
+void QBBEventThread::run()
+{
+ screen_event_t event;
+
+ // create screen event
+ errno = 0;
+ int result = screen_create_event(&event);
+ if (result) {
+ qFatal("QBB: failed to create event, errno=%d", errno);
+ }
+
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: event loop started";
+#endif
+
+ // loop indefinitely
+ while (!m_quit) {
+
+ // block until screen event is available
+ errno = 0;
+ result = screen_get_event(m_screenContext, event, -1);
+ if (result) {
+ qFatal("QBB: failed to get event, errno=%d", errno);
+ }
+
+ // process received event
+ dispatchEvent(event);
+ }
+
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: event loop stopped";
+#endif
+
+ // cleanup
+ screen_destroy_event(event);
+}
+
+void QBBEventThread::shutdown()
+{
+ screen_event_t event;
+
+ // create screen event
+ errno = 0;
+ int result = screen_create_event(&event);
+ if (result) {
+ qFatal("QBB: failed to create event, errno=%d", errno);
+ }
+
+ // set the event type as user
+ errno = 0;
+ int type = SCREEN_EVENT_USER;
+ result = screen_set_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type);
+ if (result) {
+ qFatal("QBB: failed to set event type, errno=%d", errno);
+ }
+
+ // NOTE: ignore SCREEN_PROPERTY_USER_DATA; treat all user events as shutdown events
+
+ // post event to event loop so it will wake up and die
+ errno = 0;
+ result = screen_send_event(m_screenContext, event, getpid());
+ if (result) {
+ qFatal("QBB: failed to set event type, errno=%d", errno);
+ }
+
+ // cleanup
+ screen_destroy_event(event);
+
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: event loop shutdown begin";
+#endif
+
+ // block until thread terminates
+ wait();
+
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: event loop shutdown end";
+#endif
+}
+
+void QBBEventThread::dispatchEvent(screen_event_t event)
+{
+ // get the event type
+ errno = 0;
+ int qnxType;
+ int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &qnxType);
+ if (result) {
+ qFatal("QBB: failed to query event type, errno=%d", errno);
+ }
+
+ switch (qnxType) {
+ case SCREEN_EVENT_MTOUCH_TOUCH:
+ case SCREEN_EVENT_MTOUCH_MOVE:
+ case SCREEN_EVENT_MTOUCH_RELEASE:
+ handleTouchEvent(event, qnxType);
+ break;
+
+ case SCREEN_EVENT_KEYBOARD:
+ handleKeyboardEvent(event);
+ break;
+
+ case SCREEN_EVENT_POINTER:
+ handlePointerEvent(event);
+ break;
+
+ case SCREEN_EVENT_CLOSE:
+ handleCloseEvent(event);
+ break;
+
+ case SCREEN_EVENT_USER:
+ // treat all user events as shutdown requests
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: QNX user event";
+#endif
+ m_quit = true;
+ break;
+
+ default:
+ // event ignored
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: QNX unknown event";
+#endif
+ break;
+ }
+}
+
+void QBBEventThread::handleKeyboardEvent(screen_event_t event)
+{
+ // get flags of key event
+ errno = 0;
+ int flags;
+ int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_FLAGS, &flags);
+ if (result) {
+ qFatal("QBB: failed to query event flags, errno=%d", errno);
+ }
+
+ // get key code
+ errno = 0;
+ int sym;
+ result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_SYM, &sym);
+ if (result) {
+ qFatal("QBB: failed to query event sym, errno=%d", errno);
+ }
+
+ int modifiers;
+ result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_MODIFIERS, &modifiers);
+ if (result) {
+ qFatal("QBB: failed to query event modifiers, errno=%d", errno);
+ }
+
+ int scan;
+ result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_SCAN, &scan);
+ if (result) {
+ qFatal("QBB: failed to query event modifiers, errno=%d", errno);
+ }
+
+ int cap;
+ result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_CAP, &cap);
+ if (result) {
+ qFatal("QBB: failed to query event cap, errno=%d", errno);
+ }
+
+ injectKeyboardEvent(flags, sym, modifiers, scan, cap);
+}
+
+void QBBEventThread::injectKeyboardEvent(int flags, int sym, int modifiers, int scan, int cap)
+{
+ Q_UNUSED(scan);
+
+ Qt::KeyboardModifiers qtMod = Qt::NoModifier;
+ if (modifiers & KEYMOD_SHIFT)
+ qtMod |= Qt::ShiftModifier;
+ if (modifiers & KEYMOD_CTRL)
+ qtMod |= Qt::ControlModifier;
+ if (modifiers & KEYMOD_ALT)
+ qtMod |= Qt::AltModifier;
+
+ // determine event type
+ QEvent::Type type = (flags & KEY_DOWN) ? QEvent::KeyPress : QEvent::KeyRelease;
+
+ // Check if the key cap is valid
+ if (flags & KEY_CAP_VALID) {
+ Qt::Key key;
+ QString keyStr;
+
+ if (cap >= 0x20 && cap <= 0x0ff) {
+ key = Qt::Key(std::toupper(cap)); // Qt expects the CAP to be upper case.
+
+ if ( qtMod & Qt::ControlModifier ) {
+ keyStr = QChar((int)(key & 0x3f));
+ } else {
+ if (flags & KEY_SYM_VALID) {
+ keyStr = QChar(sym);
+ }
+ }
+ } else if ((cap > 0x0ff && cap < UNICODE_PRIVATE_USE_AREA_FIRST) || cap > UNICODE_PRIVATE_USE_AREA_LAST) {
+ key = (Qt::Key)cap;
+ keyStr = QChar(sym);
+ } else {
+ if (isKeypadKey(cap))
+ qtMod |= Qt::KeypadModifier; // Is this right?
+ key = keyTranslator(cap);
+ }
+
+ QWindowSystemInterface::handleKeyEvent(QGuiApplication::focusWindow(), type, key, qtMod, keyStr);
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: Qt key t=" << type << ", k=" << key << ", s=" << keyStr;
+#endif
+ }
+}
+
+void QBBEventThread::handlePointerEvent(screen_event_t event)
+{
+ errno = 0;
+
+ // Query the window that was clicked
+ screen_window_t qnxWindow;
+ void *handle;
+ int result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle);
+ if (result) {
+ qFatal("QBB: failed to query event window, errno=%d", errno);
+ }
+ qnxWindow = static_cast<screen_window_t>(handle);
+
+ // Query the button states
+ int buttonState = 0;
+ result = screen_get_event_property_iv(event, SCREEN_PROPERTY_BUTTONS, &buttonState);
+ if (result) {
+ qFatal("QBB: failed to query event button state, errno=%d", errno);
+ }
+
+ // Query the window position
+ int windowPos[2];
+ result = screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos);
+ if (result) {
+ qFatal("QBB: failed to query event window position, errno=%d", errno);
+ }
+
+ // Query the screen position
+ int pos[2];
+ result = screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos);
+ if (result) {
+ qFatal("QBB: failed to query event position, errno=%d", errno);
+ }
+
+ // Query the wheel delta
+ int wheelDelta = 0;
+ result = screen_get_event_property_iv(event, SCREEN_PROPERTY_MOUSE_WHEEL, &wheelDelta);
+ if (result) {
+ qFatal("QBB: failed to query event wheel delta, errno=%d", errno);
+ }
+
+ // Map window handle to top-level QWindow
+ QWindow *w = QBBIntegration::window(qnxWindow);
+
+ // Generate enter and leave events as needed.
+ if (qnxWindow != m_lastMouseWindow) {
+ QWindow *wOld = QBBIntegration::window(m_lastMouseWindow);
+
+ if (wOld) {
+ QWindowSystemInterface::handleLeaveEvent(wOld);
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: Qt leave, w=" << wOld;
+#endif
+ }
+
+ if (w) {
+ QWindowSystemInterface::handleEnterEvent(w);
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: Qt enter, w=" << w;
+#endif
+ }
+ }
+ m_lastMouseWindow = qnxWindow;
+
+ // Apply scaling to wheel delta and invert value for Qt. We'll probably want to scale
+ // this via a system preference at some point. But for now this is a sane value and makes
+ // the wheel usable.
+ wheelDelta *= -10;
+
+ // convert point to local coordinates
+ QPoint globalPoint(pos[0], pos[1]);
+ QPoint localPoint(windowPos[0], windowPos[1]);
+
+ // Convert buttons.
+ Qt::MouseButtons buttons = Qt::NoButton;
+ if (buttonState & 1)
+ buttons |= Qt::LeftButton;
+ if (buttonState & 2)
+ buttons |= Qt::MidButton;
+ if (buttonState & 4)
+ buttons |= Qt::RightButton;
+
+ if (w) {
+ // Inject mouse event into Qt only if something has changed.
+ if (m_lastGlobalMousePoint != globalPoint ||
+ m_lastLocalMousePoint != localPoint ||
+ m_lastButtonState != buttons) {
+ QWindowSystemInterface::handleMouseEvent(w, localPoint, globalPoint, buttons);
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: Qt mouse, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), b=" << static_cast<int>(buttons);
+#endif
+ }
+
+ if (wheelDelta) {
+ // Screen only supports a single wheel, so we will assume Vertical orientation for
+ // now since that is pretty much standard.
+ QWindowSystemInterface::handleWheelEvent(w, localPoint, globalPoint, wheelDelta, Qt::Vertical);
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: Qt wheel, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), d=" << static_cast<int>(wheelDelta);
+#endif
+ }
+ }
+
+ m_lastGlobalMousePoint = globalPoint;
+ m_lastLocalMousePoint = localPoint;
+ m_lastButtonState = buttons;
+}
+
+void QBBEventThread::handleTouchEvent(screen_event_t event, int qnxType)
+{
+ // get display coordinates of touch
+ errno = 0;
+ int pos[2];
+ int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos);
+ if (result) {
+ qFatal("QBB: failed to query event position, errno=%d", errno);
+ }
+
+ // get window coordinates of touch
+ errno = 0;
+ int windowPos[2];
+ result = screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos);
+ if (result) {
+ qFatal("QBB: failed to query event window position, errno=%d", errno);
+ }
+
+ // determine which finger touched
+ errno = 0;
+ int touchId;
+ result = screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_ID, &touchId);
+ if (result) {
+ qFatal("QBB: failed to query event touch id, errno=%d", errno);
+ }
+
+ // determine which window was touched
+ errno = 0;
+ void *handle;
+ result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle);
+ if (result) {
+ qFatal("QBB: failed to query event window, errno=%d", errno);
+ }
+ screen_window_t qnxWindow = static_cast<screen_window_t>(handle);
+
+ // check if finger is valid
+ if (touchId < MaximumTouchPoints) {
+
+ // Map window handle to top-level QWindow
+ QWindow *w = QBBIntegration::window(qnxWindow);
+
+ // Generate enter and leave events as needed.
+ if (qnxWindow != m_lastMouseWindow) {
+ QWindow *wOld = QBBIntegration::window(m_lastMouseWindow);
+
+ if (wOld) {
+ QWindowSystemInterface::handleLeaveEvent(wOld);
+ #if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: Qt leave, w=" << wOld;
+ #endif
+ }
+
+ if (w) {
+ QWindowSystemInterface::handleEnterEvent(w);
+ #if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: Qt enter, w=" << w;
+ #endif
+ }
+ }
+ m_lastMouseWindow = qnxWindow;
+
+ if (w) {
+ // convert primary touch to mouse event
+ if (touchId == 0) {
+
+ // convert point to local coordinates
+ QPoint globalPoint(pos[0], pos[1]);
+ QPoint localPoint(windowPos[0], windowPos[1]);
+
+ // map touch state to button state
+ Qt::MouseButtons buttons = (qnxType == SCREEN_EVENT_MTOUCH_RELEASE) ? Qt::NoButton : Qt::LeftButton;
+
+ // inject event into Qt
+ QWindowSystemInterface::handleMouseEvent(w, localPoint, globalPoint, buttons);
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: Qt mouse, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), b=" << buttons;
+#endif
+ }
+
+ // get size of screen which contains window
+ QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(w);
+ QSizeF screenSize = platformScreen->physicalSize();
+
+ // update cached position of current touch point
+ m_touchPoints[touchId].normalPosition = QPointF( static_cast<qreal>(pos[0]) / screenSize.width(), static_cast<qreal>(pos[1]) / screenSize.height() );
+ m_touchPoints[touchId].area = QRectF( pos[0], pos[1], 0.0, 0.0 );
+
+ // determine event type and update state of current touch point
+ QEvent::Type type = QEvent::None;
+ switch (qnxType) {
+ case SCREEN_EVENT_MTOUCH_TOUCH:
+ m_touchPoints[touchId].state = Qt::TouchPointPressed;
+ type = QEvent::TouchBegin;
+ break;
+ case SCREEN_EVENT_MTOUCH_MOVE:
+ m_touchPoints[touchId].state = Qt::TouchPointMoved;
+ type = QEvent::TouchUpdate;
+ break;
+ case SCREEN_EVENT_MTOUCH_RELEASE:
+ m_touchPoints[touchId].state = Qt::TouchPointReleased;
+ type = QEvent::TouchEnd;
+ break;
+ }
+
+ // build list of active touch points
+ QList<QWindowSystemInterface::TouchPoint> pointList;
+ for (int i = 0; i < MaximumTouchPoints; i++) {
+ if (i == touchId) {
+ // current touch point is always active
+ pointList.append(m_touchPoints[i]);
+ } else if (m_touchPoints[i].state != Qt::TouchPointReleased) {
+ // finger is down but did not move
+ m_touchPoints[i].state = Qt::TouchPointStationary;
+ pointList.append(m_touchPoints[i]);
+ }
+ }
+
+ // inject event into Qt
+ QWindowSystemInterface::handleTouchEvent(w, m_touchDevice, pointList);
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: Qt touch, w=" << w << ", p=(" << pos[0] << "," << pos[1] << "), t=" << type;
+#endif
+ }
+ }
+}
+
+void QBBEventThread::handleCloseEvent(screen_event_t event)
+{
+ // Query the window that was closed
+ void *handle;
+ int result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle);
+ if (result != 0) {
+ qFatal("QBB: failed to query event window, errno=%d", errno);
+ }
+ screen_window_t qnxWindow = static_cast<screen_window_t>(handle);
+
+ // Map window handle to top-level QWindow
+ QWindow *w = QBBIntegration::window(qnxWindow);
+ if (w != 0) {
+ QWindowSystemInterface::handleCloseEvent(w);
+ }
+}
+
diff --git a/src/plugins/platforms/blackberry/qbbeventthread.h b/src/plugins/platforms/blackberry/qbbeventthread.h
new file mode 100644
index 0000000000..afa738830c
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbeventthread.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBBEVENTTHREAD_H
+#define QBBEVENTTHREAD_H
+
+#include <QtCore/QThread>
+
+#include <QtGui/QPlatformScreen>
+#include <QtGui/QWindowSystemInterface>
+
+#include <screen/screen.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBBEventThread : public QThread
+{
+public:
+ QBBEventThread(screen_context_t context, QPlatformScreen& screen);
+ virtual ~QBBEventThread();
+
+ static void injectKeyboardEvent(int flags, int sym, int mod, int scan, int cap);
+
+protected:
+ virtual void run();
+
+private:
+ enum {
+ MaximumTouchPoints = 10
+ };
+
+ void shutdown();
+ void dispatchEvent(screen_event_t event);
+ void handleKeyboardEvent(screen_event_t event);
+ void handlePointerEvent(screen_event_t event);
+ void handleTouchEvent(screen_event_t event, int type);
+ void handleCloseEvent(screen_event_t event);
+
+ screen_context_t m_screenContext;
+ QPlatformScreen& m_platformScreen;
+ bool m_quit;
+ QPoint m_lastGlobalMousePoint;
+ QPoint m_lastLocalMousePoint;
+ Qt::MouseButtons m_lastButtonState;
+ screen_window_t m_lastMouseWindow;
+ QTouchDevice *m_touchDevice;
+ QWindowSystemInterface::TouchPoint m_touchPoints[MaximumTouchPoints];
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBEVENTTHREAD_H
diff --git a/src/plugins/platforms/blackberry/qbbglbackingstore.cpp b/src/plugins/platforms/blackberry/qbbglbackingstore.cpp
new file mode 100644
index 0000000000..91b07770e1
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbglbackingstore.cpp
@@ -0,0 +1,189 @@
+/***************************************************************************
+**
+** 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 "qbbglbackingstore.h"
+#include "qbbglcontext.h"
+#include "qbbwindow.h"
+#include "qbbscreen.h"
+
+#include <QtGui/qwindow.h>
+
+#include <QtOpenGL/private/qgl_p.h>
+#include <QtOpenGL/QGLContext>
+
+#include <QtCore/QDebug>
+
+#include <errno.h>
+
+QT_BEGIN_NAMESPACE
+
+QBBGLPaintDevice::QBBGLPaintDevice(QWindow *window)
+ : QGLPaintDevice(),
+ m_window(0),
+ m_glContext(0)
+{
+ m_window = static_cast<QBBWindow*>(window->handle());
+
+ // Extract the QPlatformOpenGLContext from the window
+ QPlatformOpenGLContext *platformOpenGLContext = m_window->platformOpenGLContext();
+
+ // Convert this to a QGLContext
+ m_glContext = QGLContext::fromOpenGLContext(platformOpenGLContext->context());
+}
+
+QBBGLPaintDevice::~QBBGLPaintDevice()
+{
+ // Cleanup GL context
+ delete m_glContext;
+}
+
+QPaintEngine *QBBGLPaintDevice::paintEngine() const
+{
+ // Select a paint engine based on configued OpenGL version
+ return qt_qgl_paint_engine();
+}
+
+QSize QBBGLPaintDevice::size() const
+{
+ // Get size of EGL surface
+ return m_window->geometry().size();
+}
+
+
+QBBGLBackingStore::QBBGLBackingStore(QWindow *window)
+ : QPlatformBackingStore(window),
+ m_openGLContext(0),
+ m_paintDevice(0),
+ m_requestedSize(),
+ m_size()
+{
+#if defined(QBBGLBACKINGSTORE_DEBUG)
+ qDebug() << "QBBGLBackingStore::QBBGLBackingStore - w=" << window;
+#endif
+
+ // Create an OpenGL paint device which in turn creates a QGLContext for us
+ m_paintDevice = new QBBGLPaintDevice(window);
+ m_openGLContext = m_paintDevice->context()->contextHandle();
+}
+
+QBBGLBackingStore::~QBBGLBackingStore()
+{
+#if defined(QBBGLBACKINGSTORE_DEBUG)
+ qDebug() << "QBBGLBackingStore::~QBBGLBackingStore - w=" << window();
+#endif
+
+ // cleanup OpenGL paint device
+ delete m_paintDevice;
+}
+
+void QBBGLBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
+{
+ Q_UNUSED(region);
+ Q_UNUSED(offset);
+
+#if defined(QBBGLBACKINGSTORE_DEBUG)
+ qDebug() << "QBBGLBackingStore::flush - w=" << window;
+#endif
+
+ // update the display with newly rendered content
+ m_openGLContext->swapBuffers(window);
+}
+
+void QBBGLBackingStore::resize(const QSize &size, const QRegion &staticContents)
+{
+ Q_UNUSED(staticContents);
+#if defined(QBBGLBACKINGSTORE_DEBUG)
+ qDebug() << "QBBGLBackingStore::resize - w=" << window() << ", s=" << size;
+#endif
+ // NOTE: defer resizing window buffers until next paint as
+ // resize() can be called multiple times before a paint occurs
+ m_requestedSize = size;
+}
+
+void QBBGLBackingStore::beginPaint(const QRegion &region)
+{
+ Q_UNUSED(region);
+
+#if defined(QBBGLBACKINGSTORE_DEBUG)
+ qDebug() << "QBBGLBackingStore::beginPaint - w=" << window();
+#endif
+
+ // resize EGL surface if window surface resized
+ if (m_size != m_requestedSize) {
+ resizeSurface(m_requestedSize);
+ }
+}
+
+void QBBGLBackingStore::endPaint(const QRegion &region)
+{
+ Q_UNUSED(region);
+#if defined(QBBGLBACKINGSTORE_DEBUG)
+ qDebug() << "QBBGLBackingStore::endPaint - w=" << window();
+#endif
+}
+
+void QBBGLBackingStore::resizeSurface(const QSize &size)
+{
+ // need to destroy surface so make sure its not current
+ bool restoreCurrent = false;
+ QBBGLContext *platformContext = static_cast<QBBGLContext *>(m_openGLContext->handle());
+ if (platformContext->isCurrent()) {
+ m_openGLContext->doneCurrent();
+ restoreCurrent = true;
+ }
+
+ // destroy old EGL surface
+ platformContext->destroySurface();
+
+ // resize window's buffers
+ static_cast<QBBWindow*>(window()->handle())->setBufferSize(size);
+
+ // re-create EGL surface with new size
+ m_size = size;
+ platformContext->createSurface(window()->handle());
+
+ // make context current again
+ if (restoreCurrent) {
+ m_openGLContext->makeCurrent(window());
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/blackberry/qbbglbackingstore.h b/src/plugins/platforms/blackberry/qbbglbackingstore.h
new file mode 100644
index 0000000000..5455c5767c
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbglbackingstore.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBBGLBACKINGSTORE_H
+#define QBBGLBACKINGSTORE_H
+
+#include <QtGui/qplatformbackingstore_qpa.h>
+#include <QtOpenGL/private/qglpaintdevice_p.h>
+
+#include <screen/screen.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGLContext;
+class QBBGLContext;
+class QBBScreen;
+class QBBWindow;
+
+class QBBGLPaintDevice : public QGLPaintDevice
+{
+public:
+ QBBGLPaintDevice(QWindow *window);
+ virtual ~QBBGLPaintDevice();
+
+ virtual QPaintEngine *paintEngine() const;
+ virtual QSize size() const;
+ virtual QGLContext *context() const { return m_glContext; }
+
+private:
+ QBBWindow *m_window;
+ QGLContext *m_glContext;
+};
+
+class QBBGLBackingStore : public QPlatformBackingStore
+{
+public:
+ QBBGLBackingStore(QWindow *window);
+ virtual ~QBBGLBackingStore();
+
+ virtual QPaintDevice *paintDevice() { return m_paintDevice; }
+ virtual void flush(QWindow *window, const QRegion &region, const QPoint &offset);
+ virtual void resize(const QSize &size, const QRegion &staticContents);
+ virtual void beginPaint(const QRegion &region);
+ virtual void endPaint(const QRegion &region);
+
+ void resizeSurface(const QSize &size);
+
+private:
+ QOpenGLContext *m_openGLContext;
+ QBBGLPaintDevice *m_paintDevice;
+ QSize m_requestedSize;
+ QSize m_size;
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBGLBACKINGSTORE_H
diff --git a/src/plugins/platforms/blackberry/qbbglcontext.cpp b/src/plugins/platforms/blackberry/qbbglcontext.cpp
new file mode 100644
index 0000000000..fb74fdb5d2
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbglcontext.cpp
@@ -0,0 +1,356 @@
+/***************************************************************************
+**
+** 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 "qbbglcontext.h"
+#include "qbbrootwindow.h"
+#include "qbbscreen.h"
+#include "qbbwindow.h"
+
+#include "private/qeglconvenience_p.h"
+
+#include <QtCore/QDebug>
+#include <QtGui/QOpenGLContext>
+
+QT_BEGIN_NAMESPACE
+
+EGLDisplay QBBGLContext::ms_eglDisplay = EGL_NO_DISPLAY;
+
+static EGLenum checkEGLError(const char *msg)
+{
+ static const char *errmsg[] =
+ {
+ "EGL function succeeded",
+ "EGL is not initialized, or could not be initialized, for the specified display",
+ "EGL cannot access a requested resource",
+ "EGL failed to allocate resources for the requested operation",
+ "EGL fail to access an unrecognized attribute or attribute value was passed in an attribute list",
+ "EGLConfig argument does not name a valid EGLConfig",
+ "EGLContext argument does not name a valid EGLContext",
+ "EGL current surface of the calling thread is no longer valid",
+ "EGLDisplay argument does not name a valid EGLDisplay",
+ "EGL arguments are inconsistent",
+ "EGLNativePixmapType argument does not refer to a valid native pixmap",
+ "EGLNativeWindowType argument does not refer to a valid native window",
+ "EGL one or more argument values are invalid",
+ "EGLSurface argument does not name a valid surface configured for rendering",
+ "EGL power management event has occurred",
+ };
+ EGLenum error = eglGetError();
+ fprintf(stderr, "%s: %s\n", msg, errmsg[error - EGL_SUCCESS]);
+ return error;
+}
+
+QBBGLContext::QBBGLContext(QOpenGLContext *glContext)
+ : QPlatformOpenGLContext(),
+ m_glContext(glContext),
+ m_eglSurface(EGL_NO_SURFACE)
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ QSurfaceFormat format = m_glContext->format();
+
+ // Set current rendering API
+ EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
+ if (eglResult != EGL_TRUE) {
+ qFatal("QBB: failed to set EGL API, err=%d", eglGetError());
+ }
+
+ // Get colour channel sizes from window format
+ int alphaSize = format.alphaBufferSize();
+ int redSize = format.redBufferSize();
+ int greenSize = format.greenBufferSize();
+ int blueSize = format.blueBufferSize();
+
+ // Check if all channels are don't care
+ if (alphaSize == -1 && redSize == -1 && greenSize == -1 && blueSize == -1) {
+ // Set colour channels based on depth of window's screen
+ QBBScreen *screen = static_cast<QBBScreen*>(QBBScreen::screens().first());
+ int depth = screen->depth();
+ if (depth == 32) {
+ // SCREEN_FORMAT_RGBA8888
+ alphaSize = 8;
+ redSize = 8;
+ greenSize = 8;
+ blueSize = 8;
+ } else {
+ // SCREEN_FORMAT_RGB565
+ alphaSize = 0;
+ redSize = 5;
+ greenSize = 6;
+ blueSize = 5;
+ }
+ } else {
+ // Choose best match based on supported pixel formats
+ if (alphaSize <= 0 && redSize <= 5 && greenSize <= 6 && blueSize <= 5) {
+ // SCREEN_FORMAT_RGB565
+ alphaSize = 0;
+ redSize = 5;
+ greenSize = 6;
+ blueSize = 5;
+ } else {
+ // SCREEN_FORMAT_RGBA8888
+ alphaSize = 8;
+ redSize = 8;
+ greenSize = 8;
+ blueSize = 8;
+ }
+ }
+
+ // Update colour channel sizes in window format
+ format.setAlphaBufferSize(alphaSize);
+ format.setRedBufferSize(redSize);
+ format.setGreenBufferSize(greenSize);
+ format.setBlueBufferSize(blueSize);
+ format.setSamples(2);
+
+ // Select EGL config based on requested window format
+ m_eglConfig = q_configFromGLFormat(ms_eglDisplay, format);
+ if (m_eglConfig == 0) {
+ qFatal("QBB: failed to find EGL config");
+ }
+
+ m_eglContext = eglCreateContext(ms_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, contextAttrs());
+ if (m_eglContext == EGL_NO_CONTEXT) {
+ checkEGLError("eglCreateContext");
+ qFatal("QBB: failed to create EGL context, err=%d", eglGetError());
+ }
+
+ // Query/cache window format of selected EGL config
+ m_windowFormat = q_glFormatFromConfig(ms_eglDisplay, m_eglConfig);
+}
+
+QBBGLContext::~QBBGLContext()
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ // Cleanup EGL context if it exists
+ if (m_eglContext != EGL_NO_CONTEXT) {
+ eglDestroyContext(ms_eglDisplay, m_eglContext);
+ }
+
+ // Cleanup EGL surface if it exists
+ destroySurface();
+}
+
+void QBBGLContext::initialize()
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ // Initialize connection to EGL
+ ms_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (ms_eglDisplay == EGL_NO_DISPLAY) {
+ checkEGLError("eglGetDisplay");
+ qFatal("QBB: failed to obtain EGL display");
+ }
+
+ EGLBoolean eglResult = eglInitialize(ms_eglDisplay, 0, 0);
+ if (eglResult != EGL_TRUE) {
+ checkEGLError("eglInitialize");
+ qFatal("QBB: failed to initialize EGL display, err=%d", eglGetError());
+ }
+}
+
+void QBBGLContext::shutdown()
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ // Close connection to EGL
+ eglTerminate(ms_eglDisplay);
+}
+
+bool QBBGLContext::makeCurrent(QPlatformSurface *surface)
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ // Set current rendering API
+ EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
+ if (eglResult != EGL_TRUE) {
+ qFatal("QBB: failed to set EGL API, err=%d", eglGetError());
+ }
+
+ if (m_eglSurface == EGL_NO_SURFACE)
+ createSurface(surface);
+
+ eglResult = eglMakeCurrent(ms_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
+ if (eglResult != EGL_TRUE) {
+ checkEGLError("eglMakeCurrent");
+ qFatal("QBB: failed to set current EGL context, err=%d", eglGetError());
+ }
+ return (eglResult == EGL_TRUE);
+}
+
+void QBBGLContext::doneCurrent()
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ // set current rendering API
+ EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
+ if (eglResult != EGL_TRUE) {
+ qFatal("QBB: failed to set EGL API, err=%d", eglGetError());
+ }
+
+ // clear curent EGL context and unbind EGL surface
+ eglResult = eglMakeCurrent(ms_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ if (eglResult != EGL_TRUE) {
+ qFatal("QBB: failed to clear current EGL context, err=%d", eglGetError());
+ }
+}
+
+void QBBGLContext::swapBuffers(QPlatformSurface *surface)
+{
+ Q_UNUSED(surface);
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ // Set current rendering API
+ EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
+ if (eglResult != EGL_TRUE) {
+ qFatal("QBB: failed to set EGL API, err=%d", eglGetError());
+ }
+
+ // Post EGL surface to window
+ eglResult = eglSwapBuffers(ms_eglDisplay, m_eglSurface);
+ if (eglResult != EGL_TRUE) {
+ qFatal("QBB: failed to swap EGL buffers, err=%d", eglGetError());
+ }
+}
+
+QFunctionPointer QBBGLContext::getProcAddress(const QByteArray &procName)
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ // Set current rendering API
+ EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
+ if (eglResult != EGL_TRUE) {
+ qFatal("QBB: failed to set EGL API, err=%d", eglGetError());
+ }
+
+ // Lookup EGL extension function pointer
+ return static_cast<QFunctionPointer>(eglGetProcAddress(procName.constData()));
+}
+
+EGLint *QBBGLContext::contextAttrs()
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ // Choose EGL settings based on OpenGL version
+#if defined(QT_OPENGL_ES_2)
+ static EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+ return attrs;
+#else
+ return 0;
+#endif
+}
+
+bool QBBGLContext::isCurrent() const
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ return (eglGetCurrentContext() == m_eglContext);
+}
+
+void QBBGLContext::createSurface(QPlatformSurface *surface)
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ // Get a pointer to the corresponding platform window
+ QBBWindow *platformWindow = dynamic_cast<QBBWindow*>(surface);
+ if (!platformWindow) {
+ qFatal("QBB: unable to create EGLSurface without a QBBWindow");
+ }
+
+ // If the platform window does not yet have any buffers, we create
+ // a temporary set of buffers with a size of 1x1 pixels. This will
+ // suffice until such time as the platform window has obtained
+ // buffers of the proper size
+ if (!platformWindow->hasBuffers()) {
+ platformWindow->setPlatformOpenGLContext(this);
+ m_surfaceSize = platformWindow->geometry().size();
+ platformWindow->setBufferSize(m_surfaceSize);
+ }
+
+ // Obtain the native handle for our window
+ screen_window_t handle = platformWindow->nativeHandle();
+
+ const EGLint eglSurfaceAttrs[] =
+ {
+ EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
+ EGL_NONE
+ };
+
+ // Create EGL surface
+ m_eglSurface = eglCreateWindowSurface(ms_eglDisplay, m_eglConfig, (EGLNativeWindowType) handle, eglSurfaceAttrs);
+ if (m_eglSurface == EGL_NO_SURFACE) {
+ checkEGLError("eglCreateWindowSurface");
+ qFatal("QBB: failed to create EGL surface, err=%d", eglGetError());
+ }
+}
+
+void QBBGLContext::destroySurface()
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ // Destroy EGL surface if it exists
+ if (m_eglSurface != EGL_NO_SURFACE) {
+ EGLBoolean eglResult = eglDestroySurface(ms_eglDisplay, m_eglSurface);
+ if (eglResult != EGL_TRUE) {
+ qFatal("QBB: failed to destroy EGL surface, err=%d", eglGetError());
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/blackberry/qbbglcontext.h b/src/plugins/platforms/blackberry/qbbglcontext.h
new file mode 100644
index 0000000000..8ea1df5f40
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbglcontext.h
@@ -0,0 +1,93 @@
+/***************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBBGLCONTEXT_H
+#define QBBGLCONTEXT_H
+
+#include <QtGui/QPlatformOpenGLContext>
+#include <QtGui/QSurfaceFormat>
+#include <QtCore/QSize>
+
+#include <EGL/egl.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBBWindow;
+
+class QBBGLContext : public QPlatformOpenGLContext
+{
+public:
+ QBBGLContext(QOpenGLContext *glContext);
+ virtual ~QBBGLContext();
+
+ static void initialize();
+ static void shutdown();
+
+ virtual bool makeCurrent(QPlatformSurface *surface);
+ virtual void doneCurrent();
+ virtual void swapBuffers(QPlatformSurface *surface);
+ virtual QFunctionPointer getProcAddress(const QByteArray &procName);
+
+ virtual QSurfaceFormat format() const { return m_windowFormat; }
+
+ bool isCurrent() const;
+
+ void createSurface(QPlatformSurface *surface);
+ void destroySurface();
+
+private:
+ /** \todo Should this be non-static so we can use additional displays? */
+ static EGLDisplay ms_eglDisplay;
+
+ QSurfaceFormat m_windowFormat;
+ QOpenGLContext *m_glContext;
+
+ EGLConfig m_eglConfig;
+ EGLContext m_eglContext;
+ EGLSurface m_eglSurface;
+ QSize m_surfaceSize;
+
+ static EGLint *contextAttrs();
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBGLCONTEXT_H
diff --git a/src/plugins/platforms/blackberry/qbbinputcontext_imf.cpp b/src/plugins/platforms/blackberry/qbbinputcontext_imf.cpp
new file mode 100644
index 0000000000..fab3d3f151
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbinputcontext_imf.cpp
@@ -0,0 +1,1696 @@
+/***************************************************************************
+**
+** 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 "qbbinputcontext_imf.h"
+#include "qbbeventthread.h"
+#include "qbbvirtualkeyboard.h"
+
+#include <QtWidgets/QAbstractSpinBox>
+#include <QtWidgets/QAction>
+
+#include <QtGui/QGuiApplication>
+#include <QtGui/QInputMethodEvent>
+#include <QtGui/QTextCharFormat>
+
+#include <QtCore/QDebug>
+#include <QtCore/QMutex>
+#include <QtCore/QVariant>
+#include <QtCore/QVariantHash>
+#include <QtCore/QWaitCondition>
+
+#include <dlfcn.h>
+#include "imf/imf_client.h"
+#include "imf/input_control.h"
+#include <process.h>
+#include <sys/keycodes.h>
+
+/** TODO:
+ Support inputMethodHints to restrict input (needs additional features in IMF).
+*/
+
+#define STRX(x) #x
+#define STR(x) STRX(x)
+
+// Someone tell me why input_control methods are in this namespace, but the rest is not.
+using namespace InputMethodSystem;
+
+#define qs(x) QString::fromLatin1(x)
+#define iarg(name) event->mArgs[qs(#name)] = QVariant::fromValue(name)
+#define parg(name) event->mArgs[qs(#name)] = QVariant::fromValue((void*)name)
+namespace
+{
+
+spannable_string_t *toSpannableString(const QString &text);
+static const input_session_t *sInputSession = 0;
+bool isSessionOkay(input_session_t *ic)
+{
+ return ic !=0 && sInputSession != 0 && ic->component_id == sInputSession->component_id;
+}
+
+enum ImfEventType
+{
+ ImfBeginBatchEdit,
+ ImfClearMetaKeyStates,
+ ImfCommitText,
+ ImfDeleteSurroundingText,
+ ImfEndBatchEdit,
+ ImfFinishComposingText,
+ ImfGetCursorCapsMode,
+ ImfGetCursorPosition,
+ ImfGetExtractedText,
+ ImfGetSelectedText,
+ ImfGetTextAfterCursor,
+ ImfGetTextBeforeCursor,
+ ImfPerformEditorAction,
+ ImfReportFullscreenMode,
+ ImfSendEvent,
+ ImfSendAsyncEvent,
+ ImfSetComposingRegion,
+ ImfSetComposingText,
+ ImfSetSelection
+};
+
+// We use this class as a round about way to support a posting synchronous event into
+// Qt's main thread from the IMF thread.
+class ImfEventResult
+{
+public:
+ ImfEventResult()
+ {
+ m_mutex.lock();
+ }
+
+ ~ImfEventResult()
+ {
+ m_mutex.unlock();
+ }
+
+ void wait()
+ {
+ m_wait.wait(&m_mutex);
+ }
+
+ void signal()
+ {
+ m_wait.wakeAll();
+ }
+
+ void setResult(const QVariant& result)
+ {
+ m_mutex.lock();
+ m_retVal = result;
+ signal();
+ m_mutex.unlock();
+ }
+
+ QVariant result()
+ {
+ return m_retVal;
+ }
+
+private:
+ QVariant m_retVal;
+ QMutex m_mutex;
+ QWaitCondition m_wait;
+};
+
+class ImfEvent : public QEvent
+{
+ public:
+ ImfEvent(input_session_t *session, ImfEventType type, ImfEventResult *result) :
+ QEvent((QEvent::Type)sUserEventType),
+ m_session(session),
+ m_imfType(type),
+ m_result(result)
+ {
+ }
+ ~ImfEvent() { }
+
+ input_session_t *m_session;
+ ImfEventType m_imfType;
+ QVariantHash m_args;
+ ImfEventResult *m_result;
+
+ static int sUserEventType;
+};
+int ImfEvent::sUserEventType = QEvent::registerEventType();
+
+static int32_t imfBeginBatchEdit(input_session_t *ic)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ ImfEventResult result;
+ ImfEvent *event = new ImfEvent(ic, ImfBeginBatchEdit, &result);
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ result.wait();
+ int32_t ret = result.result().value<int32_t>();
+
+ return ret;
+}
+
+static int32_t imfClearMetaKeyStates(input_session_t *ic, int32_t states)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ ImfEventResult result;
+ ImfEvent *event = new ImfEvent(ic, ImfClearMetaKeyStates, &result);
+ iarg(states);
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ result.wait();
+ int32_t ret = result.result().value<int32_t>();
+
+ return ret;
+}
+
+static int32_t imfCommitText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ ImfEventResult result;
+ ImfEvent *event = new ImfEvent(ic, ImfCommitText, &result);
+ parg(text);
+ iarg(new_cursor_position);
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ result.wait();
+ int32_t ret = result.result().value<int32_t>();
+
+ return ret;
+}
+
+static int32_t imfDeleteSurroundingText(input_session_t *ic, int32_t left_length, int32_t right_length)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ ImfEventResult result;
+ ImfEvent *event = new ImfEvent(ic, ImfDeleteSurroundingText, &result);
+ iarg(left_length);
+ iarg(right_length);
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ result.wait();
+ int32_t ret = result.result().value<int32_t>();
+
+ return ret;
+}
+
+static int32_t imfEndBatchEdit(input_session_t *ic)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ ImfEventResult result;
+ ImfEvent *event = new ImfEvent(ic, ImfEndBatchEdit, &result);
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ result.wait();
+ int32_t ret = result.result().value<int32_t>();
+
+ return ret;
+}
+
+static int32_t imfFinishComposingText(input_session_t *ic)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ ImfEventResult result;
+ ImfEvent *event = new ImfEvent(ic, ImfFinishComposingText, &result);
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ result.wait();
+ int32_t ret = result.result().value<int32_t>();
+
+ return ret;
+}
+
+static int32_t imfGetCursorCapsMode(input_session_t *ic, int32_t req_modes)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ ImfEventResult result;
+ ImfEvent *event = new ImfEvent(ic, ImfGetCursorCapsMode, &result);
+ iarg(req_modes);
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ int32_t ret = result.result().value<int32_t>();
+ return ret;
+}
+
+static int32_t imfGetCursorPosition(input_session_t *ic)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ ImfEventResult result;
+ ImfEvent *event = new ImfEvent(ic, ImfGetCursorPosition, &result);
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ result.wait();
+ int32_t ret = result.result().value<int32_t>();
+
+ return ret;
+}
+
+static extracted_text_t *imfGetExtractedText(input_session_t *ic, extracted_text_request_t *request, int32_t flags)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic)) {
+ extracted_text_t *et = (extracted_text_t *)calloc(sizeof(extracted_text_t),1);
+ et->text = (spannable_string_t *)calloc(sizeof(spannable_string_t),1);
+ return et;
+ }
+
+ ImfEventResult result;
+ ImfEvent *event = new ImfEvent(ic, ImfGetExtractedText, &result);
+ parg(request);
+ iarg(flags);
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ result.wait();
+ return result.result().value<extracted_text_t *>();
+}
+
+static spannable_string_t *imfGetSelectedText(input_session_t *ic, int32_t flags)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return toSpannableString("");
+
+ ImfEventResult result;
+ ImfEvent *event = new ImfEvent(ic, ImfGetSelectedText, &result);
+ iarg(flags);
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ result.wait();
+ return result.result().value<extracted_text_t *>();
+}
+
+static spannable_string_t *imfGetTextAfterCursor(input_session_t *ic, int32_t n, int32_t flags)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return toSpannableString("");
+
+ ImfEventResult result;
+ ImfEvent *event = new ImfEvent(ic, ImfGetTextAfterCursor, &result);
+ iarg(n);
+ iarg(flags);
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ result.wait();
+ return result.result().value<extracted_text_t *>();
+}
+
+static spannable_string_t *imfGetTextBeforeCursor(input_session_t *ic, int32_t n, int32_t flags)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return toSpannableString("");
+
+ ImfEventResult result;
+ ImfEvent *event = new ImfEvent(ic, ImfGetTextBeforeCursor, &result);
+ iarg(n);
+ iarg(flags);
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ result.wait();
+ return result.result().value<extracted_text_t *>();
+}
+
+static int32_t imfPerformEditorAction(input_session_t *ic, int32_t editor_action)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ ImfEventResult result;
+ ImfEvent *event = new ImfEvent(ic, ImfPerformEditorAction, &result);
+ iarg(editor_action);
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ result.wait();
+ int32_t ret = result.result().value<int32_t>();
+ return ret;
+}
+
+static int32_t imfReportFullscreenMode(input_session_t *ic, int32_t enabled)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ ImfEventResult result;
+ ImfEvent *event = new ImfEvent(ic, ImfReportFullscreenMode, &result);
+ iarg(enabled);
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ result.wait();
+ int32_t ret = result.result().value<int32_t>();
+ return ret;
+}
+
+static int32_t imfSendEvent(input_session_t *ic, event_t *event)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ ImfEvent *imfEvent = new ImfEvent(ic, ImfSendEvent, 0);
+ imfEvent->m_args[qs("event")] = QVariant::fromValue(static_cast<void *>(event));
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), imfEvent);
+
+ return 0;
+}
+
+static int32_t imfSendAsyncEvent(input_session_t *ic, event_t *event)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ ImfEvent *imfEvent = new ImfEvent(ic, ImfSendAsyncEvent, 0);
+ imfEvent->m_args[qs("event")] = QVariant::fromValue(static_cast<void *>(event));
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), imfEvent);
+
+ return 0;
+}
+
+static int32_t imfSetComposingRegion(input_session_t *ic, int32_t start, int32_t end)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ ImfEventResult result;
+ ImfEvent *event = new ImfEvent(ic, ImfSetComposingRegion, &result);
+ iarg(start);
+ iarg(end);
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ result.wait();
+ int32_t ret = result.result().value<int32_t>();
+ return ret;
+}
+
+static int32_t imfSetComposingText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ ImfEventResult result;
+ ImfEvent *event = new ImfEvent(ic, ImfSetComposingText, &result);
+ parg(text);
+ iarg(new_cursor_position);
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ result.wait();
+ int32_t ret = result.result().value<int32_t>();
+ return ret;
+}
+
+static int32_t imfSetSelection(input_session_t *ic, int32_t start, int32_t end)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ ImfEventResult result;
+ ImfEvent *event = new ImfEvent(ic, ImfSetSelection, &result);
+ iarg(start);
+ iarg(end);
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ result.wait();
+ int32_t ret = result.result().value<int32_t>();
+ return ret;
+}
+
+static connection_interface_t ic_funcs = {
+ imfBeginBatchEdit,
+ imfClearMetaKeyStates,
+ imfCommitText,
+ imfDeleteSurroundingText,
+ imfEndBatchEdit,
+ imfFinishComposingText,
+ imfGetCursorCapsMode,
+ imfGetCursorPosition,
+ imfGetExtractedText,
+ imfGetSelectedText,
+ imfGetTextAfterCursor,
+ imfGetTextBeforeCursor,
+ imfPerformEditorAction,
+ imfReportFullscreenMode,
+ NULL, //ic_send_key_event
+ imfSendEvent,
+ imfSendAsyncEvent,
+ imfSetComposingRegion,
+ imfSetComposingText,
+ imfSetSelection,
+ NULL, //ic_set_candidates,
+};
+
+static void
+initEvent(event_t *pEvent, const input_session_t *pSession, EventType eventType, int eventId)
+{
+ static int s_transactionId;
+
+ // Make sure structure is squeaky clean since it's not clear just what is significant.
+ memset(pEvent, 0, sizeof(event_t));
+ pEvent->event_type = eventType;
+ pEvent->event_id = eventId;
+ pEvent->pid = getpid();
+ pEvent->component_id = pSession->component_id;
+ pEvent->transaction_id = ++s_transactionId;
+}
+
+spannable_string_t *toSpannableString(const QString &text)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO << text;
+#endif
+
+ spannable_string_t *pString = reinterpret_cast<spannable_string_t *>(malloc(sizeof(spannable_string_t)));
+ pString->str = (wchar_t *)malloc(sizeof(wchar_t) * text.length() + 1);
+ pString->length = text.length();
+ pString->spans = NULL;
+ pString->spans_count = 0;
+
+ const QChar *pData = text.constData();
+ wchar_t *pDst = pString->str;
+
+ while (!pData->isNull())
+ {
+ *pDst = pData->unicode();
+ pDst++;
+ pData++;
+ }
+ *pDst = 0;
+
+ return pString;
+}
+
+} // namespace
+
+static const input_session_t *(*p_ictrl_open_session)(connection_interface_t *) = 0;
+static void (*p_ictrl_close_session)(input_session_t *) = 0;
+static int32_t (*p_ictrl_dispatch_event)(event_t*) = 0;
+static int32_t (*p_imf_client_init)() = 0;
+static void (*p_imf_client_disconnect)() = 0;
+static int32_t (*p_vkb_init_selection_service)() = 0;
+static int32_t (*p_ictrl_get_num_active_sessions)() = 0;
+static bool s_imfInitFailed = false;
+
+static bool imfAvailable()
+{
+ static bool s_imfDisabled = getenv("DISABLE_IMF") != NULL;
+ static bool s_imfReady = false;
+
+ if ( s_imfInitFailed || s_imfDisabled) {
+ return false;
+ }
+ else if ( s_imfReady ) {
+ return true;
+ }
+
+ if ( p_imf_client_init == NULL ) {
+ void *handle = dlopen("libinput_client.so.1", 0);
+ if ( handle ) {
+ p_imf_client_init = (int32_t (*)()) dlsym(handle, "imf_client_init");
+ p_imf_client_disconnect = (void (*)()) dlsym(handle, "imf_client_disconnect");
+ p_ictrl_open_session = (const input_session_t *(*)(connection_interface_t *))dlsym(handle, "ictrl_open_session");
+ p_ictrl_close_session = (void (*)(input_session_t *))dlsym(handle, "ictrl_close_session");
+ p_ictrl_dispatch_event = (int32_t (*)(event_t *))dlsym(handle, "ictrl_dispatch_event");
+ p_vkb_init_selection_service = (int32_t (*)())dlsym(handle, "vkb_init_selection_service");
+ p_ictrl_get_num_active_sessions = (int32_t (*)())dlsym(handle, "ictrl_get_num_active_sessions");
+ }
+ else
+ {
+ qCritical() << Q_FUNC_INFO << "libinput_client.so.1 is not present - IMF services are disabled.";
+ s_imfDisabled = true;
+ return false;
+ }
+ if ( p_imf_client_init && p_ictrl_open_session && p_ictrl_dispatch_event ) {
+ s_imfReady = true;
+ }
+ else {
+ p_ictrl_open_session = NULL;
+ p_ictrl_dispatch_event = NULL;
+ s_imfDisabled = true;
+ qCritical() << Q_FUNC_INFO << "libinput_client.so.1 did not contain the correct symbols, library mismatch? IMF services are disabled.";
+ return false;
+ }
+ }
+
+ return s_imfReady;
+}
+
+QBBInputContext::QBBInputContext():
+ QPlatformInputContext(),
+ m_lastCaretPos(0),
+ m_isComposing(false),
+ m_inputPanelVisible(false),
+ m_inputPanelLocale(QLocale::c())
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!imfAvailable())
+ return;
+
+ if ( p_imf_client_init() != 0 ) {
+ s_imfInitFailed = true;
+ qCritical("imf_client_init failed - IMF services will be unavailable");
+ }
+
+ QCoreApplication::instance()->installEventFilter(this);
+
+ // p_vkb_init_selection_service();
+
+ QBBVirtualKeyboard &keyboard = QBBVirtualKeyboard::instance();
+ connect(&keyboard, SIGNAL(visibilityChanged(bool)), this, SLOT(keyboardVisibilityChanged(bool)));
+ connect(&keyboard, SIGNAL(localeChanged(QLocale)), this, SLOT(keyboardLocaleChanged(QLocale)));
+ keyboardVisibilityChanged(keyboard.isVisible());
+ keyboardLocaleChanged(keyboard.locale());
+
+ QInputMethod *inputMethod = qApp->inputMethod();
+ connect(inputMethod, SIGNAL(inputItemChanged()), this, SLOT(inputItemChanged()));
+
+}
+
+QBBInputContext::~QBBInputContext()
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!imfAvailable())
+ return;
+
+ QCoreApplication::instance()->removeEventFilter(this);
+ p_imf_client_disconnect();
+}
+
+#define getarg(type, name) type name = imfEvent->mArgs[qs(#name)].value<type>()
+#define getparg(type, name) type name = (type)(imfEvent->mArgs[qs(#name)].value<void*>())
+
+bool QBBInputContext::isValid() const
+{
+ return imfAvailable();
+}
+
+bool QBBInputContext::eventFilter(QObject *obj, QEvent *event)
+{
+ if (event->type() == ImfEvent::sUserEventType) {
+ // Forward the event to our real handler.
+ ImfEvent *imfEvent = static_cast<ImfEvent *>(event);
+ switch (imfEvent->m_imfType) {
+ case ImfBeginBatchEdit: {
+ int32_t ret = onBeginBatchEdit(imfEvent->m_session);
+ imfEvent->m_result->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfClearMetaKeyStates: {
+ getarg(int32_t, states);
+ int32_t ret = onClearMetaKeyStates(imfEvent->m_session, states);
+ imfEvent->m_result->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfCommitText: {
+ getparg(spannable_string_t*, text);
+ getarg(int32_t, new_cursor_position);
+ int32_t ret = onCommitText(imfEvent->m_session, text, new_cursor_position);
+ imfEvent->m_result->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfDeleteSurroundingText: {
+ getarg(int32_t, left_length);
+ getarg(int32_t, right_length);
+ int32_t ret = onDeleteSurroundingText(imfEvent->m_session, left_length, right_length);
+ imfEvent->m_result->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfEndBatchEdit: {
+ int32_t ret = onEndBatchEdit(imfEvent->m_session);
+ imfEvent->m_result->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfFinishComposingText: {
+ int32_t ret = onFinishComposingText(imfEvent->m_session);
+ imfEvent->m_result->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfGetCursorCapsMode: {
+ getarg(int32_t, req_modes);
+ int32_t ret = onGetCursorCapsMode(imfEvent->m_session, req_modes);
+ imfEvent->m_result->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfGetCursorPosition: {
+ int32_t ret = onGetCursorPosition(imfEvent->m_session);
+ imfEvent->m_result->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfGetExtractedText: {
+ getparg(extracted_text_request_t*, request);
+ getarg(int32_t, flags);
+ extracted_text_t *ret = onGetExtractedText(imfEvent->m_session, request, flags);
+ imfEvent->m_result->setResult(QVariant::fromValue(static_cast<void *>(ret)));
+ break;
+ }
+
+ case ImfGetSelectedText: {
+ getarg(int32_t, flags);
+ spannable_string_t *ret = onGetSelectedText(imfEvent->m_session, flags);
+ imfEvent->m_result->setResult(QVariant::fromValue(static_cast<void *>(ret)));
+ break;
+ }
+
+ case ImfGetTextAfterCursor: {
+ getarg(int32_t, n);
+ getarg(int32_t, flags);
+ spannable_string_t *ret = onGetTextAfterCursor(imfEvent->m_session, n, flags);
+ imfEvent->m_result->setResult(QVariant::fromValue(static_cast<void *>(ret)));
+ break;
+ }
+
+ case ImfGetTextBeforeCursor: {
+ getarg(int32_t, n);
+ getarg(int32_t, flags);
+ spannable_string_t *ret = onGetTextBeforeCursor(imfEvent->m_session, n, flags);
+ imfEvent->m_result->setResult(QVariant::fromValue((void*)ret));
+ break;
+ }
+
+ case ImfPerformEditorAction: {
+ getarg(int32_t, editor_action);
+ int32_t ret = onPerformEditorAction(imfEvent->m_session, editor_action);
+ imfEvent->m_result->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfReportFullscreenMode: {
+ getarg(int32_t, enabled);
+ int32_t ret = onReportFullscreenMode(imfEvent->m_session, enabled);
+ imfEvent->m_result->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfSendEvent: {
+ getparg(event_t*, event);
+ onSendEvent(imfEvent->m_session, event);
+ break;
+ }
+
+ case ImfSendAsyncEvent: {
+ getparg(event_t*, event);
+ onSendAsyncEvent(imfEvent->m_session, event);
+ break;
+ }
+
+ case ImfSetComposingRegion: {
+ getarg(int32_t, start);
+ getarg(int32_t, end);
+ int32_t ret = onSetComposingRegion(imfEvent->m_session, start, end);
+ imfEvent->m_result->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfSetComposingText: {
+ getparg(spannable_string_t*, text);
+ getarg(int32_t, new_cursor_position);
+ int32_t ret = onSetComposingText(imfEvent->m_session, text, new_cursor_position);
+ imfEvent->m_result->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfSetSelection: {
+ getarg(int32_t, start);
+ getarg(int32_t, end);
+ int32_t ret = onSetSelection(imfEvent->m_session, start, end);
+ imfEvent->m_result->setResult(QVariant::fromValue(ret));
+ break;
+ }
+ }; //switch
+
+ return true;
+ } else {
+ // standard event processing
+ return QObject::eventFilter(obj, event);
+ }
+}
+
+bool QBBInputContext::filterEvent( const QEvent *event )
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO << event;
+#endif
+ switch (event->type()) {
+ case QEvent::CloseSoftwareInputPanel: {
+ return dispatchCloseSoftwareInputPanel();
+ }
+ case QEvent::RequestSoftwareInputPanel: {
+ return dispatchRequestSoftwareInputPanel();
+ }
+ default:
+ return false;
+ }
+}
+
+void QBBInputContext::reset()
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ endComposition();
+}
+
+void QBBInputContext::update(Qt::InputMethodQueries queries)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ reset();
+
+ QPlatformInputContext::update(queries);
+}
+
+void QBBInputContext::closeSession()
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO
+#endif
+ if (!imfAvailable())
+ return;
+
+ if (sInputSession) {
+ p_ictrl_close_session((input_session_t *)sInputSession);
+ sInputSession = 0;
+ }
+}
+
+void QBBInputContext::openSession()
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO
+#endif
+ if (!imfAvailable())
+ return;
+
+ closeSession();
+ sInputSession = p_ictrl_open_session(&ic_funcs);
+}
+
+bool QBBInputContext::hasSession()
+{
+ return sInputSession != 0;
+}
+
+bool QBBInputContext::hasSelectedText()
+{
+ QInputPanel *panel = qApp->inputPanel();
+ QObject *input = panel->inputItem();
+ if (!input)
+ return false;
+
+ QInputMethodQueryEvent query(Qt::ImCurrentSelection);
+ QCoreApplication::sendEvent(input, &query);
+
+ return !query.value(Qt::ImCurrentSelection).toString().isEmpty();
+}
+
+bool QBBInputContext::dispatchRequestSoftwareInputPanel()
+{
+ QBBVirtualKeyboard::instance().showKeyboard();
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << "QBB: requesting virtual keyboard";
+#endif
+ QInputPanel *panel = qApp->inputPanel();
+ QObject *input = panel->inputItem();
+ if (!imfAvailable() || !input)
+ return true;
+
+ if (!hasSession())
+ openSession();
+
+ // This also means that the caret position has moved
+ QInputMethodQueryEvent query(Qt::ImCursorPosition);
+ QCoreApplication::sendEvent(input, &query);
+ int caretPos = query.value(Qt::ImCursorPosition).toInt();
+ caret_event_t caretEvent;
+ memset(&caretEvent, 0, sizeof(caret_event_t));
+ initEvent(&caretEvent.event, sInputSession, EVENT_CARET, CARET_POS_CHANGED);
+ caretEvent.old_pos = m_lastCaretPos;
+ m_lastCaretPos = caretEvent.new_pos = caretPos;
+ p_ictrl_dispatch_event((event_t *)&caretEvent);
+ return true;
+}
+
+bool QBBInputContext::dispatchCloseSoftwareInputPanel()
+{
+ QBBVirtualKeyboard::instance().hideKeyboard();
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << "QBB: hiding virtual keyboard";
+#endif
+
+ // This also means we are stopping composition, but we should already have done that.
+ return true;
+}
+
+/**
+ * IMF Event Dispatchers.
+ */
+bool QBBInputContext::dispatchFocusEvent(FocusEventId id, int hints)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!sInputSession) {
+ qWarning() << Q_FUNC_INFO << "Attempt to dispatch a focus event with no input session.";
+ return false;
+ }
+
+ if (!imfAvailable())
+ return false;
+
+ // Set the last caret position to 0 since we don't really have one and we don't
+ // want to have the old one.
+ m_lastCaretPos = 0;
+
+ focus_event_t focusEvent;
+ memset(&focusEvent, 0, sizeof(focusEvent));
+ initEvent(&focusEvent.event, sInputSession, EVENT_FOCUS, id);
+ focusEvent.style = DEFAULT_STYLE;
+
+ if (hints && Qt::ImhNoPredictiveText)
+ focusEvent.style |= NO_PREDICTION | NO_AUTO_CORRECTION;
+ if (hints && Qt::ImhNoAutoUppercase)
+ focusEvent.style |= NO_AUTO_TEXT;
+
+ p_ictrl_dispatch_event((event_t *)&focusEvent);
+
+ return true;
+}
+
+bool QBBInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap)
+{
+ if (!imfAvailable())
+ return false;
+
+ int key = (flags & KEY_SYM_VALID) ? sym : cap;
+ bool navKey = false;
+ switch ( key ) {
+ case KEYCODE_RETURN:
+ /* In a single line edit we should end composition because enter might be used by something.
+ endComposition();
+ return false;*/
+ break;
+
+ case KEYCODE_BACKSPACE:
+ case KEYCODE_DELETE:
+ // If there is a selection range, then we want a delete key to operate on that (by
+ // deleting the contents of the select range) rather than operating on the composition
+ // range.
+ if (hasSelectedText())
+ return false;
+ break;
+ case KEYCODE_LEFT:
+ key = NAVIGATE_LEFT;
+ navKey = true;
+ break;
+ case KEYCODE_RIGHT:
+ key = NAVIGATE_RIGHT;
+ navKey = true;
+ break;
+ case KEYCODE_UP:
+ key = NAVIGATE_UP;
+ navKey = true;
+ break;
+ case KEYCODE_DOWN:
+ key = NAVIGATE_DOWN;
+ navKey = true;
+ break;
+ case KEYCODE_CAPS_LOCK:
+ case KEYCODE_LEFT_SHIFT:
+ case KEYCODE_RIGHT_SHIFT:
+ case KEYCODE_LEFT_CTRL:
+ case KEYCODE_RIGHT_CTRL:
+ case KEYCODE_LEFT_ALT:
+ case KEYCODE_RIGHT_ALT:
+ case KEYCODE_MENU:
+ case KEYCODE_LEFT_HYPER:
+ case KEYCODE_RIGHT_HYPER:
+ case KEYCODE_INSERT:
+ case KEYCODE_HOME:
+ case KEYCODE_PG_UP:
+ case KEYCODE_END:
+ case KEYCODE_PG_DOWN:
+ // Don't send these
+ key = 0;
+ break;
+ }
+
+ if ( mod & KEYMOD_CTRL ) {
+ // If CTRL is pressed, just let AIR handle it. But terminate any composition first
+ //endComposition();
+ return false;
+ }
+
+ // Pass the keys we don't know about on through
+ if ( key == 0 )
+ return false;
+
+ // IMF doesn't need key releases so just swallow them.
+ if (!(flags & KEY_DOWN))
+ return true;
+
+ if ( navKey ) {
+ // Even if we're forwarding up events, we can't do this for
+ // navigation keys.
+ if ( flags & KEY_DOWN ) {
+ navigation_event_t navEvent;
+ initEvent(&navEvent.event, sInputSession, EVENT_NAVIGATION, key);
+ navEvent.magnitude = 1;
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO << "dispatch navigation event " << key;
+#endif
+ p_ictrl_dispatch_event(&navEvent.event);
+ }
+ }
+ else {
+ key_event_t keyEvent;
+ initEvent(&keyEvent.event, sInputSession, EVENT_KEY, flags & KEY_DOWN ? IMF_KEY_DOWN : IMF_KEY_UP);
+ keyEvent.key_code = key;
+ keyEvent.character = 0;
+ keyEvent.meta_key_state = 0;
+
+ p_ictrl_dispatch_event(&keyEvent.event);
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO << "dispatch key event " << key;
+#endif
+ }
+
+ scan = 0;
+ return true;
+}
+
+void QBBInputContext::endComposition()
+{
+ if (!m_isComposing)
+ return;
+
+ QInputPanel *panel = qApp->inputPanel();
+ QObject *input = panel->inputItem();
+ if (!imfAvailable() || !input)
+ return;
+
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event(QLatin1String(""), attributes);
+ event.setCommitString(m_composingText);
+ m_composingText = QString();
+ m_isComposing = false;
+ QCoreApplication::sendEvent(input, &event);
+
+ action_event_t actionEvent;
+ memset(&actionEvent, 0, sizeof(actionEvent));
+ initEvent(&actionEvent.event, sInputSession, EVENT_ACTION, ACTION_END_COMPOSITION);
+ p_ictrl_dispatch_event(&actionEvent.event);
+}
+
+void QBBInputContext::setComposingText(QString const& composingText)
+{
+ m_composingText = composingText;
+ m_isComposing = true;
+
+ QInputPanel *panel = qApp->inputPanel();
+ QObject *input = panel->inputItem();
+ if (!imfAvailable() || !input)
+ return;
+
+ QList<QInputMethodEvent::Attribute> attributes;
+ QTextCharFormat format;
+ format.setFontUnderline(true);
+ attributes.push_back(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, composingText.length(), format));
+
+ QInputMethodEvent event(composingText, attributes);
+
+ QCoreApplication::sendEvent(input, &event);
+}
+
+int32_t QBBInputContext::processEvent(event_t *event)
+{
+ int32_t result = -1;
+ switch (event->event_type) {
+ case EVENT_SPELL_CHECK: {
+ #if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO << "EVENT_SPELL_CHECK";
+ #endif
+ result = 0;
+ break;
+ }
+
+ case EVENT_NAVIGATION: {
+ #if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO << "EVENT_NAVIGATION";
+ #endif
+
+ int key = event->event_id == NAVIGATE_UP ? KEYCODE_UP :
+ event->event_id == NAVIGATE_DOWN ? KEYCODE_DOWN :
+ event->event_id == NAVIGATE_LEFT ? KEYCODE_LEFT :
+ event->event_id == NAVIGATE_RIGHT ? KEYCODE_RIGHT : 0;
+
+ QBBEventThread::injectKeyboardEvent(KEY_DOWN | KEY_CAP_VALID, key, 0, 0, 0);
+ QBBEventThread::injectKeyboardEvent(KEY_CAP_VALID, key, 0, 0, 0);
+ result = 0;
+ break;
+ }
+
+ case EVENT_KEY: {
+ #if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO << "EVENT_KEY";
+ #endif
+ key_event_t *kevent = static_cast<key_event_t *>(event);
+
+ QBBEventThread::injectKeyboardEvent(KEY_DOWN | KEY_SYM_VALID | KEY_CAP_VALID, kevent->key_code, 0, 0, kevent->key_code);
+ QBBEventThread::injectKeyboardEvent(KEY_SYM_VALID | KEY_CAP_VALID, kevent->key_code, 0, 0, kevent->key_code);
+
+ result = 0;
+ break;
+ }
+
+ case EVENT_ACTION:
+ // Don't care, indicates that IMF is done.
+ break;
+
+ case EVENT_CARET:
+ case EVENT_NOTHING:
+ case EVENT_FOCUS:
+ case EVENT_USER_ACTION:
+ case EVENT_STROKE:
+ case EVENT_INVOKE_LATER:
+ qCritical() << Q_FUNC_INFO << "Unsupported event type: " << event->event_type;
+ break;
+ default:
+ qCritical() << Q_FUNC_INFO << "Unknown event type: " << event->event_type;
+ }
+ return result;
+}
+
+/**
+ * IMF Event Handlers
+ */
+
+int32_t QBBInputContext::onBeginBatchEdit(input_session_t *ic)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ // We don't care.
+ return 0;
+}
+
+int32_t QBBInputContext::onClearMetaKeyStates(input_session_t *ic, int32_t states)
+{
+ Q_UNUSED(states);
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ // Should never get called.
+ qCritical() << Q_FUNC_INFO << "onClearMetaKeyStates is unsupported.";
+ return 0;
+}
+
+int32_t QBBInputContext::onCommitText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position)
+{
+ Q_UNUSED(new_cursor_position); // TODO: How can we set the cursor position it's not part of the API.
+ if (!isSessionOkay(ic))
+ return 0;
+
+ QInputPanel *panel = qApp->inputPanel();
+ QObject *input = panel->inputItem();
+ if (!imfAvailable() || !input)
+ return 0;
+
+ QString commitString = QString::fromWCharArray(text->str, text->length);
+
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO << "Committing [" << commitString << "]";
+#endif
+
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event(QLatin1String(""), attributes);
+ event.setCommitString(commitString, 0, 0);
+
+ QCoreApplication::sendEvent(input, &event);
+ m_composingText = QString();
+
+ return 0;
+}
+
+int32_t QBBInputContext::onDeleteSurroundingText(input_session_t *ic, int32_t left_length, int32_t right_length)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO << "L:" << left_length << " R:" << right_length;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ QInputPanel *panel = qApp->inputPanel();
+ QObject *input = panel->inputItem();
+ if (!imfAvailable() || !input)
+ return 0;
+
+ if (hasSelectedText()) {
+ QBBEventThread::injectKeyboardEvent(KEY_DOWN | KEY_CAP_VALID, KEYCODE_DELETE, 0, 0, 0);
+ QBBEventThread::injectKeyboardEvent(KEY_CAP_VALID, KEYCODE_DELETE, 0, 0, 0);
+ reset();
+ return 0;
+ }
+
+ int replacementLength = left_length + right_length;
+ int replacementStart = -left_length;
+
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event(QLatin1String(""), attributes);
+ event.setCommitString(QLatin1String(""), replacementStart, replacementLength);
+ QCoreApplication::sendEvent(input, &event);
+
+ return 0;
+}
+
+int32_t QBBInputContext::onEndBatchEdit(input_session_t *ic)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ return 0;
+}
+
+int32_t QBBInputContext::onFinishComposingText(input_session_t *ic)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ QInputPanel *panel = qApp->inputPanel();
+ QObject *input = panel->inputItem();
+ if (!imfAvailable() || !input)
+ return 0;
+
+ // Only update the control, no need to send a message back to imf (don't call
+ // end composition)
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event(QLatin1String(""), attributes);
+ event.setCommitString(m_composingText);
+ m_composingText = QString();
+ m_isComposing = false;
+ QCoreApplication::sendEvent(input, &event);
+
+ return 0;
+}
+
+int32_t QBBInputContext::onGetCursorCapsMode(input_session_t *ic, int32_t req_modes)
+{
+ Q_UNUSED(req_modes);
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ // Should never get called.
+ qCritical() << Q_FUNC_INFO << "onGetCursorCapsMode is unsupported.";
+
+ return 0;
+}
+
+int32_t QBBInputContext::onGetCursorPosition(input_session_t *ic)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ QInputPanel *panel = qApp->inputPanel();
+ QObject *input = panel->inputItem();
+ if (!imfAvailable() || !input)
+ return 0;
+
+ QInputMethodQueryEvent query(Qt::ImCursorPosition);
+ QCoreApplication::sendEvent(input, &query);
+ m_lastCaretPos = query.value(Qt::ImCursorPosition).toInt();
+
+ return m_lastCaretPos;
+}
+
+extracted_text_t *QBBInputContext::onGetExtractedText(input_session_t *ic, extracted_text_request_t *request, int32_t flags)
+{
+ Q_UNUSED(flags);
+ Q_UNUSED(request);
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic)) {
+ extracted_text_t *et = (extracted_text_t *)calloc(sizeof(extracted_text_t),1);
+ et->text = reinterpret_cast<spannable_string_t *>(calloc(sizeof(spannable_string_t),1));
+ return et;
+ }
+
+ // Used to update dictionaries, but not supported right now.
+ extracted_text_t *et = (extracted_text_t *)calloc(sizeof(extracted_text_t),1);
+ et->text = reinterpret_cast<spannable_string_t *>(calloc(sizeof(spannable_string_t),1));
+
+ return et;
+}
+
+spannable_string_t *QBBInputContext::onGetSelectedText(input_session_t *ic, int32_t flags)
+{
+ Q_UNUSED(flags);
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return toSpannableString("");
+
+ QInputPanel *panel = qApp->inputPanel();
+ QObject *input = panel->inputItem();
+ if (!imfAvailable() || !input)
+ return 0;
+
+ QInputMethodQueryEvent query(Qt::ImCurrentSelection);
+ QCoreApplication::sendEvent(input, &query);
+ QString text = query.value(Qt::ImCurrentSelection).toString();
+
+ return toSpannableString(text);
+}
+
+spannable_string_t *QBBInputContext::onGetTextAfterCursor(input_session_t *ic, int32_t n, int32_t flags)
+{
+ Q_UNUSED(flags);
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return toSpannableString("");
+
+ QInputPanel *panel = qApp->inputPanel();
+ QObject *input = panel->inputItem();
+ if (!imfAvailable() || !input)
+ return toSpannableString("");
+
+ QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImSurroundingText);
+ QCoreApplication::sendEvent(input, &query);
+ QString text = query.value(Qt::ImSurroundingText).toString();
+ m_lastCaretPos = query.value(Qt::ImCursorPosition).toInt();
+
+ return toSpannableString(text.mid(m_lastCaretPos+1, n));
+}
+
+spannable_string_t *QBBInputContext::onGetTextBeforeCursor(input_session_t *ic, int32_t n, int32_t flags)
+{
+ Q_UNUSED(flags);
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return toSpannableString("");
+
+ QInputPanel *panel = qApp->inputPanel();
+ QObject *input = panel->inputItem();
+ if (!imfAvailable() || !input)
+ return toSpannableString("");
+
+ QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImSurroundingText);
+ QCoreApplication::sendEvent(input, &query);
+ QString text = query.value(Qt::ImSurroundingText).toString();
+ m_lastCaretPos = query.value(Qt::ImCursorPosition).toInt();
+
+ if (n < m_lastCaretPos) {
+ return toSpannableString(text.mid(m_lastCaretPos - n, n));
+ } else {
+ return toSpannableString(text.mid(0, m_lastCaretPos));
+ }
+}
+
+int32_t QBBInputContext::onPerformEditorAction(input_session_t *ic, int32_t editor_action)
+{
+ Q_UNUSED(editor_action);
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ // Should never get called.
+ qCritical() << Q_FUNC_INFO << "onPerformEditorAction is unsupported.";
+
+ return 0;
+}
+
+int32_t QBBInputContext::onReportFullscreenMode(input_session_t *ic, int32_t enabled)
+{
+ Q_UNUSED(enabled);
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ // Should never get called.
+ qCritical() << Q_FUNC_INFO << "onReportFullscreenMode is unsupported.";
+
+ return 0;
+}
+
+int32_t QBBInputContext::onSendEvent(input_session_t *ic, event_t *event)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ return processEvent(event);
+}
+
+int32_t QBBInputContext::onSendAsyncEvent(input_session_t *ic, event_t *event)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ return processEvent(event);
+}
+
+int32_t QBBInputContext::onSetComposingRegion(input_session_t *ic, int32_t start, int32_t end)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ QInputPanel *panel = qApp->inputPanel();
+ QObject *input = panel->inputItem();
+ if (!imfAvailable() || !input)
+ return 0;
+
+ QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImSurroundingText);
+ QCoreApplication::sendEvent(input, &query);
+ QString text = query.value(Qt::ImSurroundingText).toString();
+ m_lastCaretPos = query.value(Qt::ImCursorPosition).toInt();
+
+ QString empty = QString::fromLatin1("");
+ text = text.mid(start, end - start);
+
+ // Delete the current text.
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event(empty, attributes);
+ event.setCommitString(empty, start - m_lastCaretPos, end - start);
+ QCoreApplication::sendEvent(input, &event);
+
+ // Move the specified text into a preedit string.
+ setComposingText(text);
+
+ return 0;
+}
+
+int32_t QBBInputContext::onSetComposingText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position)
+{
+ Q_UNUSED(new_cursor_position);
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ QInputPanel *panel = qApp->inputPanel();
+ QObject *input = panel->inputItem();
+ if (!imfAvailable() || !input)
+ return 0;
+
+ m_isComposing = true;
+
+ QString preeditString = QString::fromWCharArray(text->str, text->length);
+ setComposingText(preeditString);
+
+ return 0;
+}
+
+int32_t QBBInputContext::onSetSelection(input_session_t *ic, int32_t start, int32_t end)
+{
+ Q_UNUSED(start);
+ Q_UNUSED(end);
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ // Should never get called.
+ qCritical() << Q_FUNC_INFO << "onSetSelection is unsupported.";
+
+ return 0;
+}
+
+void QBBInputContext::showInputPanel()
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ dispatchRequestSoftwareInputPanel();
+}
+
+void QBBInputContext::hideInputPanel()
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ dispatchCloseSoftwareInputPanel();
+}
+
+bool QBBInputContext::isInputPanelVisible() const
+{
+ return m_inputPanelVisible;
+}
+
+QLocale QBBInputContext::locale() const
+{
+ return m_inputPanelLocale;
+}
+
+void QBBInputContext::keyboardVisibilityChanged(bool visible)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO << "visible=" << visible;
+#endif
+ if (m_inputPanelVisible != visible) {
+ m_inputPanelVisible = visible;
+ emitInputPanelVisibleChanged();
+ }
+}
+
+void QBBInputContext::keyboardLocaleChanged(const QLocale &locale)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO << "locale=" << locale;
+#endif
+ if (m_inputPanelLocale != locale) {
+ m_inputPanelLocale = locale;
+ emitLocaleChanged();
+ }
+}
+
+void QBBInputContext::inputItemChanged()
+{
+ QInputMethod *inputMethod = qApp->inputMethod();
+ QObject *inputItem = inputMethod->inputItem();
+
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO << "input item=" << inputItem;
+#endif
+
+ if (!inputItem) {
+ if (m_inputPanelVisible)
+ hideInputPanel();
+ } else {
+ if (qobject_cast<QAbstractSpinBox*>(inputItem)) {
+ QBBVirtualKeyboard::instance().setKeyboardMode(QBBVirtualKeyboard::NumPunc);
+ } else {
+ QBBVirtualKeyboard::instance().setKeyboardMode(QBBVirtualKeyboard::Default);
+ }
+ if (!m_inputPanelVisible)
+ showInputPanel();
+ }
+}
diff --git a/src/plugins/platforms/blackberry/qbbinputcontext_imf.h b/src/plugins/platforms/blackberry/qbbinputcontext_imf.h
new file mode 100644
index 0000000000..135ec02971
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbinputcontext_imf.h
@@ -0,0 +1,132 @@
+/***************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBBINPUTCONTEXT_H
+#define QBBINPUTCONTEXT_H
+
+#include <QtGui/QPlatformInputContext>
+
+#include <QtCore/QLocale>
+#include <QtCore/QMetaType>
+#include <QtGui/QPlatformIntegration>
+
+#include "imf/imf_client.h"
+#include "imf/input_control.h"
+
+QT_BEGIN_NAMESPACE
+
+class QBBInputContext : public QPlatformInputContext
+{
+ Q_OBJECT
+public:
+ QBBInputContext();
+ ~QBBInputContext();
+
+ virtual bool isValid() const;
+
+ virtual bool filterEvent(const QEvent *event);
+ virtual void reset();
+ virtual void update(Qt::InputMethodQueries);
+ bool handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap);
+
+ virtual void showInputPanel();
+ virtual void hideInputPanel();
+ virtual bool isInputPanelVisible() const;
+
+ virtual QLocale locale() const;
+
+protected:
+ // Filters only for IMF events.
+ bool eventFilter(QObject *obj, QEvent *event);
+
+private Q_SLOTS:
+ void keyboardVisibilityChanged(bool visible);
+ void keyboardLocaleChanged(const QLocale &locale);
+ void inputItemChanged();
+
+private:
+ // IMF Event dispatchers
+ bool dispatchFocusEvent(FocusEventId id, int hints = Qt::ImhNone);
+ bool dispatchRequestSoftwareInputPanel();
+ bool dispatchCloseSoftwareInputPanel();
+ int32_t processEvent(event_t *event);
+
+ void closeSession();
+ void openSession();
+ bool hasSession();
+ void endComposition();
+ void setComposingText(QString const &composingText);
+ bool hasSelectedText();
+
+ // IMF Event handlers - these events will come in from QCoreApplication.
+ int32_t onBeginBatchEdit(input_session_t *ic);
+ int32_t onClearMetaKeyStates(input_session_t *ic, int32_t states);
+ int32_t onCommitText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position);
+ int32_t onDeleteSurroundingText(input_session_t *ic, int32_t left_length, int32_t right_length);
+ int32_t onEndBatchEdit(input_session_t *ic);
+ int32_t onFinishComposingText(input_session_t *ic);
+ int32_t onGetCursorCapsMode(input_session_t *ic, int32_t req_modes);
+ int32_t onGetCursorPosition(input_session_t *ic);
+ extracted_text_t *onGetExtractedText(input_session_t *ic, extracted_text_request_t *request, int32_t flags);
+ spannable_string_t *onGetSelectedText(input_session_t *ic, int32_t flags);
+ spannable_string_t *onGetTextAfterCursor(input_session_t *ic, int32_t n, int32_t flags);
+ spannable_string_t *onGetTextBeforeCursor(input_session_t *ic, int32_t n, int32_t flags);
+ int32_t onPerformEditorAction(input_session_t *ic, int32_t editor_action);
+ int32_t onReportFullscreenMode(input_session_t *ic, int32_t enabled);
+ int32_t onSendEvent(input_session_t *ic, event_t *event);
+ int32_t onSendAsyncEvent(input_session_t *ic, event_t *event);
+ int32_t onSetComposingRegion(input_session_t *ic, int32_t start, int32_t end);
+ int32_t onSetComposingText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position);
+ int32_t onSetSelection(input_session_t *ic, int32_t start, int32_t end);
+ int32_t onForceUpdate();
+
+ int m_lastCaretPos;
+ bool m_isComposing;
+ QString m_composingText;
+ bool m_inputPanelVisible;
+ QLocale m_inputPanelLocale;
+};
+
+Q_DECLARE_METATYPE(extracted_text_t*)
+
+QT_END_NAMESPACE
+
+#endif // QBBINPUTCONTEXT_H
diff --git a/src/plugins/platforms/blackberry/qbbinputcontext_noimf.cpp b/src/plugins/platforms/blackberry/qbbinputcontext_noimf.cpp
new file mode 100644
index 0000000000..abe84e2e53
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbinputcontext_noimf.cpp
@@ -0,0 +1,187 @@
+/***************************************************************************
+**
+** 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 "qbbinputcontext_noimf.h"
+#include "qbbvirtualkeyboard.h"
+
+#include <QtCore/QDebug>
+#include <QtGui/QGuiApplication>
+#include <QtWidgets/QAbstractSpinBox>
+
+QBBInputContext::QBBInputContext() :
+ QPlatformInputContext(),
+ m_inputPanelVisible(false),
+ m_inputPanelLocale(QLocale::c())
+{
+ QBBVirtualKeyboard &keyboard = QBBVirtualKeyboard::instance();
+ connect(&keyboard, SIGNAL(visibilityChanged(bool)), this, SLOT(keyboardVisibilityChanged(bool)));
+ connect(&keyboard, SIGNAL(localeChanged(QLocale)), this, SLOT(keyboardLocaleChanged(QLocale)));
+ keyboardVisibilityChanged(keyboard.isVisible());
+ keyboardLocaleChanged(keyboard.locale());
+
+ QInputMethod *inputMethod = qApp->inputMethod();
+ connect(inputMethod, SIGNAL(inputItemChanged()), this, SLOT(inputItemChanged()));
+}
+
+QBBInputContext::~QBBInputContext()
+{
+}
+
+bool QBBInputContext::isValid() const
+{
+ return true;
+}
+
+bool QBBInputContext::hasPhysicalKeyboard()
+{
+ // TODO: This should query the system to check if a USB keyboard is connected.
+ return false;
+}
+
+void QBBInputContext::reset()
+{
+}
+
+bool QBBInputContext::filterEvent( const QEvent *event )
+{
+ if (hasPhysicalKeyboard())
+ return false;
+
+ if (event->type() == QEvent::CloseSoftwareInputPanel) {
+ QBBVirtualKeyboard::instance().hideKeyboard();
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << "QBB: hiding virtual keyboard";
+#endif
+ return false;
+ }
+
+ if (event->type() == QEvent::RequestSoftwareInputPanel) {
+ QBBVirtualKeyboard::instance().showKeyboard();
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << "QBB: requesting virtual keyboard";
+#endif
+ return false;
+ }
+
+ return false;
+
+}
+
+bool QBBInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap)
+{
+ Q_UNUSED(flags);
+ Q_UNUSED(sym);
+ Q_UNUSED(mod);
+ Q_UNUSED(scan);
+ Q_UNUSED(cap);
+ return false;
+}
+
+void QBBInputContext::showInputPanel()
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ QBBVirtualKeyboard::instance().showKeyboard();
+}
+
+void QBBInputContext::hideInputPanel()
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ QBBVirtualKeyboard::instance().hideKeyboard();
+}
+
+bool QBBInputContext::isInputPanelVisible() const
+{
+ return m_inputPanelVisible;
+}
+
+QLocale QBBInputContext::locale() const
+{
+ return m_inputPanelLocale;
+}
+
+void QBBInputContext::keyboardVisibilityChanged(bool visible)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO << "visible=" << visible;
+#endif
+ if (m_inputPanelVisible != visible) {
+ m_inputPanelVisible = visible;
+ emitInputPanelVisibleChanged();
+ }
+}
+
+void QBBInputContext::keyboardLocaleChanged(const QLocale &locale)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO << "locale=" << locale;
+#endif
+ if (m_inputPanelLocale != locale) {
+ m_inputPanelLocale = locale;
+ emitLocaleChanged();
+ }
+}
+
+void QBBInputContext::inputItemChanged()
+{
+ QInputMethod *inputMethod = qApp->inputMethod();
+ QObject *inputItem = inputMethod->inputItem();
+
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << Q_FUNC_INFO << "input item=" << inputItem;
+#endif
+
+ if (!inputItem) {
+ if (m_inputPanelVisible)
+ hideInputPanel();
+ } else {
+ if (qobject_cast<QAbstractSpinBox*>(inputItem)) {
+ QBBVirtualKeyboard::instance().setKeyboardMode(QBBVirtualKeyboard::NumPunc);
+ } else {
+ QBBVirtualKeyboard::instance().setKeyboardMode(QBBVirtualKeyboard::Default);
+ }
+ if (!m_inputPanelVisible)
+ showInputPanel();
+ }
+}
diff --git a/src/plugins/platforms/blackberry/qbbinputcontext_noimf.h b/src/plugins/platforms/blackberry/qbbinputcontext_noimf.h
new file mode 100644
index 0000000000..3d4d6da830
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbinputcontext_noimf.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBBINPUTCONTEXT_H
+#define QBBINPUTCONTEXT_H
+
+#include <QtCore/QLocale>
+#include <QtGui/QPlatformInputContext>
+#include <QtGui/QPlatformIntegration>
+
+QT_BEGIN_NAMESPACE
+
+class QBBInputContext : public QPlatformInputContext
+{
+ Q_OBJECT
+public:
+ explicit QBBInputContext();
+ ~QBBInputContext();
+
+ virtual bool isValid() const;
+
+ void reset();
+ virtual bool filterEvent( const QEvent *event );
+ bool handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap);
+
+ virtual void showInputPanel();
+ virtual void hideInputPanel();
+ virtual bool isInputPanelVisible() const;
+
+ virtual QLocale locale() const;
+
+private Q_SLOTS:
+ void keyboardVisibilityChanged(bool visible);
+ void keyboardLocaleChanged(const QLocale &locale);
+ void inputItemChanged();
+
+private:
+ bool hasPhysicalKeyboard();
+
+ bool m_inputPanelVisible;
+ QLocale m_inputPanelLocale;
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBINPUTCONTEXT_H
diff --git a/src/plugins/platforms/blackberry/qbbintegration.cpp b/src/plugins/platforms/blackberry/qbbintegration.cpp
new file mode 100644
index 0000000000..9f922a419e
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbintegration.cpp
@@ -0,0 +1,293 @@
+/***************************************************************************
+**
+** 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 "qbbintegration.h"
+#include "qbbeventthread.h"
+#include "qbbglbackingstore.h"
+#include "qbbglcontext.h"
+#include "qbbnavigatorthread.h"
+#include "qbbrasterbackingstore.h"
+#include "qbbscreen.h"
+#include "qbbwindow.h"
+#include "qbbvirtualkeyboard.h"
+#include "qbbclipboard.h"
+#include "qbbglcontext.h"
+
+#if defined(QBB_IMF)
+#include "qbbinputcontext_imf.h"
+#else
+#include "qbbinputcontext_noimf.h"
+#endif
+
+#include "private/qgenericunixfontdatabase_p.h"
+#include "private/qgenericunixeventdispatcher_p.h"
+
+#include <QtGui/QPlatformWindow>
+#include <QtGui/QWindowSystemInterface>
+#include <QtGui/QOpenGLContext>
+
+#include <QtCore/QDebug>
+#include <QtCore/QHash>
+
+#include <errno.h>
+
+QT_BEGIN_NAMESPACE
+
+QBBWindowMapper QBBIntegration::ms_windowMapper;
+QMutex QBBIntegration::ms_windowMapperMutex;
+
+QBBIntegration::QBBIntegration()
+ : QPlatformIntegration()
+ , m_eventThread(0)
+ , m_navigatorThread(0)
+ , m_inputContext(0)
+ , m_fontDatabase(new QGenericUnixFontDatabase())
+ , m_paintUsingOpenGL(false)
+ , m_eventDispatcher(createUnixEventDispatcher())
+#ifndef QT_NO_CLIPBOARD
+ , m_clipboard(0)
+#endif
+{
+#if defined(QBBINTEGRATION_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("QBB: failed to connect to composition manager, errno=%d", errno);
+ }
+
+ // Create displays for all possible screens (which may not be attached)
+ QBBScreen::createDisplays(m_screenContext);
+ Q_FOREACH (QPlatformScreen *screen, QBBScreen::screens()) {
+ screenAdded(screen);
+ }
+
+ // Initialize global OpenGL resources
+ QBBGLContext::initialize();
+
+ // Create/start event thread
+ m_eventThread = new QBBEventThread(m_screenContext, *QBBScreen::primaryDisplay());
+ m_eventThread->start();
+
+ // Create/start navigator thread
+ m_navigatorThread = new QBBNavigatorThread(*QBBScreen::primaryDisplay());
+ m_navigatorThread->start();
+
+ // Create/start the keyboard class.
+ QBBVirtualKeyboard::instance();
+
+ // Set up the input context
+ m_inputContext = new QBBInputContext;
+}
+
+QBBIntegration::~QBBIntegration()
+{
+#if defined(QBBINTEGRATION_DEBUG)
+ qDebug() << "QBB: platform plugin shutdown begin";
+#endif
+ // Destroy the keyboard class.
+ QBBVirtualKeyboard::destroy();
+
+#ifndef QT_NO_CLIPBOARD
+ // Delete the clipboard
+ delete m_clipboard;
+#endif
+
+ // Stop/destroy event thread
+ delete m_eventThread;
+
+ // Stop/destroy navigator thread
+ delete m_navigatorThread;
+
+ // Destroy all displays
+ QBBScreen::destroyDisplays();
+
+ // Close connection to QNX composition manager
+ screen_destroy_context(m_screenContext);
+
+ // Cleanup global OpenGL resources
+ QBBGLContext::shutdown();
+
+#if defined(QBBINTEGRATION_DEBUG)
+ qDebug() << "QBB: platform plugin shutdown end";
+#endif
+}
+
+bool QBBIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+#if defined(QBBINTEGRATION_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 *QBBIntegration::createPlatformWindow(QWindow *window) const
+{
+#if defined(QBBINTEGRATION_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ // New windows are created on the primary display.
+ return new QBBWindow(window, m_screenContext);
+}
+
+QPlatformBackingStore *QBBIntegration::createPlatformBackingStore(QWindow *window) const
+{
+#if defined(QBBINTEGRATION_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ if (paintUsingOpenGL())
+ return new QBBGLBackingStore(window);
+ else
+ return new QBBRasterBackingStore(window);
+}
+
+QPlatformOpenGLContext *QBBIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
+{
+#if defined(QBBINTEGRATION_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ return new QBBGLContext(context);
+}
+
+QPlatformInputContext *QBBIntegration::inputContext() const
+{
+#if defined(QBBINTEGRATION_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ return m_inputContext;
+}
+
+void QBBIntegration::moveToScreen(QWindow *window, int screen)
+{
+#if defined(QBBINTEGRATION_DEBUG)
+ qDebug() << "QBBIntegration::moveToScreen - w=" << window << ", s=" << screen;
+#endif
+
+ // get platform window used by widget
+ QBBWindow *platformWindow = static_cast<QBBWindow *>(window->handle());
+
+ // lookup platform screen by index
+ QBBScreen *platformScreen = static_cast<QBBScreen*>(QBBScreen::screens().at(screen));
+
+ // move the platform window to the platform screen
+ platformWindow->setScreen(platformScreen);
+}
+
+QList<QPlatformScreen *> QBBIntegration::screens() const
+{
+#if defined(QBBINTEGRATION_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ return QBBScreen::screens();
+}
+
+QAbstractEventDispatcher *QBBIntegration::guiThreadEventDispatcher() const
+{
+#if defined(QBBINTEGRATION_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ return m_eventDispatcher;
+}
+
+#ifndef QT_NO_CLIPBOARD
+QPlatformClipboard *QBBIntegration::clipboard() const
+{
+#if defined(QBBINTEGRATION_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ if (!m_clipboard) {
+ m_clipboard = new QBBClipboard;
+ }
+ return m_clipboard;
+}
+#endif
+
+QVariant QBBIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
+{
+#if defined(QBBINTEGRATION_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ if (hint == ShowIsFullScreen)
+ return true;
+
+ return QPlatformIntegration::styleHint(hint);
+}
+
+QWindow *QBBIntegration::window(screen_window_t qnxWindow)
+{
+#if defined(QBBINTEGRATION_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ QMutexLocker locker(&ms_windowMapperMutex);
+ Q_UNUSED(locker);
+ return ms_windowMapper.value(qnxWindow, 0);
+}
+
+void QBBIntegration::addWindow(screen_window_t qnxWindow, QWindow *window)
+{
+#if defined(QBBINTEGRATION_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ QMutexLocker locker(&ms_windowMapperMutex);
+ Q_UNUSED(locker);
+ ms_windowMapper.insert(qnxWindow, window);
+}
+
+void QBBIntegration::removeWindow(screen_window_t qnxWindow)
+{
+#if defined(QBBINTEGRATION_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ QMutexLocker locker(&ms_windowMapperMutex);
+ Q_UNUSED(locker);
+ ms_windowMapper.remove(qnxWindow);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/blackberry/qbbintegration.h b/src/plugins/platforms/blackberry/qbbintegration.h
new file mode 100644
index 0000000000..6b54329dac
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbintegration.h
@@ -0,0 +1,119 @@
+/***************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBBINTEGRATION_H
+#define QBBINTEGRATION_H
+
+#include <QtGui/qplatformintegration_qpa.h>
+
+#include <QtCore/qmutex.h>
+
+#include <screen/screen.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBBEventThread;
+class QBBInputContext;
+class QBBNavigatorThread;
+class QBBWindow;
+
+#ifndef QT_NO_CLIPBOARD
+class QBBClipboard;
+#endif
+
+template<class K, class V> class QHash;
+typedef QHash<screen_window_t, QWindow *> QBBWindowMapper;
+
+class QBBIntegration : public QPlatformIntegration
+{
+public:
+ QBBIntegration();
+ virtual ~QBBIntegration();
+
+ virtual bool hasCapability(QPlatformIntegration::Capability cap) const;
+
+ virtual QPlatformWindow *createPlatformWindow(QWindow *window) const;
+ virtual QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
+ virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
+
+ virtual QPlatformInputContext *inputContext() const;
+
+ virtual QList<QPlatformScreen *> screens() const;
+ virtual void moveToScreen(QWindow *window, int screen);
+
+ virtual QAbstractEventDispatcher *guiThreadEventDispatcher() const;
+
+ virtual QPlatformFontDatabase *fontDatabase() const { return m_fontDatabase; }
+
+#ifndef QT_NO_CLIPBOARD
+ virtual QPlatformClipboard *clipboard() const;
+#endif
+
+ virtual QVariant styleHint(StyleHint hint) const;
+
+ bool paintUsingOpenGL() const { return m_paintUsingOpenGL; }
+
+ static QWindow *window(screen_window_t qnxWindow);
+
+private:
+ static void addWindow(screen_window_t qnxWindow, QWindow *window);
+ static void removeWindow(screen_window_t qnxWindow);
+
+ screen_context_t m_screenContext;
+ QBBEventThread *m_eventThread;
+ QBBNavigatorThread *m_navigatorThread;
+ QBBInputContext *m_inputContext;
+ QPlatformFontDatabase *m_fontDatabase;
+ bool m_paintUsingOpenGL;
+ QAbstractEventDispatcher *m_eventDispatcher;
+#ifndef QT_NO_CLIPBOARD
+ mutable QBBClipboard* m_clipboard;
+#endif
+
+ static QBBWindowMapper ms_windowMapper;
+ static QMutex ms_windowMapperMutex;
+
+ friend class QBBWindow;
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBINTEGRATION_H
diff --git a/src/plugins/platforms/blackberry/qbbkeytranslator.h b/src/plugins/platforms/blackberry/qbbkeytranslator.h
new file mode 100644
index 0000000000..fdc1220aba
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbkeytranslator.h
@@ -0,0 +1,269 @@
+/***************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBBKEYTRANSLATOR_H
+#define QBBKEYTRANSLATOR_H
+
+#include <sys/keycodes.h>
+
+#if defined(QBBEVENTTHREAD_DEBUG)
+#include <QtCore/QDebug>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+Qt::Key keyTranslator( int key )
+{
+ switch (key) {
+ case KEYCODE_PAUSE:
+ return Qt::Key_Pause;
+
+ case KEYCODE_SCROLL_LOCK:
+ return Qt::Key_ScrollLock;
+
+ case KEYCODE_PRINT:
+ return Qt::Key_Print;
+
+ case KEYCODE_SYSREQ:
+ return Qt::Key_SysReq;
+
+// case KEYCODE_BREAK:
+
+ case KEYCODE_ESCAPE:
+ return Qt::Key_Escape;
+
+ case KEYCODE_BACKSPACE:
+ return Qt::Key_Backspace;
+
+ case KEYCODE_TAB:
+ return Qt::Key_Tab;
+
+ case KEYCODE_BACK_TAB:
+ return Qt::Key_Backtab;
+
+ case KEYCODE_RETURN:
+ return Qt::Key_Return;
+
+ case KEYCODE_CAPS_LOCK:
+ return Qt::Key_CapsLock;
+
+ case KEYCODE_LEFT_SHIFT:
+ case KEYCODE_RIGHT_SHIFT:
+ return Qt::Key_Shift;
+
+ case KEYCODE_LEFT_CTRL:
+ case KEYCODE_RIGHT_CTRL:
+ return Qt::Key_Control;
+
+ case KEYCODE_LEFT_ALT:
+ case KEYCODE_RIGHT_ALT:
+ return Qt::Key_Alt;
+
+ case KEYCODE_MENU:
+ return Qt::Key_Menu;
+
+ case KEYCODE_LEFT_HYPER:
+ return Qt::Key_Hyper_L;
+
+ case KEYCODE_RIGHT_HYPER:
+ return Qt::Key_Hyper_R;
+
+ case KEYCODE_INSERT:
+ return Qt::Key_Insert;
+
+ case KEYCODE_HOME:
+ return Qt::Key_Home;
+
+ case KEYCODE_PG_UP:
+ return Qt::Key_PageUp;
+
+ case KEYCODE_DELETE:
+ return Qt::Key_Delete;
+
+ case KEYCODE_END:
+ return Qt::Key_End;
+
+ case KEYCODE_PG_DOWN:
+ return Qt::Key_PageDown;
+
+ case KEYCODE_LEFT:
+ return Qt::Key_Left;
+
+ case KEYCODE_RIGHT:
+ return Qt::Key_Right;
+
+ case KEYCODE_UP:
+ return Qt::Key_Up;
+
+ case KEYCODE_DOWN:
+ return Qt::Key_Down;
+
+ case KEYCODE_NUM_LOCK:
+ return Qt::Key_NumLock;
+
+ case KEYCODE_KP_PLUS:
+ return Qt::Key_Plus;
+
+ case KEYCODE_KP_MINUS:
+ return Qt::Key_Minus;
+
+ case KEYCODE_KP_MULTIPLY:
+ return Qt::Key_Asterisk;
+
+ case KEYCODE_KP_DIVIDE:
+ return Qt::Key_Slash;
+
+ case KEYCODE_KP_ENTER:
+ return Qt::Key_Enter;
+
+ case KEYCODE_KP_HOME:
+ return Qt::Key_Home;
+
+ case KEYCODE_KP_UP:
+ return Qt::Key_Up;
+
+ case KEYCODE_KP_PG_UP:
+ return Qt::Key_PageUp;
+
+ case KEYCODE_KP_LEFT:
+ return Qt::Key_Left;
+
+ // Is this right?
+ case KEYCODE_KP_FIVE:
+ return Qt::Key_5;
+
+ case KEYCODE_KP_RIGHT:
+ return Qt::Key_Right;
+
+ case KEYCODE_KP_END:
+ return Qt::Key_End;
+
+ case KEYCODE_KP_DOWN:
+ return Qt::Key_Down;
+
+ case KEYCODE_KP_PG_DOWN:
+ return Qt::Key_PageDown;
+
+ case KEYCODE_KP_INSERT:
+ return Qt::Key_Insert;
+
+ case KEYCODE_KP_DELETE:
+ return Qt::Key_Delete;
+
+ case KEYCODE_F1:
+ return Qt::Key_F1;
+
+ case KEYCODE_F2:
+ return Qt::Key_F2;
+
+ case KEYCODE_F3:
+ return Qt::Key_F3;
+
+ case KEYCODE_F4:
+ return Qt::Key_F4;
+
+ case KEYCODE_F5:
+ return Qt::Key_F5;
+
+ case KEYCODE_F6:
+ return Qt::Key_F6;
+
+ case KEYCODE_F7:
+ return Qt::Key_F7;
+
+ case KEYCODE_F8:
+ return Qt::Key_F8;
+
+ case KEYCODE_F9:
+ return Qt::Key_F9;
+
+ case KEYCODE_F10:
+ return Qt::Key_F10;
+
+ case KEYCODE_F11:
+ return Qt::Key_F11;
+
+ case KEYCODE_F12:
+ return Qt::Key_F12;
+
+ // See keycodes.h for more, but these are all the basics. And printables are already included.
+
+ default:
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: unknown key for translation:" << key;
+#endif
+ break;
+ }
+
+ return Qt::Key_Escape;
+}
+
+bool isKeypadKey( int key )
+{
+ switch (key)
+ {
+ case KEYCODE_KP_PLUS:
+ case KEYCODE_KP_MINUS:
+ case KEYCODE_KP_MULTIPLY:
+ case KEYCODE_KP_DIVIDE:
+ case KEYCODE_KP_ENTER:
+ case KEYCODE_KP_HOME:
+ case KEYCODE_KP_UP:
+ case KEYCODE_KP_PG_UP:
+ case KEYCODE_KP_LEFT:
+ case KEYCODE_KP_FIVE:
+ case KEYCODE_KP_RIGHT:
+ case KEYCODE_KP_END:
+ case KEYCODE_KP_DOWN:
+ case KEYCODE_KP_PG_DOWN:
+ case KEYCODE_KP_INSERT:
+ case KEYCODE_KP_DELETE:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+QT_END_NAMESPACE
+
+#endif // QBBKEYTRANSLATOR_H
diff --git a/src/plugins/platforms/blackberry/qbbnavigatorthread.cpp b/src/plugins/platforms/blackberry/qbbnavigatorthread.cpp
new file mode 100644
index 0000000000..65cbb77d31
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbnavigatorthread.cpp
@@ -0,0 +1,279 @@
+/***************************************************************************
+**
+** 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 "qbbnavigatorthread.h"
+#include "qbbscreen.h"
+
+#include <QtGui/QGuiApplication>
+#include <QtGui/QWindow>
+#include <QtGui/QWindowSystemInterface>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QDebug>
+#include <QtCore/QList>
+#include <QtCore/QSocketNotifier>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+static const char *navigatorControlPath = "/pps/services/navigator/control";
+static const int ppsBufferSize = 4096;
+
+QBBNavigatorThread::QBBNavigatorThread(QBBScreen& primaryScreen)
+ : m_primaryScreen(primaryScreen),
+ m_fd(-1),
+ m_readNotifier(0)
+{
+}
+
+QBBNavigatorThread::~QBBNavigatorThread()
+{
+ // block until thread terminates
+ shutdown();
+
+ delete m_readNotifier;
+}
+
+void QBBNavigatorThread::run()
+{
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "QBB: navigator thread started";
+#endif
+
+ // open connection to navigator
+ errno = 0;
+ m_fd = open(navigatorControlPath, O_RDWR);
+ if (m_fd == -1) {
+ qWarning("QBB: failed to open navigator pps, errno=%d", errno);
+ return;
+ }
+
+ m_readNotifier = new QSocketNotifier(m_fd, QSocketNotifier::Read);
+ // using direct connection to get the slot called in this thread's context
+ connect(m_readNotifier, SIGNAL(activated(int)), this, SLOT(readData()), Qt::DirectConnection);
+
+ exec();
+
+ // close connection to navigator
+ close(m_fd);
+
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "QBB: navigator thread stopped";
+#endif
+}
+
+void QBBNavigatorThread::shutdown()
+{
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "QBB: navigator thread shutdown begin";
+#endif
+
+ // signal thread to terminate
+ quit();
+
+ // block until thread terminates
+ wait();
+
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "QBB: navigator thread shutdown end";
+#endif
+}
+
+void QBBNavigatorThread::parsePPS(const QByteArray &ppsData, QByteArray &msg, QByteArray &dat, QByteArray &id)
+{
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "PPS: data=" << ppsData;
+#endif
+
+ // tokenize pps data into lines
+ QList<QByteArray> lines = ppsData.split('\n');
+
+ // validate pps object
+ if (lines.size() == 0 || lines.at(0) != "@control") {
+ qFatal("QBB: unrecognized pps object, data=%s", ppsData.constData());
+ }
+
+ // parse pps object attributes and extract values
+ for (int i = 1; i < lines.size(); i++) {
+
+ // tokenize current attribute
+ const QByteArray &attr = lines.at(i);
+
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "PPS: attr=" << attr;
+#endif
+
+ int firstColon = attr.indexOf(':');
+ if (firstColon == -1) {
+ // abort - malformed attribute
+ continue;
+ }
+
+ int secondColon = attr.indexOf(':', firstColon + 1);
+ if (secondColon == -1) {
+ // abort - malformed attribute
+ continue;
+ }
+
+ QByteArray key = attr.left(firstColon);
+ QByteArray value = attr.mid(secondColon + 1);
+
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "PPS: key=" << key;
+ qDebug() << "PPS: val=" << value;
+#endif
+
+ // save attribute value
+ if (key == "msg") {
+ msg = value;
+ } else if (key == "dat") {
+ dat = value;
+ } else if (key == "id") {
+ id = value;
+ } else {
+ qFatal("QBB: unrecognized pps attribute, attr=%s", key.constData());
+ }
+ }
+}
+
+void QBBNavigatorThread::replyPPS(const QByteArray &res, const QByteArray &id, const QByteArray &dat)
+{
+ // construct pps message
+ QByteArray ppsData = "res::";
+ ppsData += res;
+ ppsData += "\nid::";
+ ppsData += id;
+ if (!dat.isEmpty()) {
+ ppsData += "\ndat::";
+ ppsData += dat;
+ }
+ ppsData += "\n";
+
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "PPS reply=" << ppsData;
+#endif
+
+ // send pps message to navigator
+ errno = 0;
+ int bytes = write(m_fd, ppsData.constData(), ppsData.size());
+ if (bytes == -1) {
+ qFatal("QBB: failed to write navigator pps, errno=%d", errno);
+ }
+}
+
+void QBBNavigatorThread::handleMessage(const QByteArray &msg, const QByteArray &dat, const QByteArray &id)
+{
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "PPS: msg=" << msg << ", dat=" << dat << ", id=" << id;
+#endif
+
+ // check message type
+ if (msg == "orientationCheck") {
+
+ // reply to navigator that (any) orientation is acceptable
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "PPS: orientation check, o=" << dat;
+#endif
+ replyPPS(msg, id, "true");
+
+ } else if (msg == "orientation") {
+
+ // update screen geometry and reply to navigator that we're ready
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "PPS: orientation, o=" << dat;
+#endif
+ m_primaryScreen.setRotation( dat.toInt() );
+ QWindowSystemInterface::handleScreenGeometryChange(0, m_primaryScreen.geometry());
+ replyPPS(msg, id, "");
+
+ } else if (msg == "SWIPE_DOWN") {
+
+ // simulate menu key press
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "PPS: menu";
+#endif
+ QWindow *w = QGuiApplication::focusWindow();
+ QWindowSystemInterface::handleKeyEvent(w, QEvent::KeyPress, Qt::Key_Menu, Qt::NoModifier);
+ QWindowSystemInterface::handleKeyEvent(w, QEvent::KeyRelease, Qt::Key_Menu, Qt::NoModifier);
+
+ } else if (msg == "exit") {
+
+ // shutdown everything
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "PPS: exit";
+#endif
+ QCoreApplication::quit();
+ }
+}
+
+void QBBNavigatorThread::readData()
+{
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "QBB: reading navigator data";
+#endif
+ // allocate buffer for pps data
+ char buffer[ppsBufferSize];
+
+ // attempt to read pps data
+ errno = 0;
+ int bytes = read(m_fd, buffer, ppsBufferSize - 1);
+ if (bytes == -1) {
+ qFatal("QBB: failed to read navigator pps, errno=%d", errno);
+ }
+
+ // check if pps data was received
+ if (bytes > 0) {
+
+ // ensure data is null terminated
+ buffer[bytes] = '\0';
+
+ // process received message
+ QByteArray ppsData(buffer);
+ QByteArray msg;
+ QByteArray dat;
+ QByteArray id;
+ parsePPS(ppsData, msg, dat, id);
+ handleMessage(msg, dat, id);
+ }
+}
diff --git a/src/plugins/platforms/blackberry/qbbnavigatorthread.h b/src/plugins/platforms/blackberry/qbbnavigatorthread.h
new file mode 100644
index 0000000000..fda24b0c67
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbnavigatorthread.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBBNAVIGATORTHREAD_H
+#define QBBNAVIGATORTHREAD_H
+
+#include <QThread>
+
+QT_BEGIN_NAMESPACE
+
+class QBBScreen;
+class QSocketNotifier;
+
+class QBBNavigatorThread : public QThread
+{
+ Q_OBJECT
+public:
+ QBBNavigatorThread(QBBScreen &primaryScreen);
+ virtual ~QBBNavigatorThread();
+
+protected:
+ virtual void run();
+
+private Q_SLOTS:
+ void readData();
+
+private:
+ void shutdown();
+ void parsePPS(const QByteArray &ppsData, QByteArray &msg, QByteArray &dat, QByteArray &id);
+ void replyPPS(const QByteArray &res, const QByteArray &id, const QByteArray &dat);
+ void handleMessage(const QByteArray &msg, const QByteArray &dat, const QByteArray &id);
+
+ QBBScreen &m_primaryScreen;
+ int m_fd;
+ QSocketNotifier *m_readNotifier;
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBNAVIGATORTHREAD_H
diff --git a/src/plugins/platforms/blackberry/qbbrasterbackingstore.cpp b/src/plugins/platforms/blackberry/qbbrasterbackingstore.cpp
new file mode 100644
index 0000000000..405e09260f
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbrasterbackingstore.cpp
@@ -0,0 +1,166 @@
+/***************************************************************************
+**
+** 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 "qbbrasterbackingstore.h"
+#include "qbbwindow.h"
+
+#include <QtCore/QDebug>
+
+#include <errno.h>
+
+QT_BEGIN_NAMESPACE
+
+QBBRasterBackingStore::QBBRasterBackingStore(QWindow *window)
+ : QPlatformBackingStore(window)
+{
+#if defined(QBBRASTERBACKINGSTORE_DEBUG)
+ qDebug() << "QBBRasterBackingStore::QBBRasterBackingStore - w=" << window;
+#endif
+
+ // save platform window associated with widget
+ m_platformWindow = static_cast<QBBWindow*>(window->handle());
+}
+
+QBBRasterBackingStore::~QBBRasterBackingStore()
+{
+#if defined(QBBRasterBackingStore_DEBUG)
+ qDebug() << "QBBRasterBackingStore::~QBBRasterBackingStore - w=" << window();
+#endif
+}
+
+QPaintDevice *QBBRasterBackingStore::paintDevice()
+{
+ return m_platformWindow->renderBuffer().image();
+}
+
+void QBBRasterBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
+{
+ Q_UNUSED(window);
+ Q_UNUSED(offset);
+
+#if defined(QBBRASTERBACKINGSTORE_DEBUG)
+ qDebug() << "QBBRasterBackingStore::flush - w=" << this->window();
+#endif
+
+ // visit all pending scroll operations
+ for (int i = m_scrollOpList.size() - 1; i >= 0; i--) {
+
+ // do the scroll operation
+ ScrollOp &op = m_scrollOpList[i];
+ QRegion srcArea = op.totalArea.intersected( op.totalArea.translated(-op.dx, -op.dy) );
+ m_platformWindow->scroll(srcArea, op.dx, op.dy);
+ }
+
+ // clear all pending scroll operations
+ m_scrollOpList.clear();
+
+ // update the display with newly rendered content
+ m_platformWindow->post(region);
+}
+
+void QBBRasterBackingStore::resize(const QSize &size, const QRegion &staticContents)
+{
+ Q_UNUSED(size);
+ Q_UNUSED(staticContents);
+#if defined(QBBRASTERBACKINGSTORE_DEBUG)
+ qDebug() << "QBBRasterBackingStore::resize - w=" << window() << ", s=" << size;
+#endif
+
+ // NOTE: defer resizing window buffers until next paint as
+ // resize() can be called multiple times before a paint occurs
+}
+
+bool QBBRasterBackingStore::scroll(const QRegion &area, int dx, int dy)
+{
+#if defined(QBBRASTERBACKINGSTORE_DEBUG)
+ qDebug() << "QBBRasterBackingStore::scroll - w=" << window();
+#endif
+
+ // calculate entire region affected by scroll operation (src + dst)
+ QRegion totalArea = area.translated(dx, dy);
+ totalArea += area;
+
+ // visit all pending scroll operations
+ for (int i = m_scrollOpList.size() - 1; i >= 0; i--) {
+
+ ScrollOp &op = m_scrollOpList[i];
+ if (op.totalArea == totalArea) {
+ // same area is being scrolled again - update delta
+ op.dx += dx;
+ op.dy += dy;
+ return true;
+ } else if (op.totalArea.intersects(totalArea)) {
+ // current scroll overlaps previous scroll but is
+ // not equal in area - just paint everything
+ qWarning("QBB: pending scroll operations overlap but not equal");
+ return false;
+ }
+ }
+
+ // create new scroll operation
+ m_scrollOpList.append( ScrollOp(totalArea, dx, dy) );
+ return true;
+}
+
+void QBBRasterBackingStore::beginPaint(const QRegion &region)
+{
+ Q_UNUSED(region);
+
+#if defined(QBBRASTERBACKINGSTORE_DEBUG)
+ qDebug() << "QBBRasterBackingStore::beginPaint - w=" << window();
+#endif
+
+ // resize window buffers if surface resized
+ QSize s = window()->size();
+ if (s != m_platformWindow->bufferSize()) {
+ m_platformWindow->setBufferSize(s);
+ }
+}
+
+void QBBRasterBackingStore::endPaint(const QRegion &region)
+{
+ Q_UNUSED(region);
+#if defined(QBBRasterBackingStore_DEBUG)
+ qDebug() << "QBBRasterBackingStore::endPaint - w=" << window();
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/blackberry/qbbrasterbackingstore.h b/src/plugins/platforms/blackberry/qbbrasterbackingstore.h
new file mode 100644
index 0000000000..ca1e27bcc8
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbrasterbackingstore.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBBRASTERWINDOWSURFACE_H
+#define QBBRASTERWINDOWSURFACE_H
+
+#include <QtGui/qplatformbackingstore_qpa.h>
+
+#include <screen/screen.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBBWindow;
+
+class QBBRasterBackingStore : public QPlatformBackingStore
+{
+public:
+ QBBRasterBackingStore(QWindow *window);
+ virtual ~QBBRasterBackingStore();
+
+ virtual QPaintDevice *paintDevice();
+ virtual void flush(QWindow *window, const QRegion &region, const QPoint &offset);
+ virtual void resize(const QSize &size, const QRegion &staticContents);
+ virtual bool scroll(const QRegion &area, int dx, int dy);
+ virtual void beginPaint(const QRegion &region);
+ virtual void endPaint(const QRegion &region);
+
+private:
+ class ScrollOp {
+ public:
+ ScrollOp(const QRegion &a, int x, int y) : totalArea(a), dx(x), dy(y) {}
+ QRegion totalArea;
+ int dx;
+ int dy;
+ };
+
+ QBBWindow *m_platformWindow;
+ QList<ScrollOp> m_scrollOpList;
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBRASTERWINDOWSURFACE_H
diff --git a/src/plugins/platforms/blackberry/qbbrootwindow.cpp b/src/plugins/platforms/blackberry/qbbrootwindow.cpp
new file mode 100644
index 0000000000..831b0774f9
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbrootwindow.cpp
@@ -0,0 +1,257 @@
+/***************************************************************************
+**
+** 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 "qbbrootwindow.h"
+
+#include "qbbscreen.h"
+
+#include <QtCore/QUuid>
+
+#if defined(QBBROOTWINDOW_DEBUG)
+#include <QtCore/QDebug>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+
+static const int MAGIC_ZORDER_FOR_NO_NAV = 10;
+
+QBBRootWindow::QBBRootWindow(QBBScreen *screen)
+ : m_screen(screen),
+ m_window(0),
+ m_windowGroupName()
+{
+#if defined(QBBROOTWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ // Create one top-level QNX window to act as a container for child windows
+ // since navigator only supports one application window
+ errno = 0;
+ int result = screen_create_window(&m_window, m_screen->nativeContext());
+ int val[2];
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to create window, errno=%d", errno);
+ }
+
+ // Move window to proper display
+ errno = 0;
+ screen_display_t display = m_screen->nativeDisplay();
+ result = screen_set_window_property_pv(m_window, SCREEN_PROPERTY_DISPLAY, (void **)&display);
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to set window display, errno=%d", errno);
+ }
+
+ // Make sure window is above navigator but below keyboard if running as root
+ // since navigator won't automatically set our z-order in this case
+ if (getuid() == 0) {
+ errno = 0;
+ val[0] = MAGIC_ZORDER_FOR_NO_NAV;
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ZORDER, val);
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to set window z-order, errno=%d", errno);
+ }
+ }
+
+ // Window won't be visible unless it has some buffers so make one dummy buffer that is 1x1
+ errno = 0;
+ val[0] = SCREEN_USAGE_NATIVE;
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_USAGE, val);
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to set window buffer usage, errno=%d", errno);
+ }
+
+ errno = 0;
+ val[0] = m_screen->nativeFormat();
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, val);
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to set window pixel format, errno=%d", errno);
+ }
+
+ errno = 0;
+ val[0] = 1;
+ val[1] = 1;
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BUFFER_SIZE, val);
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to set window buffer size, errno=%d", errno);
+ }
+
+ errno = 0;
+ result = screen_create_window_buffers(m_window, 1);
+ if (result != 0) {
+ qFatal("QBB: failed to create window buffer, errno=%d", errno);
+ }
+
+ // Window is always the size of the display
+ errno = 0;
+ QRect geometry = m_screen->geometry();
+ val[0] = geometry.width();
+ val[1] = geometry.height();
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val);
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to set window size, errno=%d", errno);
+ }
+
+ // Fill the window with solid black
+ errno = 0;
+ val[0] = 0;
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_COLOR, val);
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to set window colour, errno=%d", errno);
+ }
+
+ // Make the window opaque
+ errno = 0;
+ val[0] = SCREEN_TRANSPARENCY_NONE;
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_TRANSPARENCY, val);
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to set window transparency, errno=%d", errno);
+ }
+
+ // Set the swap interval to 1
+ errno = 0;
+ val[0] = 1;
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SWAP_INTERVAL, val);
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to set window swap interval, errno=%d", errno);
+ }
+
+ // Set viewport size equal to window size but move outside buffer so the fill colour is used exclusively
+ errno = 0;
+ val[0] = geometry.width();
+ val[1] = geometry.height();
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val);
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to set window source size, errno=%d", errno);
+ }
+
+ errno = 0;
+ val[0] = 1;
+ val[1] = 0;
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_POSITION, val);
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to set window source position, errno=%d", errno);
+ }
+
+ createWindowGroup();
+ post();
+}
+
+QBBRootWindow::~QBBRootWindow()
+{
+ // Cleanup top-level QNX window
+ screen_destroy_window(m_window);
+}
+
+void QBBRootWindow::post() const
+{
+#if defined(QBBROOTWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ errno = 0;
+ screen_buffer_t buffer;
+ int result = screen_get_window_property_pv(m_window, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)&buffer);
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to query window buffer, errno=%d", errno);
+ }
+
+ errno = 0;
+ int dirtyRect[] = {0, 0, 1, 1};
+ result = screen_post_window(m_window, buffer, 1, dirtyRect, 0);
+ if (result != 0) {
+ qFatal("QBB: failed to post window buffer, errno=%d", errno);
+ }
+}
+
+void QBBRootWindow::flush() const
+{
+#if defined(QBBROOTWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ // Force immediate display update
+ errno = 0;
+ int result = screen_flush_context(m_screen->nativeContext(), 0);
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to flush context, errno=%d", errno);
+ }
+}
+
+void QBBRootWindow::setRotation(int rotation)
+{
+#if defined(QBBROOTWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "angle =" << rotation;
+#endif
+ errno = 0;
+ int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ROTATION, &rotation);
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to set window rotation, errno=%d", errno);
+ }
+}
+
+void QBBRootWindow::resize(const QSize &size)
+{
+ errno = 0;
+ int val[] = {size.width(), size.height()};
+ int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val);
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to set window size, errno=%d", errno);
+ }
+
+ errno = 0;
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val);
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to set window source size, errno=%d", errno);
+ }
+
+ // NOTE: display will update when child windows relayout and repaint
+}
+
+void QBBRootWindow::createWindowGroup()
+{
+ // Generate a random window group name
+ m_windowGroupName = QUuid::createUuid().toString().toAscii();
+
+ // Create window group so child windows can be parented by container window
+ errno = 0;
+ int result = screen_create_window_group(m_window, m_windowGroupName.constData());
+ if (result != 0) {
+ qFatal("QBBRootWindow: failed to create app window group, errno=%d", errno);
+ }
+}
diff --git a/src/plugins/platforms/blackberry/qbbrootwindow.h b/src/plugins/platforms/blackberry/qbbrootwindow.h
new file mode 100644
index 0000000000..0b89f52a5e
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbrootwindow.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBBROOTWINDOW_H
+#define QBBROOTWINDOW_H
+
+#include <QtCore/QByteArray>
+#include <QtCore/QRect>
+
+#include <screen/screen.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBBScreen;
+
+class QBBRootWindow
+{
+public:
+ QBBRootWindow(QBBScreen *screen);
+ ~QBBRootWindow();
+
+ screen_window_t nativeHandle() const { return m_window; }
+
+ void post() const;
+ void flush() const;
+
+ void setRotation(int rotation);
+
+ void resize(const QSize &size);
+
+ QByteArray groupName() const { return m_windowGroupName; }
+
+private:
+ void createWindowGroup();
+
+ QBBScreen *m_screen;
+ screen_window_t m_window;
+ QByteArray m_windowGroupName;
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBROOTWINDOW_H
diff --git a/src/plugins/platforms/blackberry/qbbscreen.cpp b/src/plugins/platforms/blackberry/qbbscreen.cpp
new file mode 100644
index 0000000000..39d2136b7d
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbscreen.cpp
@@ -0,0 +1,315 @@
+/***************************************************************************
+**
+** 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 "qbbscreen.h"
+#include "qbbvirtualkeyboard.h"
+#include "qbbwindow.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QUuid>
+
+#include <errno.h>
+
+QT_BEGIN_NAMESPACE
+
+QList<QPlatformScreen *> QBBScreen::ms_screens;
+QList<QBBWindow*> QBBScreen::ms_childWindows;
+
+QBBScreen::QBBScreen(screen_context_t screenContext, screen_display_t display, bool primaryScreen)
+ : m_screenContext(screenContext),
+ m_display(display),
+ m_rootWindow(),
+ m_primaryScreen(primaryScreen),
+ m_posted(false),
+ m_platformContext(0)
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ // Cache initial orientation of this display
+ // TODO: use ORIENTATION environment variable?
+ errno = 0;
+ int result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_ROTATION, &m_initialRotation);
+ if (result != 0) {
+ qFatal("QBBScreen: failed to query display rotation, errno=%d", errno);
+ }
+ m_currentRotation = m_initialRotation;
+
+ // Cache size of this display in pixels
+ // TODO: use WIDTH and HEIGHT environment variables?
+ errno = 0;
+ int val[2];
+ result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_SIZE, val);
+ if (result != 0) {
+ qFatal("QBBScreen: failed to query display size, errno=%d", errno);
+ }
+
+ m_currentGeometry = m_initialGeometry = QRect(0, 0, val[0], val[1]);
+
+ // Cache size of this display in millimeters
+ errno = 0;
+ result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_PHYSICAL_SIZE, val);
+ if (result != 0) {
+ qFatal("QBBScreen: failed to query display physical size, errno=%d", errno);
+ }
+
+ // Peg the DPI to 96 (for now) so fonts are a reasonable size. We'll want to match
+ // everything with a QStyle later, and at that point the physical size can be used
+ // instead.
+ {
+ static const int dpi = 96;
+ int width = m_currentGeometry.width() / dpi * qreal(25.4) ;
+ int height = m_currentGeometry.height() / dpi * qreal(25.4) ;
+
+ m_currentPhysicalSize = m_initialPhysicalSize = QSize(width,height);
+ }
+
+ // We only create the root window if we are the primary display.
+ if (primaryScreen)
+ m_rootWindow = QSharedPointer<QBBRootWindow>(new QBBRootWindow(this));
+}
+
+QBBScreen::~QBBScreen()
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+}
+
+/* static */
+void QBBScreen::createDisplays(screen_context_t context)
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ // Query number of displays
+ errno = 0;
+ int displayCount;
+ int result = screen_get_context_property_iv(context, SCREEN_PROPERTY_DISPLAY_COUNT, &displayCount);
+ if (result != 0) {
+ qFatal("QBBScreen: 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(context, SCREEN_PROPERTY_DISPLAYS, (void **)displays);
+ if (result != 0) {
+ qFatal("QBBScreen: failed to query displays, errno=%d", errno);
+ }
+
+ for (int i=0; i<displayCount; i++) {
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << "QBBScreen::Creating screen for display " << i;
+#endif
+ QBBScreen *screen = new QBBScreen(context, displays[i], i==0);
+ ms_screens.append(screen);
+ }
+}
+
+/* static */
+void QBBScreen::destroyDisplays()
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ qDeleteAll(ms_screens);
+ ms_screens.clear();
+
+ // We're not managing the child windows anymore so we need to clear the list.
+ ms_childWindows.clear();
+}
+
+/* static */
+int QBBScreen::defaultDepth()
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ static int defaultDepth = 0;
+ if (defaultDepth == 0) {
+ // check if display depth was specified in environment variable;
+ // use default value if no valid value found
+ defaultDepth = qgetenv("QBB_DISPLAY_DEPTH").toInt();
+ if (defaultDepth != 16 && defaultDepth != 32) {
+ defaultDepth = 32;
+ }
+ }
+ return defaultDepth;
+}
+
+QRect QBBScreen::availableGeometry() const
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ // available geometry = total geometry - keyboard
+ int keyboardHeight = QBBVirtualKeyboard::instance().height();
+ return QRect(m_currentGeometry.x(), m_currentGeometry.y(),
+ m_currentGeometry.width(), m_currentGeometry.height() - keyboardHeight);
+}
+
+/*!
+ Check if the supplied angles are perpendicular to each other.
+*/
+static bool isOrthogonal(int angle1, int angle2)
+{
+ return ((angle1 - angle2) % 180) != 0;
+}
+
+void QBBScreen::setRotation(int rotation)
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << Q_FUNC_INFO << "orientation =" << rotation;
+#endif
+ // Check if rotation changed
+ if (m_currentRotation != rotation) {
+ // Update rotation of root window
+ if (m_rootWindow)
+ m_rootWindow->setRotation(rotation);
+
+ // Swap dimensions if we've rotated 90 or 270 from initial orientation
+ if (isOrthogonal(m_currentRotation, rotation)) {
+ m_currentGeometry = QRect(0, 0, m_initialGeometry.height(), m_initialGeometry.width());
+ m_currentPhysicalSize = QSize(m_initialPhysicalSize.height(), m_initialPhysicalSize.width());
+ } else {
+ m_currentGeometry = QRect(0, 0, m_initialGeometry.width(), m_initialGeometry.height());
+ m_currentPhysicalSize = m_initialPhysicalSize;
+ }
+
+ // Resize root window if we've rotated 90 or 270 from previous orientation
+ if (isOrthogonal(m_currentRotation, rotation)) {
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << Q_FUNC_INFO << "resize, size =" << m_currentGeometry.size();
+#endif
+ if (m_rootWindow)
+ m_rootWindow->resize(m_currentGeometry.size());
+ } else {
+ // TODO: Find one global place to flush display updates
+ // Force immediate display update if no geometry changes required
+ if (m_rootWindow)
+ m_rootWindow->flush();
+ }
+
+ // Save new rotation
+ m_currentRotation = rotation;
+ }
+}
+
+void QBBScreen::addWindow(QBBWindow *window)
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window;
+#endif
+
+ if (ms_childWindows.contains(window))
+ return;
+
+ ms_childWindows.push_back(window);
+ QBBScreen::updateHierarchy();
+}
+
+void QBBScreen::removeWindow(QBBWindow *window)
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window;
+#endif
+
+ ms_childWindows.removeAll(window);
+ QBBScreen::updateHierarchy();
+}
+
+void QBBScreen::raiseWindow(QBBWindow *window)
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window;
+#endif
+
+ removeWindow(window);
+ ms_childWindows.push_back(window);
+ QBBScreen::updateHierarchy();
+}
+
+void QBBScreen::lowerWindow(QBBWindow *window)
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window;
+#endif
+
+ removeWindow(window);
+ ms_childWindows.push_front(window);
+ QBBScreen::updateHierarchy();
+}
+
+void QBBScreen::updateHierarchy()
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+
+ QList<QBBWindow*>::iterator it;
+ int topZorder = 0;
+
+ for (it = ms_childWindows.begin(); it != ms_childWindows.end(); it++)
+ (*it)->updateZorder(topZorder);
+
+ // After a hierarchy update, we need to force a flush on all screens.
+ // Right now, all screens share a context.
+ screen_flush_context( primaryDisplay()->m_screenContext, 0 );
+}
+
+void QBBScreen::onWindowPost(QBBWindow *window)
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ Q_UNUSED(window)
+
+ // post app window (so navigator will show it) after first child window
+ // has posted; this only needs to happen once as the app window's content
+ // never changes
+ if (!m_posted && m_rootWindow) {
+ m_rootWindow->post();
+ m_posted = true;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/blackberry/qbbscreen.h b/src/plugins/platforms/blackberry/qbbscreen.h
new file mode 100644
index 0000000000..16606944d8
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbscreen.h
@@ -0,0 +1,121 @@
+/***************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBBSCREEN_H
+#define QBBSCREEN_H
+
+#include <QtGui/QPlatformScreen>
+
+#include "qbbrootwindow.h"
+
+#include <QtCore/QByteArray>
+#include <QtCore/QScopedPointer>
+
+#include <screen/screen.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBBWindow;
+
+class QBBScreen : public QPlatformScreen
+{
+public:
+ static QList<QPlatformScreen *> screens() { return ms_screens; }
+ static void createDisplays(screen_context_t context);
+ static void destroyDisplays();
+ static QBBScreen *primaryDisplay() { return static_cast<QBBScreen*>(ms_screens.at(0)); }
+ static int defaultDepth();
+
+ virtual QRect geometry() const { return m_currentGeometry; }
+ virtual QRect availableGeometry() const;
+ virtual int depth() const { return defaultDepth(); }
+ virtual QImage::Format format() const { return (depth() == 32) ? QImage::Format_RGB32 : QImage::Format_RGB16; }
+ virtual QSizeF physicalSize() const { return m_currentPhysicalSize; }
+
+ bool isPrimaryScreen() const { return m_primaryScreen; }
+
+ int rotation() const { return m_currentRotation; }
+ void setRotation(int rotation);
+
+ int nativeFormat() const { return (depth() == 32) ? SCREEN_FORMAT_RGBA8888 : SCREEN_FORMAT_RGB565; }
+ screen_display_t nativeDisplay() const { return m_display; }
+ screen_context_t nativeContext() const { return m_screenContext; }
+ const char *windowGroupName() const { return m_rootWindow->groupName().constData(); }
+
+ /* Window hierarchy management */
+ static void addWindow(QBBWindow *child);
+ static void removeWindow(QBBWindow *child);
+ static void raiseWindow(QBBWindow *window);
+ static void lowerWindow(QBBWindow *window);
+ static void updateHierarchy();
+
+ void onWindowPost(QBBWindow *window);
+
+ QSharedPointer<QBBRootWindow> rootWindow() const { return m_rootWindow; }
+
+private:
+ QBBScreen(screen_context_t context, screen_display_t display, bool primaryScreen);
+ virtual ~QBBScreen();
+
+ static bool orthogonal(int rotation1, int rotation2);
+
+ screen_context_t m_screenContext;
+ screen_display_t m_display;
+ QSharedPointer<QBBRootWindow> m_rootWindow;
+ bool m_primaryScreen;
+ bool m_posted;
+ bool m_usingOpenGL;
+
+ int m_initialRotation;
+ int m_currentRotation;
+ QSize m_initialPhysicalSize;
+ QSize m_currentPhysicalSize;
+ QRect m_initialGeometry;
+ QRect m_currentGeometry;
+ QPlatformOpenGLContext *m_platformContext;
+
+ static QList<QPlatformScreen *> ms_screens;
+ static QList<QBBWindow *> ms_childWindows;
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBSCREEN_H
diff --git a/src/plugins/platforms/blackberry/qbbvirtualkeyboard.cpp b/src/plugins/platforms/blackberry/qbbvirtualkeyboard.cpp
new file mode 100644
index 0000000000..082ef9b19d
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbvirtualkeyboard.cpp
@@ -0,0 +1,500 @@
+/***************************************************************************
+**
+** 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 "qbbvirtualkeyboard.h"
+#include "qbbscreen.h"
+
+#include <QtGui/QPlatformScreen>
+#include <QtGui/QPlatformWindow>
+
+#include <QtCore/QDebug>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/iomsg.h>
+#include <sys/pps.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+const char *QBBVirtualKeyboard::ms_PPSPath = "/pps/services/input/control?wait";
+const size_t QBBVirtualKeyboard::ms_bufferSize = 2048;
+
+static QBBVirtualKeyboard *s_instance = 0;
+
+// Huge hack for keyboard shadow (see QNX PR 88400). Should be removed ASAP.
+#define KEYBOARD_SHADOW_HEIGHT 8
+
+QBBVirtualKeyboard::QBBVirtualKeyboard() :
+ m_encoder(NULL),
+ m_decoder(NULL),
+ m_buffer(NULL),
+ m_height(0),
+ m_fd(-1),
+ m_keyboardMode(Default),
+ m_visible(false),
+ m_locale(QLatin1String("en_US"))
+{
+ connect();
+}
+
+QBBVirtualKeyboard::~QBBVirtualKeyboard()
+{
+ close();
+}
+
+/* static */
+QBBVirtualKeyboard& QBBVirtualKeyboard::instance()
+{
+ if (!s_instance) {
+ s_instance = new QBBVirtualKeyboard();
+ s_instance->start();
+ }
+
+ return *s_instance;
+}
+
+/* static */
+void QBBVirtualKeyboard::destroy()
+{
+ if (s_instance) {
+ delete s_instance;
+ s_instance = 0;
+ }
+}
+
+void QBBVirtualKeyboard::close()
+{
+ if (m_fd) {
+ // any reads will fail after we close the fd, which is basically what we want.
+ ::close(m_fd);
+ }
+
+ // Wait for the thread to die (should be immediate), then continue the cleanup.
+ wait();
+
+ if (m_fd) {
+ m_fd = -1;
+ }
+
+
+ if (m_decoder)
+ {
+ pps_decoder_cleanup(m_decoder);
+ delete m_decoder;
+ m_decoder = NULL;
+ }
+
+ if (m_encoder)
+ {
+ pps_encoder_cleanup(m_encoder);
+ delete m_encoder;
+ m_encoder = NULL;
+ }
+
+ delete [] m_buffer;
+ m_buffer = NULL;
+}
+
+bool QBBVirtualKeyboard::connect()
+{
+ close();
+
+ m_encoder = new pps_encoder_t;
+ m_decoder = new pps_decoder_t;
+
+ pps_encoder_initialize(m_encoder, false);
+ pps_decoder_initialize(m_decoder, NULL);
+
+ errno = 0;
+ m_fd = ::open(ms_PPSPath, O_RDWR);
+ if (m_fd == -1)
+ {
+ qCritical("QBBVirtualKeyboard: Unable to open \"%s\" for keyboard: %s (%d).",
+ ms_PPSPath, strerror(errno), errno);
+ close();
+ return false;
+ }
+
+ m_buffer = new char[ms_bufferSize];
+ if (!m_buffer) {
+ qCritical("QBBVirtualKeyboard: Unable to allocate buffer of %d bytes. Size is unavailable.", ms_bufferSize);
+ return false;
+ }
+
+ if (!queryPPSInfo())
+ return false;
+
+ start();
+
+ return true;
+}
+
+bool QBBVirtualKeyboard::queryPPSInfo()
+{
+ // Request info, requires id to regenerate res message.
+ pps_encoder_add_string(m_encoder, "msg", "info");
+ pps_encoder_add_string(m_encoder, "id", "libWebView");
+
+ if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) {
+ close();
+ return false;
+ }
+
+ pps_encoder_reset(m_encoder);
+
+ return true;
+}
+
+void QBBVirtualKeyboard::notifyClientActiveStateChange(bool active)
+{
+ if (!active)
+ hideKeyboard();
+}
+
+void QBBVirtualKeyboard::run()
+{
+ ppsDataReady();
+}
+
+void QBBVirtualKeyboard::ppsDataReady()
+{
+ while (1) {
+ ssize_t nread = read(m_fd, m_buffer, ms_bufferSize - 1);
+
+#ifdef QBBVIRTUALKEYBOARD_DEBUG
+ qDebug() << "QBB: keyboardMessage size: " << nread;
+#endif
+ if (nread < 0)
+ break;
+
+ // nread is the real space necessary, not the amount read.
+ if (static_cast<size_t>(nread) > ms_bufferSize - 1) {
+ qCritical("QBBVirtualKeyboard: Keyboard buffer size too short; need %u.", nread + 1);
+ break;
+ }
+
+ m_buffer[nread] = 0;
+ pps_decoder_parse_pps_str(m_decoder, m_buffer);
+ pps_decoder_push(m_decoder, NULL);
+#ifdef QBBVIRTUALKEYBOARD_DEBUG
+ pps_decoder_dump_tree(m_decoder, stderr);
+#endif
+
+ const char *value;
+ if (pps_decoder_get_string(m_decoder, "error", &value) == PPS_DECODER_OK) {
+ qCritical("QBBVirtualKeyboard: Keyboard PPS decoder error: %s", value ? value : "[null]");
+ continue;
+ }
+
+ if (pps_decoder_get_string(m_decoder, "msg", &value) == PPS_DECODER_OK) {
+ if (strcmp(value, "show") == 0) {
+ const bool oldVisible = m_visible;
+ m_visible = true;
+ handleKeyboardStateChangeMessage(true);
+ if (oldVisible != m_visible)
+ emit visibilityChanged(m_visible);
+ } else if (strcmp(value, "hide") == 0) {
+ const bool oldVisible = m_visible;
+ m_visible = false;
+ handleKeyboardStateChangeMessage(false);
+ if (oldVisible != m_visible)
+ emit visibilityChanged(m_visible);
+ } else if (strcmp(value, "info") == 0)
+ handleKeyboardInfoMessage();
+ else if (strcmp(value, "connect") == 0) { }
+ else
+ qCritical("QBBVirtualKeyboard: Unexpected keyboard PPS msg value: %s", value ? value : "[null]");
+ } else if (pps_decoder_get_string(m_decoder, "res", &value) == PPS_DECODER_OK) {
+ if (strcmp(value, "info") == 0)
+ handleKeyboardInfoMessage();
+ else
+ qCritical("QBBVirtualKeyboard: Unexpected keyboard PPS res value: %s", value ? value : "[null]");
+ } else
+ qCritical("QBBVirtualKeyboard: Unexpected keyboard PPS message type");
+ }
+
+#ifdef QBBVIRTUALKEYBOARD_DEBUG
+ qDebug() << "QBB: exiting keyboard thread";
+#endif
+
+ if (m_decoder)
+ pps_decoder_cleanup(m_decoder);
+}
+
+void QBBVirtualKeyboard::handleKeyboardInfoMessage()
+{
+ int newHeight = 0;
+ const char *value;
+
+ if (pps_decoder_push(m_decoder, "dat") != PPS_DECODER_OK) {
+ qCritical("QBBVirtualKeyboard: Keyboard PPS dat object not found");
+ return;
+ }
+ if (pps_decoder_get_int(m_decoder, "size", &newHeight) != PPS_DECODER_OK) {
+ qCritical("QBBVirtualKeyboard: Keyboard PPS size field not found");
+ return;
+ }
+ if (pps_decoder_push(m_decoder, "locale") != PPS_DECODER_OK) {
+ qCritical("QBBVirtualKeyboard: Keyboard PPS locale object not found");
+ return;
+ }
+ if (pps_decoder_get_string(m_decoder, "languageId", &value) != PPS_DECODER_OK) {
+ qCritical("QBBVirtualKeyboard: Keyboard PPS languageId field not found");
+ return;
+ }
+ const QString languageId = QString::fromLatin1(value);
+ if (pps_decoder_get_string(m_decoder, "countryId", &value) != PPS_DECODER_OK) {
+ qCritical("QBBVirtualKeyboard: Keyboard PPS size countryId not found");
+ return;
+ }
+ const QString countryId = QString::fromLatin1(value);
+
+ // HUGE hack, should be removed ASAP.
+ newHeight -= KEYBOARD_SHADOW_HEIGHT; // We want to ignore the 8 pixel shadow above the keyboard. (PR 88400)
+
+ if (newHeight != m_height) {
+ m_height = newHeight;
+ updateAvailableScreenGeometry();
+ }
+
+ const QLocale locale = QLocale(languageId + QLatin1Char('_') + countryId);
+ if (locale != m_locale) {
+ m_locale = locale;
+ emit localeChanged(locale);
+ }
+
+#ifdef QBBVIRTUALKEYBOARD_DEBUG
+ qDebug() << "QBB: handleKeyboardInfoMessage size=" << m_height << "locale=" << m_locale;
+#endif
+}
+
+void QBBVirtualKeyboard::handleKeyboardStateChangeMessage(bool visible)
+{
+
+#ifdef QBBVIRTUALKEYBOARD_DEBUG
+ qDebug() << "QBB: handleKeyboardStateChangeMessage " << visible;
+#endif
+ updateAvailableScreenGeometry();
+
+ if (visible)
+ showKeyboard();
+ else
+ hideKeyboard();
+}
+
+void QBBVirtualKeyboard::updateAvailableScreenGeometry()
+{
+#ifdef QBBVIRTUALKEYBOARD_DEBUG
+ qDebug() << "QBB: updateAvailableScreenGeometry: keyboard visible=" << m_visible << ", keyboard height=" << m_height;
+#endif
+
+ // TODO: What screen index should be used? I assume primaryScreen here because it works, and
+ // we do it for handleScreenGeometryChange elsewhere but since we have support
+ // for more than one screen, that's not going to always work.
+ QBBScreen *platformScreen = QBBScreen::primaryDisplay();
+ QWindowSystemInterface::handleScreenAvailableGeometryChange(platformScreen->screen(), platformScreen->availableGeometry());
+}
+
+bool QBBVirtualKeyboard::showKeyboard()
+{
+#ifdef QBBVIRTUALKEYBOARD_DEBUG
+ qDebug() << "QBB: showKeyboard()";
+#endif
+
+ // Try to connect.
+ if (m_fd == -1 && !connect())
+ return false;
+
+ // NOTE: This must be done everytime the keyboard is shown even if there is no change because
+ // hiding the keyboard wipes the setting.
+ applyKeyboardModeOptions();
+
+ pps_encoder_reset(m_encoder);
+
+ // Send the show message.
+ pps_encoder_add_string(m_encoder, "msg", "show");
+
+ if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) {
+ close();
+ return false;
+ }
+
+ pps_encoder_reset(m_encoder);
+
+ // Return true if no error occurs. Sizing response will be triggered when confirmation of
+ // the change arrives.
+ return true;
+}
+
+bool QBBVirtualKeyboard::hideKeyboard()
+{
+#ifdef QBBVIRTUALKEYBOARD_DEBUG
+ qDebug() << "QBB: hideKeyboard()";
+#endif
+
+ if (m_fd == -1 && !connect())
+ return false;
+
+ pps_encoder_add_string(m_encoder, "msg", "hide");
+
+ if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) {
+ close();
+
+ //Try again.
+ if (connect()) {
+ if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) {
+ close();
+ return false;
+ }
+ }
+ else
+ return false;
+ }
+
+ pps_encoder_reset(m_encoder);
+
+ // Return true if no error occurs. Sizing response will be triggered when confirmation of
+ // the change arrives.
+ return true;
+}
+
+void QBBVirtualKeyboard::setKeyboardMode(KeyboardMode mode)
+{
+ m_keyboardMode = mode;
+}
+
+void QBBVirtualKeyboard::applyKeyboardModeOptions()
+{
+ // Try to connect.
+ if (m_fd == -1 && !connect())
+ return;
+
+ // Send the options message.
+ pps_encoder_add_string(m_encoder, "msg", "options");
+
+ pps_encoder_start_object(m_encoder, "dat");
+ switch (m_keyboardMode) {
+ case Url:
+ addUrlModeOptions();
+ break;
+ case Email:
+ addEmailModeOptions();
+ break;
+ case Web:
+ addWebModeOptions();
+ break;
+ case NumPunc:
+ addNumPuncModeOptions();
+ break;
+ case Symbol:
+ addSymbolModeOptions();
+ break;
+ case Phone:
+ addPhoneModeOptions();
+ break;
+ case Pin:
+ addPinModeOptions();
+ break;
+ case Default:
+ default:
+ addDefaultModeOptions();
+ break;
+ }
+
+ pps_encoder_end_object(m_encoder);
+
+ if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) {
+ close();
+ }
+
+ pps_encoder_reset(m_encoder);
+}
+
+void QBBVirtualKeyboard::addDefaultModeOptions()
+{
+ pps_encoder_add_string(m_encoder, "enter", "enter.default");
+ pps_encoder_add_string(m_encoder, "type", "default");
+}
+
+void QBBVirtualKeyboard::addUrlModeOptions()
+{
+ pps_encoder_add_string(m_encoder, "enter", "enter.default");
+ pps_encoder_add_string(m_encoder, "type", "url");
+}
+
+void QBBVirtualKeyboard::addEmailModeOptions()
+{
+ pps_encoder_add_string(m_encoder, "enter", "enter.default");
+ pps_encoder_add_string(m_encoder, "type", "email");
+}
+
+void QBBVirtualKeyboard::addWebModeOptions()
+{
+ pps_encoder_add_string(m_encoder, "enter", "enter.default");
+ pps_encoder_add_string(m_encoder, "type", "web");
+}
+
+void QBBVirtualKeyboard::addNumPuncModeOptions()
+{
+ pps_encoder_add_string(m_encoder, "enter", "enter.default");
+ pps_encoder_add_string(m_encoder, "type", "numPunc");
+}
+
+void QBBVirtualKeyboard::addPhoneModeOptions()
+{
+ pps_encoder_add_string(m_encoder, "enter", "enter.default");
+ pps_encoder_add_string(m_encoder, "type", "phone");
+}
+
+void QBBVirtualKeyboard::addPinModeOptions()
+{
+ pps_encoder_add_string(m_encoder, "enter", "enter.default");
+ pps_encoder_add_string(m_encoder, "type", "pin");
+}
+
+void QBBVirtualKeyboard::addSymbolModeOptions()
+{
+ pps_encoder_add_string(m_encoder, "enter", "enter.default");
+ pps_encoder_add_string(m_encoder, "type", "symbol");
+}
diff --git a/src/plugins/platforms/blackberry/qbbvirtualkeyboard.h b/src/plugins/platforms/blackberry/qbbvirtualkeyboard.h
new file mode 100644
index 0000000000..14003ee897
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbvirtualkeyboard.h
@@ -0,0 +1,130 @@
+/***************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef VIRTUALKEYBOARD_H_
+#define VIRTUALKEYBOARD_H_
+
+#include <QtCore/QThread>
+#include <QtCore/QLocale>
+#include <QtGui/QPlatformScreen>
+#include <QtGui/QWindowSystemInterface>
+
+#include <stddef.h>
+#include <vector>
+#include <string>
+#include <sys/pps.h>
+
+QT_BEGIN_NAMESPACE
+
+/* Shamelessly copied from the browser - this should be rewritten once we have a proper PPS wrapper class */
+class QBBVirtualKeyboard : public QThread
+{
+ Q_OBJECT
+public:
+ // NOTE: Not all the following keyboard modes are currently used.
+ // Default - Regular Keyboard
+ // Url/Email - Enhanced keys for each types.
+ // Web - Regular keyboard with two blank keys, currently unused.
+ // NumPunc - Numbers & Punctionation, alternate to Symbol
+ // Symbol - All symbols, alternate to NumPunc, currently unused.
+ // Phone - Phone enhanced keyboard - currently unused as no alternate keyboard available to access a-zA-Z
+ // Pin - Keyboard for entering Pins (Hex values) currently unused.
+ //
+ // SPECIAL NOTE: Usage of NumPunc may have to be removed, ABC button is non-functional.
+ //
+ enum KeyboardMode { Default, Url, Email, Web, NumPunc, Symbol, Phone, Pin };
+
+ static QBBVirtualKeyboard& instance();
+ static void destroy();
+
+ bool showKeyboard();
+ bool hideKeyboard();
+ int height() { return m_visible ? m_height : 0; }
+ void setKeyboardMode(KeyboardMode);
+ void notifyClientActiveStateChange(bool);
+ bool isVisible() const { return m_visible; }
+ QLocale locale() const { return m_locale; }
+
+Q_SIGNALS:
+ void localeChanged(const QLocale &locale);
+ void visibilityChanged(bool visible);
+
+private:
+ QBBVirtualKeyboard();
+ virtual ~QBBVirtualKeyboard();
+
+ // Will be called internally if needed.
+ bool connect();
+ void close();
+ void ppsDataReady();
+ bool queryPPSInfo();
+ void handleKeyboardInfoMessage();
+ void handleKeyboardStateChangeMessage(bool visible);
+ void updateAvailableScreenGeometry();
+
+ void applyKeyboardModeOptions();
+ void addDefaultModeOptions();
+ void addUrlModeOptions();
+ void addEmailModeOptions();
+ void addWebModeOptions();
+ void addNumPuncModeOptions();
+ void addSymbolModeOptions();
+ void addPhoneModeOptions();
+ void addPinModeOptions();
+
+ // QThread overrides
+ virtual void run();
+
+ pps_encoder_t *m_encoder;
+ pps_decoder_t *m_decoder;
+ char *m_buffer;
+ int m_height;
+ int m_fd;
+ KeyboardMode m_keyboardMode;
+ bool m_visible;
+ QLocale m_locale;
+
+ // Path to keyboardManager in PPS.
+ static const char *ms_PPSPath;
+ static const size_t ms_bufferSize;
+};
+
+#endif /* VIRTUALKEYBOARD_H_ */
diff --git a/src/plugins/platforms/blackberry/qbbwindow.cpp b/src/plugins/platforms/blackberry/qbbwindow.cpp
new file mode 100644
index 0000000000..bc9f112b01
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbwindow.cpp
@@ -0,0 +1,665 @@
+/***************************************************************************
+**
+** 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 "qbbwindow.h"
+#include "qbbglcontext.h"
+#include "qbbintegration.h"
+#include "qbbscreen.h"
+
+#include <QtGui/QWindow>
+#include <QtGui/QWindowSystemInterface>
+
+#include <QtCore/QDebug>
+
+#include <errno.h>
+
+QT_BEGIN_NAMESPACE
+
+QBBWindow::QBBWindow(QWindow *window, screen_context_t context)
+ : QPlatformWindow(window),
+ m_screenContext(context),
+ m_window(0),
+ m_currentBufferIndex(-1),
+ m_previousBufferIndex(-1),
+ m_platformOpenGLContext(0),
+ m_screen(0),
+ m_parentWindow(0),
+ m_visible(true)
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window << ", size =" << window->size();
+#endif
+ int result;
+
+ // Create child QNX window
+ errno = 0;
+ result = screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to create window, errno=%d", errno);
+ }
+
+ // Set window buffer usage based on rendering API
+ int val;
+ QSurface::SurfaceType surfaceType = window->surfaceType();
+ switch (surfaceType) {
+ case QSurface::RasterSurface:
+ val = SCREEN_USAGE_NATIVE | SCREEN_USAGE_READ | SCREEN_USAGE_WRITE;
+ break;
+ case QSurface::OpenGLSurface:
+ val = SCREEN_USAGE_OPENGL_ES2;
+ break;
+ default:
+ qFatal("QBBWindow: unsupported window API");
+ break;
+ }
+
+ errno = 0;
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_USAGE, &val);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to set window buffer usage, errno=%d", errno);
+ }
+
+ // Alpha channel is always pre-multiplied if present
+ errno = 0;
+ val = SCREEN_PRE_MULTIPLIED_ALPHA;
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ALPHA_MODE, &val);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to set window alpha mode, errno=%d", errno);
+ }
+
+ // Make the window opaque
+ errno = 0;
+ val = SCREEN_TRANSPARENCY_NONE;
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_TRANSPARENCY, &val);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to set window transparency, errno=%d", errno);
+ }
+
+ // Set the window swap interval
+ errno = 0;
+ val = 1;
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SWAP_INTERVAL, &val);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to set window swap interval, errno=%d", errno);
+ }
+
+ // Assign the window to the primary display (this is the default specified by screen).
+ setScreen(QBBScreen::primaryDisplay());
+
+ // Add the window to the root of the hierarchy
+ QBBScreen::addWindow(this);
+
+ // Add window to plugin's window mapper
+ QBBIntegration::addWindow(m_window, window);
+}
+
+QBBWindow::~QBBWindow()
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window();
+#endif
+ // Remove from plugin's window mapper
+ QBBIntegration::removeWindow(m_window);
+
+ // Remove from parent's Hierarchy.
+ removeFromParent();
+ QBBScreen::updateHierarchy();
+
+ // We shouldn't allow this case unless QT allows it. Does it? Or should we send the
+ // handleCloseEvent on all children when this window is deleted?
+ if (m_childWindows.size() > 0)
+ qFatal("QBBWindow: window destroyed before children!");
+
+ // Cleanup QNX window and its buffers
+ screen_destroy_window(m_window);
+}
+
+void QBBWindow::setGeometry(const QRect &rect)
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window() << ", (" << rect.x() << "," << rect.y() << "," << rect.width() << "," << rect.height() << ")";
+#endif
+
+ QRect oldGeometry = geometry();
+
+ // Call base class method
+ QPlatformWindow::setGeometry(rect);
+
+ // Set window geometry equal to widget geometry
+ errno = 0;
+ int val[2];
+ val[0] = rect.x();
+ val[1] = rect.y();
+ int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, val);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to set window position, errno=%d", errno);
+ }
+
+ errno = 0;
+ val[0] = rect.width();
+ val[1] = rect.height();
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to set window size, errno=%d", errno);
+ }
+
+ // Set viewport size equal to window size
+ errno = 0;
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to set window source size, errno=%d", errno);
+ }
+
+ // Now move all children.
+ QPoint offset;
+ if (!oldGeometry.isEmpty()) {
+ offset = rect.topLeft();
+ offset -= oldGeometry.topLeft();
+
+ QList<QBBWindow*>::iterator it;
+ for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) {
+ (*it)->offset(offset);
+ }
+ }
+}
+
+void QBBWindow::offset(const QPoint &offset)
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window();
+#endif
+ // Move self and then children.
+ QRect newGeometry = geometry();
+ newGeometry.translate(offset);
+
+ // Call the base class
+ QPlatformWindow::setGeometry(newGeometry);
+
+ int val[2];
+
+ errno = 0;
+ val[0] = newGeometry.x();
+ val[1] = newGeometry.y();
+ int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, val);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to set window position, errno=%d", errno);
+ }
+
+ QList<QBBWindow*>::iterator it;
+ for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) {
+ (*it)->offset(offset);
+ }
+}
+
+void QBBWindow::setVisible(bool visible)
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window() << "visible =" << visible;
+#endif
+
+ m_visible = visible;
+
+ QBBWindow *root = this;
+ while (root->m_parentWindow)
+ root = root->m_parentWindow;
+
+ root->updateVisibility(root->m_visible);
+
+ window()->requestActivateWindow();
+}
+
+void QBBWindow::updateVisibility(bool parentVisible)
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "parentVisible =" << parentVisible << "window =" << window();
+#endif
+ // Set window visibility
+ errno = 0;
+ int val = (m_visible && parentVisible) ? 1 : 0;
+ int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_VISIBLE, &val);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to set window visibility, errno=%d", errno);
+ }
+
+ QList<QBBWindow *>::iterator it;
+ for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) {
+ (*it)->updateVisibility(m_visible && parentVisible);
+ }
+}
+
+void QBBWindow::setOpacity(qreal level)
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window() << "opacity =" << level;
+#endif
+ // Set window global alpha
+ errno = 0;
+ int val = (int)(level * 255);
+ int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_GLOBAL_ALPHA, &val);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to set window global alpha, errno=%d", errno);
+ }
+
+ // TODO: How to handle children of this window? If we change all the visibilities, then
+ // the transparency will look wrong...
+}
+
+void QBBWindow::setBufferSize(const QSize &size)
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window() << "size =" << size;
+#endif
+ // Set window buffer size
+ errno = 0;
+ int val[2] = { size.width(), size.height() };
+ int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BUFFER_SIZE, val);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to set window buffer size, errno=%d", errno);
+ }
+
+ // Create window buffers if they do not exist
+ if (!hasBuffers()) {
+ // Get pixel format from EGL config if using OpenGL;
+ // otherwise inherit pixel format of window's screen
+ if (m_platformOpenGLContext != 0) {
+ val[0] = platformWindowFormatToNativeFormat(m_platformOpenGLContext->format());
+ } else {
+ val[0] = m_screen->nativeFormat();
+ }
+
+ errno = 0;
+ result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, val);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to set window pixel format, errno=%d", errno);
+ }
+
+ errno = 0;
+ result = screen_create_window_buffers(m_window, MAX_BUFFER_COUNT);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to create window buffers, errno=%d", errno);
+ }
+ }
+
+ // Cache new buffer size
+ m_bufferSize = size;
+
+ // Buffers were destroyed; reacquire them
+ m_currentBufferIndex = -1;
+ m_previousDirty = QRegion();
+ m_scrolled = QRegion();
+}
+
+QBBBuffer &QBBWindow::renderBuffer()
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window();
+#endif
+ // Check if render buffer is invalid
+ if (m_currentBufferIndex == -1) {
+ // Get all buffers available for rendering
+ errno = 0;
+ screen_buffer_t buffers[MAX_BUFFER_COUNT];
+ int result = screen_get_window_property_pv(m_window, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)buffers);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to query window buffers, errno=%d", errno);
+ }
+
+ // Wrap each buffer
+ for (int i = 0; i < MAX_BUFFER_COUNT; ++i) {
+ m_buffers[i] = QBBBuffer(buffers[i]);
+ }
+
+ // Use the first available render buffer
+ m_currentBufferIndex = 0;
+ m_previousBufferIndex = -1;
+ }
+
+ return m_buffers[m_currentBufferIndex];
+}
+
+void QBBWindow::scroll(const QRegion &region, int dx, int dy, bool flush)
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window();
+#endif
+ copyBack(region, dx, dy, flush);
+ m_scrolled += region;
+}
+
+void QBBWindow::post(const QRegion &dirty)
+{
+ // Check if render buffer exists and something was rendered
+ if (m_currentBufferIndex != -1 && !dirty.isEmpty()) {
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << "QBBWindow::post - window =" << window();
+#endif
+ QBBBuffer &currentBuffer = m_buffers[m_currentBufferIndex];
+
+ // Copy unmodified region from old render buffer to new render buffer;
+ // required to allow partial updates
+ QRegion preserve = m_previousDirty - dirty - m_scrolled;
+ copyBack(preserve, 0, 0);
+
+ // Calculate region that changed
+ QRegion modified = preserve + dirty + m_scrolled;
+ QRect rect = modified.boundingRect();
+ int dirtyRect[4] = { rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height() };
+
+ // Update the display with contents of render buffer
+ errno = 0;
+ int result = screen_post_window(m_window, currentBuffer.nativeBuffer(), 1, dirtyRect, 0);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to post window buffer, errno=%d", errno);
+ }
+
+ // Advance to next nender buffer
+ m_previousBufferIndex = m_currentBufferIndex++;
+ if (m_currentBufferIndex >= MAX_BUFFER_COUNT) {
+ m_currentBufferIndex = 0;
+ }
+
+ // Save modified region and clear scrolled region
+ m_previousDirty = dirty;
+ m_scrolled = QRegion();
+
+ // Notify screen that window posted
+ if (m_screen != 0) {
+ m_screen->onWindowPost(this);
+ }
+ }
+}
+
+void QBBWindow::setScreen(QBBScreen *platformScreen)
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window() << "platformScreen =" << platformScreen;
+#endif
+
+ if (m_screen == platformScreen)
+ return;
+
+ m_screen = platformScreen;
+
+ // Move window to proper screen/display
+ errno = 0;
+ screen_display_t display = platformScreen->nativeDisplay();
+ int result = screen_set_window_property_pv(m_window, SCREEN_PROPERTY_DISPLAY, (void **)&display);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to set window display, errno=%d", errno);
+ }
+
+ // Add window to display's window group
+ errno = 0;
+ result = screen_join_window_group(m_window, platformScreen->windowGroupName());
+ if (result != 0) {
+ qFatal("QBBWindow: failed to join window group, errno=%d", errno);
+ }
+
+ QList<QBBWindow*>::iterator it;
+ for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) {
+ // Only subwindows and tooltips need necessarily be moved to another display with the window.
+ if ((window()->windowType() & Qt::WindowType_Mask) == Qt::SubWindow ||
+ (window()->windowType() & Qt::WindowType_Mask) == Qt::ToolTip)
+ (*it)->setScreen(platformScreen);
+ }
+
+ QBBScreen::updateHierarchy();
+}
+
+void QBBWindow::removeFromParent()
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window();
+#endif
+ // Remove from old Hierarchy position
+ if (m_parentWindow) {
+ if (m_parentWindow->m_childWindows.removeAll(this))
+ m_parentWindow = 0;
+ else
+ qFatal("QBBWindow: Window Hierarchy broken; window has parent, but parent hasn't got child.");
+ } else {
+ QBBScreen::removeWindow(this);
+ }
+}
+
+void QBBWindow::setParent(const QPlatformWindow *window)
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << this->window() << "platformWindow =" << window;
+#endif
+ // Cast away the const, we need to modify the hierarchy.
+ QBBWindow *newParent = 0;
+
+ if (window)
+ newParent = static_cast<QBBWindow*>((QPlatformWindow *)window);
+
+ if (newParent == m_parentWindow)
+ return;
+
+ removeFromParent();
+ m_parentWindow = newParent;
+
+ // Add to new hierarchy position.
+ if (m_parentWindow) {
+ if (m_parentWindow->m_screen != m_screen)
+ setScreen(m_parentWindow->m_screen);
+
+ m_parentWindow->m_childWindows.push_back(this);
+ } else {
+ QBBScreen::addWindow(this);
+ }
+
+ QBBScreen::updateHierarchy();
+}
+
+void QBBWindow::raise()
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window();
+#endif
+
+ QBBWindow *oldParent = m_parentWindow;
+ if (oldParent) {
+ removeFromParent();
+ oldParent->m_childWindows.push_back(this);
+ } else {
+ QBBScreen::raiseWindow(this);
+ }
+
+ QBBScreen::updateHierarchy();
+}
+
+void QBBWindow::lower()
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window();
+#endif
+
+ QBBWindow *oldParent = m_parentWindow;
+ if (oldParent) {
+ removeFromParent();
+ oldParent->m_childWindows.push_front(this);
+ } else {
+ QBBScreen::lowerWindow(this);
+ }
+
+ QBBScreen::updateHierarchy();
+}
+
+void QBBWindow::requestActivateWindow()
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window();
+#endif
+
+ // TODO: Tell screen to set keyboard focus to this window.
+
+ // Notify that we gained focus.
+ gainedFocus();
+}
+
+void QBBWindow::gainedFocus()
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window();
+#endif
+
+ // Got focus
+ QWindowSystemInterface::handleWindowActivated(window());
+}
+
+void QBBWindow::setPlatformOpenGLContext(QBBGLContext *platformOpenGLContext)
+{
+ // This function does not take ownership of the platform gl context.
+ // It is owned by the frontend QOpenGLContext
+ m_platformOpenGLContext = platformOpenGLContext;
+}
+
+void QBBWindow::updateZorder(int &topZorder)
+{
+ errno = 0;
+ int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ZORDER, &topZorder);
+ topZorder++;
+
+ if (result != 0)
+ qFatal("QBBWindow: failed to set window z-order=%d, errno=%d, mWindow=%p", topZorder, errno, m_window);
+
+ QList<QBBWindow*>::const_iterator it;
+
+ for (it = m_childWindows.begin(); it != m_childWindows.end(); it++)
+ (*it)->updateZorder(topZorder);
+}
+
+void QBBWindow::copyBack(const QRegion &region, int dx, int dy, bool flush)
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO << "window =" << window();
+#endif
+ int result;
+
+ // Abort if previous buffer is invalid
+ if (m_previousBufferIndex == -1) {
+ return;
+ }
+
+ // Abort if nothing to copy
+ if (region.isEmpty()) {
+ return;
+ }
+
+ QBBBuffer &currentBuffer = m_buffers[m_currentBufferIndex];
+ QBBBuffer &previousBuffer = m_buffers[m_previousBufferIndex];
+
+ // Break down region into non-overlapping rectangles
+ QVector<QRect> rects = region.rects();
+ for (int i = rects.size() - 1; i >= 0; i--) {
+ // Clip rectangle to bounds of target
+ QRect rect = rects[i].intersected( currentBuffer.rect() );
+
+ if (rect.isEmpty())
+ continue;
+
+ // Setup blit operation
+ int attribs[] = { SCREEN_BLIT_SOURCE_X, rect.x(),
+ SCREEN_BLIT_SOURCE_Y, rect.y(),
+ SCREEN_BLIT_SOURCE_WIDTH, rect.width(),
+ SCREEN_BLIT_SOURCE_HEIGHT, rect.height(),
+ SCREEN_BLIT_DESTINATION_X, rect.x() + dx,
+ SCREEN_BLIT_DESTINATION_Y, rect.y() + dy,
+ SCREEN_BLIT_DESTINATION_WIDTH, rect.width(),
+ SCREEN_BLIT_DESTINATION_HEIGHT, rect.height(),
+ SCREEN_BLIT_END };
+
+ // Queue blit operation
+ errno = 0;
+ result = screen_blit(m_screenContext, currentBuffer.nativeBuffer(), previousBuffer.nativeBuffer(), attribs);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to blit buffers, errno=%d", errno);
+ }
+ }
+
+ // Check if flush requested
+ if (flush) {
+ // Wait for all blits to complete
+ errno = 0;
+ result = screen_flush_blits(m_screenContext, SCREEN_WAIT_IDLE);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to flush blits, errno=%d", errno);
+ }
+
+ // Buffer was modified outside the CPU
+ currentBuffer.invalidateInCache();
+ }
+}
+
+int QBBWindow::platformWindowFormatToNativeFormat(const QSurfaceFormat &format)
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << Q_FUNC_INFO;
+#endif
+ // Extract size of colour channels from window format
+ int redSize = format.redBufferSize();
+ if (redSize == -1) {
+ qFatal("QBBWindow: red size not defined");
+ }
+
+ int greenSize = format.greenBufferSize();
+ if (greenSize == -1) {
+ qFatal("QBBWindow: green size not defined");
+ }
+
+ int blueSize = format.blueBufferSize();
+ if (blueSize == -1) {
+ qFatal("QBBWindow: blue size not defined");
+ }
+
+ // select matching native format
+ if (redSize == 5 && greenSize == 6 && blueSize == 5) {
+ return SCREEN_FORMAT_RGB565;
+ } else if (redSize == 8 && greenSize == 8 && blueSize == 8) {
+ return SCREEN_FORMAT_RGBA8888;
+ } else {
+ qFatal("QBBWindow: unsupported pixel format");
+ return 0;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/blackberry/qbbwindow.h b/src/plugins/platforms/blackberry/qbbwindow.h
new file mode 100644
index 0000000000..ffdeba423a
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbwindow.h
@@ -0,0 +1,133 @@
+/***************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QBBWINDOW_H
+#define QBBWINDOW_H
+
+#include <QtGui/QPlatformWindow>
+
+#include "qbbbuffer.h"
+
+#include <QtGui/QImage>
+
+#include <EGL/egl.h>
+
+#include <screen/screen.h>
+
+QT_BEGIN_NAMESPACE
+
+// all surfaces double buffered
+#define MAX_BUFFER_COUNT 2
+
+class QBBGLContext;
+class QBBScreen;
+
+class QPlatformGLContext;
+class QSurfaceFormat;
+
+class QBBWindow : public QPlatformWindow
+{
+friend class QBBScreen;
+public:
+ QBBWindow(QWindow *window, screen_context_t context);
+ virtual ~QBBWindow();
+
+ virtual void setGeometry(const QRect &rect);
+ virtual void setVisible(bool visible);
+ virtual void setOpacity(qreal level);
+
+ virtual WId winId() const { return (WId)m_window; }
+ screen_window_t nativeHandle() const { return m_window; }
+
+ void setBufferSize(const QSize &size);
+ QSize bufferSize() const { return m_bufferSize; }
+ bool hasBuffers() const { return !m_bufferSize.isEmpty(); }
+
+ QBBBuffer &renderBuffer();
+ void scroll(const QRegion &region, int dx, int dy, bool flush=false);
+ void post(const QRegion &dirty);
+
+ void setScreen(QBBScreen *platformScreen);
+
+ virtual void setParent(const QPlatformWindow *window);
+ virtual void raise();
+ virtual void lower();
+ virtual void requestActivateWindow();
+
+ void gainedFocus();
+
+ QBBScreen *screen() const { return m_screen; }
+ const QList<QBBWindow*>& children() const { return m_childWindows; }
+
+ void setPlatformOpenGLContext(QBBGLContext *platformOpenGLContext);
+ QBBGLContext *platformOpenGLContext() const { return m_platformOpenGLContext; }
+
+private:
+ void removeFromParent();
+ void offset(const QPoint &offset);
+ void updateVisibility(bool parentVisible);
+ void updateZorder(int &topZorder);
+
+ void fetchBuffers();
+
+ void copyBack(const QRegion &region, int dx, int dy, bool flush=false);
+
+ static int platformWindowFormatToNativeFormat(const QSurfaceFormat &format);
+
+ screen_context_t m_screenContext;
+ screen_window_t m_window;
+ QSize m_bufferSize;
+ QBBBuffer m_buffers[MAX_BUFFER_COUNT];
+ int m_currentBufferIndex;
+ int m_previousBufferIndex;
+ QRegion m_previousDirty;
+ QRegion m_scrolled;
+
+ QBBGLContext *m_platformOpenGLContext;
+ QBBScreen *m_screen;
+ QList<QBBWindow*> m_childWindows;
+ QBBWindow *m_parentWindow;
+ bool m_visible;
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBWINDOW_H
diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro
index c2e6d8cea7..8f728a5fb0 100644
--- a/src/plugins/platforms/platforms.pro
+++ b/src/plugins/platforms/platforms.pro
@@ -11,3 +11,7 @@ mac {
}
win32: SUBDIRS += windows
+
+blackberry-armv7le-qcc {
+ SUBDIRS += blackberry
+}