summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael Roquetto <rafael.roquetto@kdab.com>2012-02-07 19:01:40 (GMT)
committerQt by Nokia <qt-info@nokia.com>2012-02-21 06:37:02 (GMT)
commitc87445a2b75264e633d2f358534109ee8ca27ca9 (patch)
tree207e679057de4868b38021f41a11fc7e77aac3f6
parentae39f2286b6fb5ddc63223bab4b3fab3736b4ee8 (diff)
downloadQt-c87445a2b75264e633d2f358534109ee8ca27ca9.zip
Qt-c87445a2b75264e633d2f358534109ee8ca27ca9.tar.gz
Qt-c87445a2b75264e633d2f358534109ee8ca27ca9.tar.bz2
Initial import of the BlackBerry Playbook QPA plugin.
Change-Id: Ibc883be9af145eafef2e5ff9eb82c3364bace331 Reviewed-by: Sean Harmer <sh@theharmers.co.uk> Reviewed-by: Jørgen Lind <jorgen.lind@nokia.com>
-rw-r--r--src/plugins/platforms/blackberry/blackberry.pro44
-rw-r--r--src/plugins/platforms/blackberry/main.cpp71
-rw-r--r--src/plugins/platforms/blackberry/qbbbuffer.cpp166
-rw-r--r--src/plugins/platforms/blackberry/qbbbuffer.h72
-rw-r--r--src/plugins/platforms/blackberry/qbbclipboard.cpp128
-rw-r--r--src/plugins/platforms/blackberry/qbbclipboard.h64
-rw-r--r--src/plugins/platforms/blackberry/qbbeventthread.cpp613
-rw-r--r--src/plugins/platforms/blackberry/qbbeventthread.h87
-rw-r--r--src/plugins/platforms/blackberry/qbbglcontext.cpp366
-rw-r--r--src/plugins/platforms/blackberry/qbbglcontext.h90
-rw-r--r--src/plugins/platforms/blackberry/qbbglwindowsurface.cpp161
-rw-r--r--src/plugins/platforms/blackberry/qbbglwindowsurface.h90
-rw-r--r--src/plugins/platforms/blackberry/qbbinputcontext.cpp45
-rw-r--r--src/plugins/platforms/blackberry/qbbinputcontext.h44
-rw-r--r--src/plugins/platforms/blackberry/qbbinputcontext_imf.cpp1659
-rw-r--r--src/plugins/platforms/blackberry/qbbinputcontext_imf.h117
-rw-r--r--src/plugins/platforms/blackberry/qbbinputcontext_noimf.cpp101
-rw-r--r--src/plugins/platforms/blackberry/qbbinputcontext_noimf.h68
-rw-r--r--src/plugins/platforms/blackberry/qbbintegration.cpp221
-rw-r--r--src/plugins/platforms/blackberry/qbbintegration.h88
-rw-r--r--src/plugins/platforms/blackberry/qbbkeytranslator.h266
-rw-r--r--src/plugins/platforms/blackberry/qbblocalethread.cpp137
-rw-r--r--src/plugins/platforms/blackberry/qbblocalethread.h69
-rw-r--r--src/plugins/platforms/blackberry/qbbnavigatorthread.cpp271
-rw-r--r--src/plugins/platforms/blackberry/qbbnavigatorthread.h71
-rw-r--r--src/plugins/platforms/blackberry/qbbrasterwindowsurface.cpp169
-rw-r--r--src/plugins/platforms/blackberry/qbbrasterwindowsurface.h79
-rw-r--r--src/plugins/platforms/blackberry/qbbscreen.cpp516
-rw-r--r--src/plugins/platforms/blackberry/qbbscreen.h115
-rw-r--r--src/plugins/platforms/blackberry/qbbvirtualkeyboard.cpp475
-rw-r--r--src/plugins/platforms/blackberry/qbbvirtualkeyboard.h124
-rw-r--r--src/plugins/platforms/blackberry/qbbwindow.cpp669
-rw-r--r--src/plugins/platforms/blackberry/qbbwindow.h125
33 files changed, 7381 insertions, 0 deletions
diff --git a/src/plugins/platforms/blackberry/blackberry.pro b/src/plugins/platforms/blackberry/blackberry.pro
new file mode 100644
index 0000000..0d3cf43
--- /dev/null
+++ b/src/plugins/platforms/blackberry/blackberry.pro
@@ -0,0 +1,44 @@
+TARGET = blackberry
+include(../../qpluginbase.pri)
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms
+QT += opengl
+
+SOURCES = main.cpp \
+ qbbbuffer.cpp \
+ qbbeventthread.cpp \
+ qbbglcontext.cpp \
+ qbbglwindowsurface.cpp \
+ qbbinputcontext.cpp \
+ qbbintegration.cpp \
+ qbbnavigatorthread.cpp \
+ qbbscreen.cpp \
+ qbbwindow.cpp \
+ qbbrasterwindowsurface.cpp \
+ qbbvirtualkeyboard.cpp \
+ qbbclipboard.cpp \
+ qbblocalethread.cpp
+
+HEADERS = qbbbuffer.h \
+ qbbeventthread.h \
+ qbbinputcontext.h \
+ qbbintegration.h \
+ qbbnavigatorthread.h \
+ qbbglcontext.h \
+ qbbglwindowsurface.h \
+ qbbscreen.h \
+ qbbwindow.h \
+ qbbrasterwindowsurface.h \
+ qbbvirtualkeyboard.h \
+ qbbclipboard.h \
+ qbblocalethread.h
+
+QMAKE_CXXFLAGS += -I./private
+
+LIBS += -lpps -lscreen -lEGL -lclipboard
+
+include (../eglconvenience/eglconvenience.pri)
+include (../fontdatabases/genericunix/genericunix.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 0000000..ff0baaa
--- /dev/null
+++ b/src/plugins/platforms/blackberry/main.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $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 << "blackberry";
+ return list;
+}
+
+QPlatformIntegration *QBBIntegrationPlugin::create(const QString& system, const QStringList& paramList)
+{
+ Q_UNUSED(paramList);
+ if (system.toLower() == "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 0000000..00476da
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbbuffer.cpp
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QBBBUFFER_DEBUG
+
+
+#include "qbbbuffer.h"
+
+#include <QDebug>
+
+#include <errno.h>
+#include <sys/mman.h>
+
+QT_BEGIN_NAMESPACE
+
+QBBBuffer::QBBBuffer()
+ : mBuffer(NULL)
+{
+#if defined(QBBBUFFER_DEBUG)
+ qDebug() << "QBBBuffer::QBBBuffer - empty";
+#endif
+}
+
+QBBBuffer::QBBBuffer(screen_buffer_t buffer)
+ : mBuffer(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 = NULL;
+ 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
+ mImage = QImage(dataPtr, size[0], size[1], stride, imageFormat);
+}
+
+QBBBuffer::QBBBuffer(const QBBBuffer &other)
+ : mBuffer(other.mBuffer),
+ mImage(other.mImage)
+{
+#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 (mBuffer == NULL) {
+ qFatal("QBB: can't invalidate cache for null buffer");
+ }
+
+ // evict buffer's data from cache
+ errno = 0;
+ int result = msync(mImage.bits(), mImage.height() * mImage.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 0000000..70c7ee8
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbbuffer.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBBBUFFER_H
+#define QBBBUFFER_H
+
+#include <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 mBuffer; }
+ const QImage *image() const { return (mBuffer != NULL) ? &mImage : NULL; }
+ QImage *image() { return (mBuffer != NULL) ? &mImage : NULL; }
+
+ QRect rect() const { return mImage.rect(); }
+
+ void invalidateInCache();
+
+private:
+ screen_buffer_t mBuffer;
+ QImage mImage;
+};
+
+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 0000000..3f7d2d5
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbclipboard.cpp
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// #define QBBCLIPBOARD_DEBUG
+
+#ifndef QT_NO_CLIPBOARD
+
+#include "qbbclipboard.h"
+#include <QUrl>
+#include <QStringList>
+#include <QColor>
+#include <QDebug>
+
+#include <clipboard/clipboard.h>
+#include <errno.h>
+
+QT_BEGIN_NAMESPACE
+static const char *typeList[] = {"text/html", "text/plain", "application/x-color"};
+
+QBBClipboard::QBBClipboard()
+{
+ mMimeData = 0;
+}
+
+QBBClipboard::~QBBClipboard()
+{
+ delete mMimeData;
+}
+
+void QBBClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
+{
+ if (mode != QClipboard::Clipboard)
+ return;
+
+ if (mMimeData != data) {
+ delete mMimeData;
+ mMimeData = 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;
+#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
+ mMimeData->setData(qtype, QByteArray(pbuffer, size));
+ delete pbuffer;
+ }
+ }
+}
+
+QMimeData* QBBClipboard::mimeData(QClipboard::Mode mode)
+{
+ if (mode != QClipboard::Clipboard)
+ return 0;
+
+ if (!mMimeData)
+ mMimeData = new QMimeData();
+
+ mMimeData->clear();
+
+ for (int i = 0; i < 3; i++)
+ readClipboardBuff(typeList[i]);
+
+ return mMimeData;
+}
+
+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 0000000..1241bf0
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbclipboard.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $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 *mMimeData;
+ void readClipboardBuff(const char *type);
+};
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_CLIPBOAR
+#endif //QBBCLIPBOARD_H
diff --git a/src/plugins/platforms/blackberry/qbbeventthread.cpp b/src/plugins/platforms/blackberry/qbbeventthread.cpp
new file mode 100644
index 0000000..29dc9a7
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbeventthread.cpp
@@ -0,0 +1,613 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// #define QBBEVENTTHREAD_DEBUG
+
+#include "qbbeventthread.h"
+#include "qbbinputcontext.h"
+#include "qbbkeytranslator.h"
+
+#include <QtGui/QWidget>
+#include <QtGui/QPlatformScreen>
+#include <QtGui/QApplication>
+#include <QDebug>
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/keycodes.h>
+
+#include <cctype>
+
+QBBEventThread::QBBEventThread(screen_context_t context, QPlatformScreen& screen)
+ : mContext(context),
+ mScreen(screen),
+ mQuit(false),
+ mLastButtonState(Qt::NoButton),
+ mLastMouseWindow(0)
+{
+ // initialize array of touch points
+ for (int i = 0; i < MAX_TOUCH_POINTS; i++) {
+
+ // map array index to id
+ mTouchPoints[i].id = i;
+
+ // first finger is primary
+ mTouchPoints[i].isPrimary = (i == 0);
+
+ // pressure is not supported - use default
+ mTouchPoints[i].pressure = 1.0;
+
+ // nothing touching
+ mTouchPoints[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 (!mQuit) {
+
+ // block until screen event is available
+ errno = 0;
+ result = screen_get_event(mContext, 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(mContext, 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
+ mQuit = 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);
+ }
+
+ // Let the input context have a stab at it first.
+ QWidget *focusWidget = QApplication::focusWidget();
+ if (focusWidget) {
+ QInputContext* inputContext = focusWidget->inputContext();
+ if (inputContext) {
+ QBBInputContext *qbbInputContext = dynamic_cast<QBBInputContext *>(inputContext);
+
+ if (qbbInputContext && qbbInputContext->handleKeyboardEvent(flags, sym, modifiers, scan, cap))
+ return;
+ }
+ }
+
+ 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(QApplication::activeWindow(), type, key, qtMod, keyStr);
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: Qt key t=" << type << ", k=" << key << ", s=" << keyStr;
+#endif
+ }
+}
+
+void QBBEventThread::injectPointerMoveEvent(int x, int y)
+{
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "Injecting mouse event..." << x << y;
+#endif
+
+ QWidget *w = qApp->topLevelAt(x, y);
+ void *qnxWindow = w ? w->platformWindow() : 0;
+
+ // Generate enter and leave events as needed.
+ if (qnxWindow != mLastMouseWindow) {
+ QWidget* wOld = QWidget::find( (WId)mLastMouseWindow );
+
+ 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
+ }
+ }
+
+ mLastMouseWindow = qnxWindow;
+
+ // convert point to local coordinates
+ QPoint globalPoint(x, y);
+ QPoint localPoint(x, y);
+
+ if (w)
+ localPoint = QPoint(x - w->x(), y - w->y());
+
+ // Convert buttons.
+ Qt::MouseButtons buttons = mLastButtonState;
+
+ if (w) {
+ // Inject mouse event into Qt only if something has changed.
+ if (mLastGlobalMousePoint != globalPoint ||
+ mLastLocalMousePoint != localPoint ||
+ mLastButtonState != buttons) {
+ QWindowSystemInterface::handleMouseEvent(w, localPoint, globalPoint, buttons);
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: Qt mouse, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), b=" << (int)buttons;
+#endif
+ }
+ }
+
+ mLastGlobalMousePoint = globalPoint;
+ mLastLocalMousePoint = localPoint;
+ mLastButtonState = buttons;
+}
+
+void QBBEventThread::handlePointerEvent(screen_event_t event)
+{
+ errno = 0;
+
+ // Query the window that was clicked
+ void *qnxWindow;
+ int result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &qnxWindow);
+ if (result) {
+ qFatal("QBB: failed to query event window, errno=%d", errno);
+ }
+
+ // 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 to top-level widget
+ QWidget* w = QWidget::find( (WId)qnxWindow );
+
+ // Generate enter and leave events as needed.
+ if (qnxWindow != mLastMouseWindow) {
+ QWidget* wOld = QWidget::find( (WId)mLastMouseWindow );
+
+ 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
+ }
+ }
+ mLastMouseWindow = 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 (mLastGlobalMousePoint != globalPoint ||
+ mLastLocalMousePoint != localPoint ||
+ mLastButtonState != buttons) {
+ QWindowSystemInterface::handleMouseEvent(w, localPoint, globalPoint, buttons);
+#if defined(QBBEVENTTHREAD_DEBUG)
+ qDebug() << "QBB: Qt mouse, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), b=" << (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=" << (int)wheelDelta;
+#endif
+ }
+ }
+
+ mLastGlobalMousePoint = globalPoint;
+ mLastLocalMousePoint = localPoint;
+ mLastButtonState = 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 *qnxWindow;
+ result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &qnxWindow);
+ if (result) {
+ qFatal("QBB: failed to query event window, errno=%d", errno);
+ }
+
+ // check if finger is valid
+ if (touchId < MAX_TOUCH_POINTS) {
+
+ // map window to top-level widget
+ QWidget* w = QWidget::find( (WId)qnxWindow );
+
+ // Generate enter and leave events as needed.
+ if (qnxWindow != mLastMouseWindow) {
+ QWidget* wOld = QWidget::find( (WId)mLastMouseWindow );
+
+ 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
+ }
+ }
+ mLastMouseWindow = 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::platformScreenForWidget(w);
+ QSize screenSize = platformScreen->physicalSize();
+
+ // update cached position of current touch point
+ mTouchPoints[touchId].normalPosition = QPointF( ((qreal)pos[0]) / screenSize.width(), ((qreal)pos[1]) / screenSize.height() );
+ mTouchPoints[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:
+ mTouchPoints[touchId].state = Qt::TouchPointPressed;
+ type = QEvent::TouchBegin;
+ break;
+ case SCREEN_EVENT_MTOUCH_MOVE:
+ mTouchPoints[touchId].state = Qt::TouchPointMoved;
+ type = QEvent::TouchUpdate;
+ break;
+ case SCREEN_EVENT_MTOUCH_RELEASE:
+ mTouchPoints[touchId].state = Qt::TouchPointReleased;
+ type = QEvent::TouchEnd;
+ break;
+ }
+
+ // build list of active touch points
+ QList<QWindowSystemInterface::TouchPoint> pointList;
+ for (int i = 0; i < MAX_TOUCH_POINTS; i++) {
+ if (i == touchId) {
+ // current touch point is always active
+ pointList.append(mTouchPoints[i]);
+ } else if (mTouchPoints[i].state != Qt::TouchPointReleased) {
+ // finger is down but did not move
+ mTouchPoints[i].state = Qt::TouchPointStationary;
+ pointList.append(mTouchPoints[i]);
+ }
+ }
+
+ // inject event into Qt
+ QWindowSystemInterface::handleTouchEvent(w, type, QTouchEvent::TouchScreen, 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 *qnxWindow;
+ int result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &qnxWindow);
+ if (result != 0) {
+ qFatal("QBB: failed to query event window, errno=%d", errno);
+ }
+
+ // map window to top-level widget
+ QWidget* w = QWidget::find( (WId)qnxWindow );
+ if (w != NULL) {
+ QWindowSystemInterface::handleCloseEvent(w);
+ }
+}
+
diff --git a/src/plugins/platforms/blackberry/qbbeventthread.h b/src/plugins/platforms/blackberry/qbbeventthread.h
new file mode 100644
index 0000000..a4557fe
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbeventthread.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBBEVENTTHREAD_H
+#define QBBEVENTTHREAD_H
+
+#include <QtGui/QPlatformScreen>
+#include <QtGui/QWindowSystemInterface>
+#include <QThread>
+
+#include <screen/screen.h>
+
+QT_BEGIN_NAMESPACE
+
+// an arbitrary number
+#define MAX_TOUCH_POINTS 10
+
+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);
+ void injectPointerMoveEvent(int x, int y);
+
+protected:
+ virtual void run();
+
+private:
+ screen_context_t mContext;
+ QPlatformScreen& mScreen;
+ bool mQuit;
+ QPoint mLastGlobalMousePoint;
+ QPoint mLastLocalMousePoint;
+ Qt::MouseButtons mLastButtonState;
+ void* mLastMouseWindow;
+
+ QWindowSystemInterface::TouchPoint mTouchPoints[MAX_TOUCH_POINTS];
+
+ 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);
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBEVENTTHREAD_H
diff --git a/src/plugins/platforms/blackberry/qbbglcontext.cpp b/src/plugins/platforms/blackberry/qbbglcontext.cpp
new file mode 100644
index 0000000..ff61970
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbglcontext.cpp
@@ -0,0 +1,366 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QBBGLCONTEXT_DEBUG
+
+
+#include "qbbglcontext.h"
+#include "qbbscreen.h"
+#include "qbbwindow.h"
+#include "../eglconvenience/qeglconvenience.h"
+
+#include <QtGui/QWidget>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+EGLDisplay QBBGLContext::sEglDisplay = EGL_NO_DISPLAY;
+EGLConfig QBBGLContext::sEglConfig = 0;
+QPlatformWindowFormat QBBGLContext::sWindowFormat;
+
+QBBGLContext::QBBGLContext(QBBWindow* platformWindow)
+ : QPlatformGLContext(),
+ mPlatformWindow(platformWindow),
+ mEglSurface(EGL_NO_SURFACE)
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << "QBBGLContext::QBBGLContext - w=" << mPlatformWindow->widget();
+#endif
+
+ // verify rendering API is correct
+ QPlatformWindowFormat format = mPlatformWindow->widget()->platformWindowFormat();
+ if (format.windowApi() != QPlatformWindowFormat::OpenGL) {
+ qFatal("QBB: window API is not OpenGL");
+ }
+
+ // 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
+ int depth = platformWindow->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
+ sEglConfig = q_configFromQPlatformWindowFormat(sEglDisplay, format);
+ if (sEglConfig == 0) {
+ qFatal("QBB: failed to find EGL config");
+ }
+
+ mEglContext = eglCreateContext(sEglDisplay, sEglConfig, EGL_NO_CONTEXT, contextAttrs());
+ if (mEglContext == EGL_NO_CONTEXT) {
+ qFatal("QBB: failed to create EGL context, err=%d", eglGetError());
+ }
+
+ // query/cache window format of selected EGL config
+ sWindowFormat = qt_qPlatformWindowFormatFromConfig(sEglDisplay, sEglConfig);
+}
+
+QBBGLContext::~QBBGLContext()
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << "QBBGLContext::~QBBGLContext - w=" << mPlatformWindow->widget();
+#endif
+
+ // cleanup EGL context if it exists
+ if (mEglContext != EGL_NO_CONTEXT) {
+ eglDestroyContext(sEglDisplay, mEglContext);
+ }
+
+ // cleanup EGL surface if it exists
+ destroySurface();
+}
+
+void QBBGLContext::initialize()
+{
+ // initialize connection to EGL
+ sEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (sEglDisplay == EGL_NO_DISPLAY) {
+ qFatal("QBB: failed to obtain EGL display");
+ }
+
+ EGLBoolean eglResult = eglInitialize(sEglDisplay, NULL, NULL);
+ if (eglResult != EGL_TRUE) {
+ qFatal("QBB: failed to initialize EGL display, err=%d", eglGetError());
+ }
+
+ // choose EGL settings based on OpenGL version
+#if defined(QT_OPENGL_ES_2)
+ EGLint renderableType = EGL_OPENGL_ES2_BIT;
+#else
+ EGLint renderableType = EGL_OPENGL_ES_BIT;
+#endif
+
+ // get EGL config compatible with window
+ EGLint numConfig;
+ EGLint configAttrs[] = { EGL_BUFFER_SIZE, 32,
+ EGL_ALPHA_SIZE, 8,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, renderableType,
+ EGL_NONE };
+ eglResult = eglChooseConfig(sEglDisplay, configAttrs, &sEglConfig, 1, &numConfig);
+ if (eglResult != EGL_TRUE || numConfig == 0) {
+ qFatal("QBB: failed to find EGL config, err=%d, numConfig=%d", eglGetError(), numConfig);
+ }
+
+ // query/cache window format
+ sWindowFormat = qt_qPlatformWindowFormatFromConfig(sEglDisplay, sEglConfig);
+ sWindowFormat.setWindowApi(QPlatformWindowFormat::OpenGL);
+}
+
+void QBBGLContext::shutdown()
+{
+ // close connection to EGL
+ eglTerminate(sEglDisplay);
+}
+
+void QBBGLContext::makeCurrent()
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << "QBBGLContext::makeCurrent - w=" << mPlatformWindow->widget();
+#endif
+
+ if (!mPlatformWindow->hasBuffers()) {
+ // NOTE: create a dummy EGL surface since Qt will call makeCurrent() before
+ // setting the geometry on the associated window
+ mSurfaceSize = QSize(1, 1);
+ mPlatformWindow->setBufferSize(mSurfaceSize);
+ createSurface();
+ }
+
+ // call the parent method
+ QPlatformGLContext::makeCurrent();
+
+ // 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());
+ }
+
+ // set current EGL context and bind with EGL surface
+ eglResult = eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext);
+ if (eglResult != EGL_TRUE) {
+ qFatal("QBB: failed to set current EGL context, err=%d", eglGetError());
+ }
+}
+
+void QBBGLContext::doneCurrent()
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << "QBBGLContext::doneCurrent - w=" << mPlatformWindow->widget();
+#endif
+
+ // call the parent method
+ QPlatformGLContext::doneCurrent();
+
+ // 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(sEglDisplay, 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()
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << "QBBGLContext::swapBuffers - w=" << mPlatformWindow->widget();
+#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(sEglDisplay, mEglSurface);
+ if (eglResult != EGL_TRUE) {
+ qFatal("QBB: failed to swap EGL buffers, err=%d", eglGetError());
+ }
+
+ // resize surface if window was resized
+ QSize s = mPlatformWindow->geometry().size();
+ if (s != mSurfaceSize) {
+ resizeSurface(s);
+ }
+}
+
+void* QBBGLContext::getProcAddress(const QString& procName)
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << "QBBGLContext::getProcAddress - w=" << mPlatformWindow->widget();
+#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 (void *)eglGetProcAddress( procName.toAscii().constData() );
+}
+
+void QBBGLContext::resizeSurface(const QSize &size)
+{
+ // need to destroy surface so make sure its not current
+ bool restoreCurrent = false;
+ if (isCurrent()) {
+ doneCurrent();
+ restoreCurrent = true;
+ }
+
+ // destroy old EGL surface
+ destroySurface();
+
+ // resize window's buffers
+ mPlatformWindow->setBufferSize(size);
+
+ // re-create EGL surface with new size
+ mSurfaceSize = size;
+ createSurface();
+
+ // make context current again
+ if (restoreCurrent) {
+ makeCurrent();
+ }
+}
+
+EGLint *QBBGLContext::contextAttrs()
+{
+ // 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 NULL;
+#endif
+}
+
+bool QBBGLContext::isCurrent() const
+{
+ return (eglGetCurrentContext() == mEglContext);
+}
+
+void QBBGLContext::createSurface()
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << "QBBGLContext::createSurface - w=" << mPlatformWindow->widget();
+#endif
+
+ // create EGL surface
+ mEglSurface = eglCreateWindowSurface(sEglDisplay, sEglConfig, (EGLNativeWindowType)mPlatformWindow->winId(), NULL);
+ if (mEglSurface == EGL_NO_SURFACE) {
+ qFatal("QBB: failed to create EGL surface, err=%d", eglGetError());
+ }
+}
+
+void QBBGLContext::destroySurface()
+{
+#if defined(QBBGLCONTEXT_DEBUG)
+ qDebug() << "QBBGLContext::destroySurface - w=" << mPlatformWindow->widget();
+#endif
+
+ // destroy EGL surface if it exists
+ if (mEglSurface != EGL_NO_SURFACE) {
+ EGLBoolean eglResult = eglDestroySurface(sEglDisplay, mEglSurface);
+ 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 0000000..80d4c53
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbglcontext.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBBGLCONTEXT_H
+#define QBBGLCONTEXT_H
+
+#include <QtGui/QPlatformGLContext>
+#include <QtGui/QPlatformWindowFormat>
+#include <QSize>
+
+#include <EGL/egl.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBBWindow;
+
+class QBBGLContext : public QPlatformGLContext
+{
+public:
+ QBBGLContext(QBBWindow* platformWindow);
+ virtual ~QBBGLContext();
+
+ static void initialize();
+ static void shutdown();
+
+ virtual void makeCurrent();
+ virtual void doneCurrent();
+ virtual void swapBuffers();
+ virtual void* getProcAddress(const QString& procName);
+
+ virtual QPlatformWindowFormat platformWindowFormat() const { return sWindowFormat; }
+
+ void resizeSurface(const QSize &size);
+ QSize surfaceSize() const { return mSurfaceSize; }
+
+private:
+ static EGLDisplay sEglDisplay;
+ static EGLConfig sEglConfig;
+ static QPlatformWindowFormat sWindowFormat;
+
+ QBBWindow *mPlatformWindow;
+ EGLContext mEglContext;
+ EGLSurface mEglSurface;
+ QSize mSurfaceSize;
+
+ static EGLint *contextAttrs();
+ bool isCurrent() const;
+ void createSurface();
+ void destroySurface();
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBGLCONTEXT_H
diff --git a/src/plugins/platforms/blackberry/qbbglwindowsurface.cpp b/src/plugins/platforms/blackberry/qbbglwindowsurface.cpp
new file mode 100644
index 0000000..b5a7083
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbglwindowsurface.cpp
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QBBGLWINDOWSURFACE_DEBUG
+
+
+#include "qbbglwindowsurface.h"
+#include "qbbglcontext.h"
+#include "qbbwindow.h"
+
+#include <QtGui/QWidget>
+#include <QtOpenGL/private/qgl_p.h>
+#include <QGLContext>
+#include <QDebug>
+
+#include <errno.h>
+
+QT_BEGIN_NAMESPACE
+
+QBBGLPaintDevice::QBBGLPaintDevice(QBBGLContext* platformGlContext)
+ : mPlatformGlContext(platformGlContext)
+{
+ // create GL context from platform GL context
+ mGlContext = QGLContext::fromPlatformGLContext(mPlatformGlContext);
+}
+
+QBBGLPaintDevice::~QBBGLPaintDevice()
+{
+ // cleanup GL context
+ delete mGlContext;
+}
+
+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 mPlatformGlContext->surfaceSize();
+}
+
+QBBGLWindowSurface::QBBGLWindowSurface(QWidget *window)
+ : QWindowSurface(window)
+{
+#if defined(QBBGLWINDOWSURFACE_DEBUG)
+ qDebug() << "QBBGLWindowSurface::QBBGLWindowSurface - w=" << window;
+#endif
+
+ // extract GL context associated with window
+ mPlatformGlContext = static_cast<QBBGLContext*>(window->platformWindow()->glContext());
+
+ // create an OpenGL paint device
+ mPaintDevice = new QBBGLPaintDevice(mPlatformGlContext);
+}
+
+QBBGLWindowSurface::~QBBGLWindowSurface()
+{
+#if defined(QBBGLWINDOWSURFACE_DEBUG)
+ qDebug() << "QBBGLWindowSurface::~QBBGLWindowSurface - w=" << window();
+#endif
+
+ // cleanup OpenGL paint device
+ delete mPaintDevice;
+}
+
+void QBBGLWindowSurface::flush(QWidget *widget, const QRegion &region, const QPoint &offset)
+{
+ Q_UNUSED(widget);
+ Q_UNUSED(region);
+ Q_UNUSED(offset);
+
+#if defined(QBBGLWINDOWSURFACE_DEBUG)
+ qDebug() << "QBBGLWindowSurface::flush - w=" << window();
+#endif
+
+ // update the display with newly rendered content
+ mPlatformGlContext->swapBuffers();
+}
+
+void QBBGLWindowSurface::resize(const QSize &size)
+{
+#if defined(QBBGLWINDOWSURFACE_DEBUG)
+ qDebug() << "QBBGLWindowSurface::resize - w=" << window() << ", s=" << size;
+#endif
+
+ // call parent method
+ QWindowSurface::resize(size);
+
+ // NOTE: defer resizing window buffers until next paint as
+ // resize() can be called multiple times before a paint occurs
+}
+
+void QBBGLWindowSurface::beginPaint(const QRegion &region)
+{
+ Q_UNUSED(region);
+
+#if defined(QBBGLWINDOWSURFACE_DEBUG)
+ qDebug() << "QBBGLWindowSurface::beginPaint - w=" << window();
+#endif
+
+ // resize EGL surface if window surface resized
+ QSize s = size();
+ if (s != mPlatformGlContext->surfaceSize()) {
+ mPlatformGlContext->resizeSurface(s);
+ }
+}
+
+void QBBGLWindowSurface::endPaint(const QRegion &region)
+{
+ Q_UNUSED(region);
+#if defined(QBBGLWINDOWSURFACE_DEBUG)
+ qDebug() << "QBBGLWindowSurface::endPaint - w=" << window();
+#endif
+}
+
+QWindowSurface::WindowSurfaceFeatures QBBGLWindowSurface::features() const
+{
+ // force full frame updates on every paint
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/blackberry/qbbglwindowsurface.h b/src/plugins/platforms/blackberry/qbbglwindowsurface.h
new file mode 100644
index 0000000..5546432
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbglwindowsurface.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBBGLWINDOWSURFACE_H
+#define QBBGLWINDOWSURFACE_H
+
+#include <QtGui/private/qwindowsurface_p.h>
+#include <QtOpenGL/private/qglpaintdevice_p.h>
+
+#include <screen/screen.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGLContext;
+class QBBGLContext;
+class QBBWindow;
+
+class QBBGLPaintDevice : public QGLPaintDevice
+{
+public:
+ QBBGLPaintDevice(QBBGLContext* platformGlContext);
+ virtual ~QBBGLPaintDevice();
+
+ virtual QPaintEngine *paintEngine() const;
+ virtual QSize size() const;
+ virtual QGLContext *context() const { return mGlContext; }
+
+private:
+ QBBGLContext* mPlatformGlContext;
+ QGLContext *mGlContext;
+};
+
+class QBBGLWindowSurface : public QWindowSurface
+{
+public:
+ QBBGLWindowSurface(QWidget *window);
+ virtual ~QBBGLWindowSurface();
+
+ virtual QPaintDevice *paintDevice() { return mPaintDevice; }
+ virtual void flush(QWidget *widget, const QRegion &region, const QPoint &offset);
+ virtual void resize(const QSize &size);
+ virtual void beginPaint(const QRegion &region);
+ virtual void endPaint(const QRegion &region);
+
+ virtual QWindowSurface::WindowSurfaceFeatures features() const;
+
+private:
+ QBBGLContext* mPlatformGlContext;
+ QBBGLPaintDevice* mPaintDevice;
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBGLWINDOWSURFACE_H
diff --git a/src/plugins/platforms/blackberry/qbbinputcontext.cpp b/src/plugins/platforms/blackberry/qbbinputcontext.cpp
new file mode 100644
index 0000000..a7c98f1
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbinputcontext.cpp
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifdef QBB_IMF
+#include "qbbinputcontext_imf.cpp"
+#else
+#include "qbbinputcontext_noimf.cpp"
+#endif
+
diff --git a/src/plugins/platforms/blackberry/qbbinputcontext.h b/src/plugins/platforms/blackberry/qbbinputcontext.h
new file mode 100644
index 0000000..9845f1c
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbinputcontext.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBB_IMF
+#include "qbbinputcontext_noimf.h"
+#else
+#include "qbbinputcontext_imf.h"
+#endif
diff --git a/src/plugins/platforms/blackberry/qbbinputcontext_imf.cpp b/src/plugins/platforms/blackberry/qbbinputcontext_imf.cpp
new file mode 100644
index 0000000..95a0441
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbinputcontext_imf.cpp
@@ -0,0 +1,1659 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+/* TODO
+ * Support inputMethodHints to restrict input (needs additional features in IMF).
+*/
+
+// #define QBBINPUTCONTEXT_DEBUG
+// #define QBBINPUTCONTEXT_IMF_EVENT_DEBUG
+
+#define STRX(x) #x
+#define STR(x) STRX(x)
+#define TAG __FILE__ "(" STR(__LINE__) ")" << __func__ << ":"
+
+#include <qbbeventthread.h>
+#include <qbbinputcontext.h>
+#include <qbbvirtualkeyboard.h>
+
+#include <QAction>
+#include <QCoreApplication>
+#include <QDebug>
+#include <QInputMethodEvent>
+#include <QMutex>
+#include <QTextCharFormat>
+#include <QVariant>
+#include <QVariantHash>
+#include <QWaitCondition>
+
+#include <dlfcn.h>
+#include "imf/imf_client.h"
+#include "imf/input_control.h"
+#include <process.h>
+#include <sys/keycodes.h>
+
+// 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(QString const& 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()
+ {
+ mMutex.lock();
+ }
+
+ ~ImfEventResult()
+ {
+ mMutex.unlock();
+ }
+
+ void wait()
+ {
+ mWait.wait(&mMutex);
+ }
+
+ void signal()
+ {
+ mWait.wakeAll();
+ }
+
+ void setResult(QVariant const& result)
+ {
+ mMutex.lock();
+ mRetVal = result;
+ signal();
+ mMutex.unlock();
+ }
+
+ QVariant& getResult()
+ {
+ return mRetVal;
+ }
+
+private:
+ QVariant mRetVal;
+ QMutex mMutex;
+ QWaitCondition mWait;
+};
+
+class ImfEvent : public QEvent
+{
+ public:
+ ImfEvent(input_session_t* session, ImfEventType type, ImfEventResult* result) :
+ QEvent((QEvent::Type)sUserEventType),
+ mSession(session),
+ mImfType(type),
+ mResult(result)
+ {
+ }
+ ~ImfEvent() { }
+
+ input_session_t* mSession;
+ ImfEventType mImfType;
+ QVariantHash mArgs;
+ ImfEventResult *mResult;
+
+ static int sUserEventType;
+};
+int ImfEvent::sUserEventType = QEvent::registerEventType();
+
+static int32_t imfBeginBatchEdit(input_session_t* ic)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << TAG;
+#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.getResult().toInt();
+
+ return ret;
+}
+
+static int32_t imfClearMetaKeyStates(input_session_t* ic, int32_t states)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << TAG;
+#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.getResult().toInt();
+
+ 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() << TAG;
+#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.getResult().toInt();
+
+ 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() << TAG;
+#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.getResult().toInt();
+
+ return ret;
+}
+
+static int32_t imfEndBatchEdit(input_session_t* ic)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << TAG;
+#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.getResult().toInt();
+
+ return ret;
+}
+
+static int32_t imfFinishComposingText(input_session_t* ic)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << TAG;
+#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.getResult().toInt();
+
+ return ret;
+}
+
+static int32_t imfGetCursorCapsMode(input_session_t* ic, int32_t req_modes)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << TAG;
+#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.getResult().value<int>();
+ return ret;
+}
+
+static int32_t imfGetCursorPosition(input_session_t* ic)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << TAG;
+#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.getResult().toInt();
+
+ 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() << TAG;
+#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();
+ void* ret = result.getResult().value<void*>();
+ return (extracted_text_t*)ret;
+}
+
+static spannable_string_t* imfGetSelectedText(input_session_t* ic, int32_t flags)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << TAG;
+#endif
+
+ if (!isSessionOkay(ic))
+ return toSpannableString("");
+
+ ImfEventResult result;
+ ImfEvent* event = new ImfEvent(ic, ImfGetSelectedText, &result);
+ iarg(flags);
+
+ QCoreApplication::postEvent(QCoreApplication::instance(), event);
+
+ result.wait();
+ void* ret = result.getResult().value<void*>();
+ return (spannable_string_t*)ret;
+}
+
+static spannable_string_t* imfGetTextAfterCursor(input_session_t* ic, int32_t n, int32_t flags)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << TAG;
+#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();
+ void* ret = result.getResult().value<void*>();
+ return (spannable_string_t*)ret;
+}
+
+static spannable_string_t* imfGetTextBeforeCursor(input_session_t* ic, int32_t n, int32_t flags)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << TAG;
+#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();
+ void* ret = result.getResult().value<void*>();
+ return (spannable_string_t*)ret;
+}
+
+static int32_t imfPerformEditorAction(input_session_t* ic, int32_t editor_action)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << TAG;
+#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.getResult().value<int>();
+ return ret;
+}
+
+static int32_t imfReportFullscreenMode(input_session_t* ic, int32_t enabled)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << TAG;
+#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.getResult().value<int>();
+ return ret;
+}
+
+static int32_t imfSendEvent(input_session_t* ic, event_t * event)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << TAG;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ ImfEvent* imfEvent = new ImfEvent(ic, ImfSendEvent, 0);
+ imfEvent->mArgs[qs("event")] = QVariant::fromValue((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() << TAG;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ ImfEvent* imfEvent = new ImfEvent(ic, ImfSendAsyncEvent, 0);
+ imfEvent->mArgs[qs("event")] = QVariant::fromValue((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() << TAG;
+#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.getResult().value<int>();
+ 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() << TAG;
+#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.getResult().value<int>();
+ return ret;
+}
+
+static int32_t imfSetSelection(input_session_t* ic, int32_t start, int32_t end)
+{
+#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
+ qDebug() << TAG;
+#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.getResult().value<int>();
+ 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(QString const& text)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG << text;
+#endif
+
+ spannable_string_t *pString = (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;
+
+ QChar const* 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() << TAG << "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() << TAG << "libinput_client.so.1 did not contain the correct symbols, library mismatch? IMF services are disabled.";
+ return false;
+ }
+ }
+
+ return s_imfReady;
+}
+
+QBBInputContext::QBBInputContext(QObject* parent):
+ QInputContext(parent),
+ mLastCaretPos(0),
+ mIsComposing(false)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#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();
+}
+
+QBBInputContext::~QBBInputContext()
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#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::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->mImfType) {
+ case ImfBeginBatchEdit:
+ {
+ int32_t ret = onBeginBatchEdit(imfEvent->mSession);
+ imfEvent->mResult->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfClearMetaKeyStates:
+ {
+ getarg(int32_t, states);
+ int32_t ret = onClearMetaKeyStates(imfEvent->mSession, states);
+ imfEvent->mResult->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfCommitText:
+ {
+ getparg(spannable_string_t*, text);
+ getarg(int32_t, new_cursor_position);
+ int32_t ret = onCommitText(imfEvent->mSession, text, new_cursor_position);
+ imfEvent->mResult->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfDeleteSurroundingText:
+ {
+ getarg(int32_t, left_length);
+ getarg(int32_t, right_length);
+ int32_t ret = onDeleteSurroundingText(imfEvent->mSession, left_length, right_length);
+ imfEvent->mResult->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfEndBatchEdit:
+ {
+ int32_t ret = onEndBatchEdit(imfEvent->mSession);
+ imfEvent->mResult->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfFinishComposingText:
+ {
+ int32_t ret = onFinishComposingText(imfEvent->mSession);
+ imfEvent->mResult->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfGetCursorCapsMode:
+ {
+ getarg(int32_t, req_modes);
+ int32_t ret = onGetCursorCapsMode(imfEvent->mSession, req_modes);
+ imfEvent->mResult->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfGetCursorPosition:
+ {
+ int32_t ret = onGetCursorPosition(imfEvent->mSession);
+ imfEvent->mResult->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfGetExtractedText:
+ {
+ getparg(extracted_text_request_t*, request);
+ getarg(int32_t, flags);
+ extracted_text_t* ret = onGetExtractedText(imfEvent->mSession, request, flags);
+ imfEvent->mResult->setResult(QVariant::fromValue((void*)ret));
+ break;
+ }
+
+ case ImfGetSelectedText:
+ {
+ getarg(int32_t, flags);
+ spannable_string_t* ret = onGetSelectedText(imfEvent->mSession, flags);
+ imfEvent->mResult->setResult(QVariant::fromValue((void*)ret));
+ break;
+ }
+
+ case ImfGetTextAfterCursor:
+ {
+ getarg(int32_t, n);
+ getarg(int32_t, flags);
+ spannable_string_t* ret = onGetTextAfterCursor(imfEvent->mSession, n, flags);
+ imfEvent->mResult->setResult(QVariant::fromValue((void*)ret));
+ break;
+ }
+
+ case ImfGetTextBeforeCursor:
+ {
+ getarg(int32_t, n);
+ getarg(int32_t, flags);
+ spannable_string_t* ret = onGetTextBeforeCursor(imfEvent->mSession, n, flags);
+ imfEvent->mResult->setResult(QVariant::fromValue((void*)ret));
+ break;
+ }
+
+ case ImfPerformEditorAction:
+ {
+ getarg(int32_t, editor_action);
+ int32_t ret = onPerformEditorAction(imfEvent->mSession, editor_action);
+ imfEvent->mResult->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfReportFullscreenMode:
+ {
+ getarg(int32_t, enabled);
+ int32_t ret = onReportFullscreenMode(imfEvent->mSession, enabled);
+ imfEvent->mResult->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfSendEvent:
+ {
+ getparg(event_t*, event);
+ onSendEvent(imfEvent->mSession, event);
+ break;
+ }
+
+ case ImfSendAsyncEvent:
+ {
+ getparg(event_t*, event);
+ onSendAsyncEvent(imfEvent->mSession, event);
+ break;
+ }
+
+ case ImfSetComposingRegion:
+ {
+ getarg(int32_t, start);
+ getarg(int32_t, end);
+ int32_t ret = onSetComposingRegion(imfEvent->mSession, start, end);
+ imfEvent->mResult->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfSetComposingText:
+ {
+ getparg(spannable_string_t*, text);
+ getarg(int32_t, new_cursor_position);
+ int32_t ret = onSetComposingText(imfEvent->mSession, text, new_cursor_position);
+ imfEvent->mResult->setResult(QVariant::fromValue(ret));
+ break;
+ }
+
+ case ImfSetSelection:
+ {
+ getarg(int32_t, start);
+ getarg(int32_t, end);
+ int32_t ret = onSetSelection(imfEvent->mSession, start, end);
+ imfEvent->mResult->setResult(QVariant::fromValue(ret));
+ break;
+ }
+ }; //switch
+
+ return true;
+ } else {
+ // standard event processing
+ return QObject::eventFilter(obj, event);
+ }
+}
+
+QString QBBInputContext::identifierName()
+{
+ return tr("PlayBook IMF");
+}
+
+QString QBBInputContext::language()
+{
+ return QBBVirtualKeyboard::instance().languageId();
+}
+
+bool QBBInputContext::filterEvent( const QEvent *event )
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG << event;
+#endif
+
+ switch (event->type()) {
+ case QEvent::CloseSoftwareInputPanel: {
+ return dispatchCloseSoftwareInputPanel();
+ }
+ case QEvent::RequestSoftwareInputPanel: {
+ return dispatchRequestSoftwareInputPanel();
+ }
+ default:
+ return false;
+ }
+}
+
+QList<QAction *> QBBInputContext::actions()
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#endif
+ return QInputContext::actions();
+}
+
+QFont QBBInputContext::font() const
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#endif
+ return QInputContext::font();
+}
+
+bool QBBInputContext::isComposing() const
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#endif
+ return mIsComposing;
+}
+
+void QBBInputContext::mouseHandler(int x, QMouseEvent * event)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#endif
+ return QInputContext::mouseHandler(x, event);
+}
+
+void QBBInputContext::reset()
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#endif
+
+ endComposition();
+}
+
+void QBBInputContext::setFocusWidget(QWidget * widget)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#endif
+
+ if (hasSession()) {
+ endComposition();
+ dispatchFocusEvent(FOCUS_LOST);
+ closeSession();
+ }
+
+ // Update the widget before moving on.
+ QInputContext::setFocusWidget(widget);
+
+ // If we have hidden text, or any flags that restrict input (exclusive flags), then we just disable
+ // imf for this field.
+ if (widget != 0 && !(widget->inputMethodHints() & Qt::ImhHiddenText) && !(widget->inputMethodHints() >= Qt::ImhDigitsOnly && widget->inputMethodHints() <= Qt::ImhUrlCharactersOnly))
+ {
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG << "Starting input session for " << widget;
+#endif
+ openSession();
+ dispatchFocusEvent(FOCUS_GAINED, widget->inputMethodHints());
+ }
+}
+
+void QBBInputContext::update()
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#endif
+
+ reset();
+
+ QInputContext::update();
+}
+
+void QBBInputContext::widgetDestroyed(QWidget * widget)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#endif
+ QInputContext::widgetDestroyed(widget);
+}
+
+void QBBInputContext::closeSession()
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;;
+#endif
+
+ if (!imfAvailable())
+ return;
+
+ if (sInputSession) {
+ p_ictrl_close_session((input_session_t *)sInputSession);
+ sInputSession = 0;
+ }
+}
+
+void QBBInputContext::openSession()
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;;
+#endif
+
+ if (!imfAvailable())
+ return;
+
+ closeSession();
+ sInputSession = p_ictrl_open_session(&ic_funcs);
+}
+
+bool QBBInputContext::hasSession()
+{
+ return sInputSession != 0;
+}
+
+bool QBBInputContext::hasSelectedText()
+{
+ if (focusWidget()) {
+ return focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt() != focusWidget()->inputMethodQuery(Qt::ImAnchorPosition).toInt();
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool QBBInputContext::dispatchRequestSoftwareInputPanel()
+{
+ QBBVirtualKeyboard::instance().showKeyboard();
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << "QBB: requesting virtual keyboard";
+#endif
+
+ if (!imfAvailable() || !focusWidget())
+ return true;
+
+ // This also means that the caret position has moved
+ int caretPos = focusWidget()->inputMethodQuery(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 = mLastCaretPos;
+ mLastCaretPos = 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() << TAG;
+#endif
+
+ if (!sInputSession) {
+ qWarning() << TAG << "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.
+ mLastCaretPos = 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() << TAG << "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() << TAG << "dispatch key event " << key;
+#endif
+ }
+
+ scan = 0;
+ return true;
+}
+
+void QBBInputContext::endComposition()
+{
+ if (!imfAvailable())
+ return;
+
+ if (!isComposing())
+ return;
+
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event(QLatin1String(""), attributes);
+ event.setCommitString(mComposingText);
+ mComposingText = QString();
+ mIsComposing = false;
+ sendEvent(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)
+{
+ mComposingText = composingText;
+ mIsComposing = true;
+
+ QList<QInputMethodEvent::Attribute> attributes;
+ QTextCharFormat format;
+ format.setFontUnderline(true);
+ attributes.push_back(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, composingText.length(), format));
+
+ QInputMethodEvent event(composingText, attributes);
+
+ sendEvent(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() << TAG << "EVENT_SPELL_CHECK";
+ #endif
+ result = 0;
+ break;
+ }
+
+ case EVENT_NAVIGATION: {
+ #if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG << "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() << TAG << "EVENT_KEY";
+ #endif
+ key_event_t* kevent = (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() << TAG << "Unsupported event type: " << event->event_type;
+ break;
+ default:
+ qCritical() << TAG << "Unknown event type: " << event->event_type;
+ }
+ return result;
+}
+
+/*
+ * IMF Event Handlers
+ */
+
+int32_t QBBInputContext::onBeginBatchEdit(input_session_t* ic)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#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() << TAG;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ // Should never get called.
+ qCritical() << TAG << "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;
+
+ QString commitString = QString::fromWCharArray(text->str, text->length);
+
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG << "Committing [" << commitString << "]";
+#endif
+
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event(QLatin1String(""), attributes);
+ event.setCommitString(commitString, 0, 0);
+
+ sendEvent(event);
+ mComposingText = QString();
+
+ return 0;
+}
+
+int32_t QBBInputContext::onDeleteSurroundingText(input_session_t* ic, int32_t left_length, int32_t right_length)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG << "L:" << left_length << " R:" << right_length;
+#endif
+
+ if (!isSessionOkay(ic))
+ 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);
+ sendEvent(event);
+
+ return 0;
+}
+
+int32_t QBBInputContext::onEndBatchEdit(input_session_t* ic)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ return 0;
+}
+
+int32_t QBBInputContext::onFinishComposingText(input_session_t* ic)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#endif
+
+ if (!isSessionOkay(ic))
+ 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(mComposingText);
+ mComposingText = QString();
+ mIsComposing = false;
+ sendEvent(event);
+
+ return 0;
+}
+
+int32_t QBBInputContext::onGetCursorCapsMode(input_session_t* ic, int32_t req_modes)
+{
+ Q_UNUSED(req_modes);
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ // Should never get called.
+ qCritical() << TAG << "onGetCursorCapsMode is unsupported.";
+
+ return 0;
+}
+
+int32_t QBBInputContext::onGetCursorPosition(input_session_t* ic)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ mLastCaretPos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt();
+ return mLastCaretPos;
+}
+
+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() << TAG;
+#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 0;
+ }
+
+ // Used to update dictionaries, but not supported right now.
+ 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;
+}
+
+spannable_string_t* QBBInputContext::onGetSelectedText(input_session_t* ic, int32_t flags)
+{
+ Q_UNUSED(flags);
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#endif
+
+ if (!isSessionOkay(ic))
+ return toSpannableString("");
+
+ QString text = focusWidget()->inputMethodQuery(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() << TAG;
+#endif
+
+ if (!isSessionOkay(ic))
+ return toSpannableString("");
+
+ QString text = focusWidget()->inputMethodQuery(Qt::ImSurroundingText).toString();
+ mLastCaretPos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt();
+
+ return toSpannableString(text.mid(mLastCaretPos+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() << TAG;
+#endif
+
+ if (!isSessionOkay(ic))
+ return toSpannableString("");
+
+ QString text = focusWidget()->inputMethodQuery(Qt::ImSurroundingText).toString();
+ mLastCaretPos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt();
+
+ if (n < mLastCaretPos)
+ {
+ return toSpannableString(text.mid(mLastCaretPos - n, n));
+ }
+ else
+ return toSpannableString(text.mid(0, mLastCaretPos));
+}
+
+int32_t QBBInputContext::onPerformEditorAction(input_session_t* ic, int32_t editor_action)
+{
+ Q_UNUSED(editor_action);
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ // Should never get called.
+ qCritical() << TAG << "onPerformEditorAction is unsupported.";
+
+ return 0;
+}
+
+int32_t QBBInputContext::onReportFullscreenMode(input_session_t* ic, int32_t enabled)
+{
+ Q_UNUSED(enabled);
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ // Should never get called.
+ qCritical() << TAG << "onReportFullscreenMode is unsupported.";
+
+ return 0;
+}
+
+int32_t QBBInputContext::onSendEvent(input_session_t* ic, event_t * event)
+{
+#if defined(QBBINPUTCONTEXT_DEBUG)
+ qDebug() << TAG;
+#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() << TAG;
+#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() << TAG;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ if (!focusWidget())
+ {
+ qCritical() << "No focus widget!";
+ return 0;
+ }
+
+ QList<QInputMethodEvent::Attribute> attributes;
+
+ mLastCaretPos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt();
+ QString text = focusWidget()->inputMethodQuery(Qt::ImSurroundingText).toString();
+ QString empty = QString::fromLatin1("");
+ text = text.mid(start, end - start);
+
+ // Delete the current text.
+ {
+ QInputMethodEvent event(empty, attributes);
+ event.setCommitString(empty, start - mLastCaretPos, end - start);
+ sendEvent(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() << TAG;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ if (!focusWidget())
+ {
+ qCritical() << "No focus widget!";
+ return 0;
+ }
+
+ mIsComposing = 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() << TAG;
+#endif
+
+ if (!isSessionOkay(ic))
+ return 0;
+
+ // Should never get called.
+ qCritical() << TAG << "onSetSelection is unsupported.";
+
+ return 0;
+}
+
+
diff --git a/src/plugins/platforms/blackberry/qbbinputcontext_imf.h b/src/plugins/platforms/blackberry/qbbinputcontext_imf.h
new file mode 100644
index 0000000..6d18ddd
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbinputcontext_imf.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBBINPUTCONTEXT_H
+#define QBBINPUTCONTEXT_H
+
+#include "imf/imf_client.h"
+#include "imf/input_control.h"
+
+#include <QtGui/QPlatformIntegration>
+#include <qinputcontext.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBBInputContext : public QInputContext
+{
+public:
+ explicit QBBInputContext(QObject* parent = 0);
+ ~QBBInputContext();
+
+ virtual QList<QAction *> actions();
+ virtual bool filterEvent(const QEvent * event);
+ virtual QFont font() const;
+ virtual QString identifierName();
+ virtual bool isComposing() const;
+ virtual QString language();
+ virtual void mouseHandler(int x, QMouseEvent * event);
+ virtual void reset();
+ virtual void setFocusWidget(QWidget * widget);
+ virtual void update();
+ virtual void widgetDestroyed(QWidget * widget);
+ bool handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap);
+
+protected:
+ // Filters only for IMF events.
+ bool eventFilter(QObject *obj, QEvent *event);
+
+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 mLastCaretPos;
+ bool mIsComposing;
+ QString mComposingText;
+};
+
+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 0000000..8894098
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbinputcontext_noimf.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// #define QBBINPUTCONTEXT_DEBUG
+
+#include <qbbinputcontext.h>
+#include <qbbvirtualkeyboard.h>
+
+#include <QDebug>
+
+QBBInputContext::QBBInputContext(QObject* parent):
+ QInputContext(parent)
+{
+}
+
+QBBInputContext::~QBBInputContext()
+{
+}
+
+QString QBBInputContext::language()
+{
+ // Once we enable full IMF support, we need to hook that up here.
+ return QBBVirtualKeyboard::instance().languageId();
+}
+
+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)
+{
+ return false;
+}
+
diff --git a/src/plugins/platforms/blackberry/qbbinputcontext_noimf.h b/src/plugins/platforms/blackberry/qbbinputcontext_noimf.h
new file mode 100644
index 0000000..d7f3cc5
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbinputcontext_noimf.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBBINPUTCONTEXT_H
+#define QBBINPUTCONTEXT_H
+
+#include <QtGui/QPlatformIntegration>
+#include <qinputcontext.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBBInputContext : public QInputContext
+{
+public:
+ explicit QBBInputContext(QObject* parent = 0);
+ ~QBBInputContext();
+ QString identifierName() { return QString("BlackBerry IMF"); }
+ QString language();
+
+ void reset();
+ bool isComposing() const { return false; }
+ virtual bool filterEvent( const QEvent *event );
+ bool handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap);
+
+private:
+ bool hasPhysicalKeyboard();
+
+};
+
+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 0000000..cc16938
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbintegration.cpp
@@ -0,0 +1,221 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QBBINTEGRATION_DEBUG
+
+#include "qbbintegration.h"
+#include "qbbinputcontext.h"
+#include "qbbeventthread.h"
+#include "qbbglcontext.h"
+#include "qbbglwindowsurface.h"
+#include "qbbnavigatorthread.h"
+#include "qbbrasterwindowsurface.h"
+#include "qbbscreen.h"
+#include "qbbwindow.h"
+#include "qbbvirtualkeyboard.h"
+#include "qgenericunixfontdatabase.h"
+#include "qbbclipboard.h"
+#include "qbbglcontext.h"
+#include "qbblocalethread.h"
+
+#include "qapplication.h"
+#include <QtGui/private/qpixmap_raster_p.h>
+#include <QtGui/QPlatformWindow>
+#include <QtGui/QWindowSystemInterface>
+#include <QtOpenGL/private/qpixmapdata_gl_p.h>
+#include <QDebug>
+
+#include <errno.h>
+
+QT_BEGIN_NAMESPACE
+
+QBBIntegration::QBBIntegration() :
+ mFontDb(new QGenericUnixFontDatabase()),
+ mPaintUsingOpenGL(getenv("QBB_USE_OPENGL") != NULL)
+{
+ if (mPaintUsingOpenGL) {
+ // Set default window API to OpenGL
+ QPlatformWindowFormat format = QPlatformWindowFormat::defaultFormat();
+ format.setWindowApi(QPlatformWindowFormat::OpenGL);
+ QPlatformWindowFormat::setDefaultFormat(format);
+ }
+
+ // initialize global OpenGL resources
+ QBBGLContext::initialize();
+
+ // open connection to QNX composition manager
+ errno = 0;
+ int result = screen_create_context(&mContext, 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(mContext);
+
+ // create/start event thread
+ mEventThread = new QBBEventThread(mContext, *QBBScreen::primaryDisplay());
+ mEventThread->start();
+
+ // create/start navigator thread
+ mNavigatorThread = new QBBNavigatorThread(*QBBScreen::primaryDisplay());
+ mNavigatorThread->start();
+
+#ifdef QBBLOCALETHREAD_ENABLED
+ // Start the locale change monitoring thread.
+ mLocaleThread = new QBBLocaleThread();
+ mLocaleThread->start();
+#endif
+
+ // create/start the keyboard class.
+ QBBVirtualKeyboard::instance();
+
+ // Set up the input context
+ qApp->setInputContext(new QBBInputContext(qApp));
+}
+
+QBBIntegration::~QBBIntegration()
+{
+#if defined(QBBINTEGRATION_DEBUG)
+ qDebug() << "QBB: platform plugin shutdown begin";
+#endif
+ // destroy the keyboard class.
+ QBBVirtualKeyboard::destroy();
+
+#ifdef QBBLOCALETHREAD_ENABLED
+ // stop/destroy the locale thread.
+ delete mLocaleThread;
+#endif
+
+ // stop/destroy event thread
+ delete mEventThread;
+
+ // stop/destroy navigator thread
+ delete mNavigatorThread;
+
+ // destroy all displays
+ QBBScreen::destroyDisplays();
+
+ // close connection to QNX composition manager
+ screen_destroy_context(mContext);
+
+ // cleanup global OpenGL resources
+ QBBGLContext::shutdown();
+
+#if defined(QBBINTEGRATION_DEBUG)
+ qDebug() << "QBB: platform plugin shutdown end";
+#endif
+}
+
+bool QBBIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+ switch (cap) {
+ case ThreadedPixmaps: return true;
+#if defined(QT_OPENGL_ES)
+ case OpenGL: return true;
+#endif
+ default: return QPlatformIntegration::hasCapability(cap);
+ }
+}
+
+QPixmapData *QBBIntegration::createPixmapData(QPixmapData::PixelType type) const
+{
+ if (paintUsingOpenGL())
+ return new QGLPixmapData(type);
+ else
+ return new QRasterPixmapData(type);
+}
+
+QPlatformWindow *QBBIntegration::createPlatformWindow(QWidget *widget, WId winId) const
+{
+ Q_UNUSED(winId);
+
+ // New windows are created on the primary display.
+ return new QBBWindow(widget, mContext);
+}
+
+QWindowSurface *QBBIntegration::createWindowSurface(QWidget *widget, WId winId) const
+{
+ Q_UNUSED(winId);
+ if (paintUsingOpenGL())
+ return new QBBGLWindowSurface(widget);
+ else
+ return new QBBRasterWindowSurface(widget);
+}
+
+void QBBIntegration::moveToScreen(QWidget *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->platformWindow());
+
+ // lookup platform screen by index
+ QBBScreen* platformScreen = static_cast<QBBScreen*>(QBBScreen::screens().at(screen));
+
+ // move the platform window to the platform screen (this can fail when move to screen
+ // is called before the window is actually created).
+ if (platformWindow && platformScreen)
+ platformWindow->setScreen(platformScreen);
+}
+
+QList<QPlatformScreen *> QBBIntegration::screens() const
+{
+ return QBBScreen::screens();
+}
+
+#ifndef QT_NO_CLIPBOARD
+QPlatformClipboard *QBBIntegration::clipboard() const
+{
+ static QPlatformClipboard *clipboard = 0;
+ if (!clipboard) {
+ clipboard = static_cast<QPlatformClipboard *>(new QBBClipboard);
+ }
+ return clipboard;
+}
+#endif
+
+void QBBIntegration::setCursorPos(int x, int y)
+{
+ mEventThread->injectPointerMoveEvent(x, y);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/blackberry/qbbintegration.h b/src/plugins/platforms/blackberry/qbbintegration.h
new file mode 100644
index 0000000..8c20b6c
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbintegration.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBBINTEGRATION_H
+#define QBBINTEGRATION_H
+
+#include <QtGui/QPlatformIntegration>
+
+#include <screen/screen.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBBEventThread;
+class QBBNavigatorThread;
+class QBBLocaleThread;
+
+class QBBIntegration : public QPlatformIntegration
+{
+public:
+ QBBIntegration();
+ virtual ~QBBIntegration();
+
+ virtual bool hasCapability(QPlatformIntegration::Capability cap) const;
+
+ virtual QPixmapData *createPixmapData(QPixmapData::PixelType type) const;
+ virtual QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId) const;
+ virtual QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const;
+
+ virtual QList<QPlatformScreen *> screens() const;
+ virtual void moveToScreen(QWidget *window, int screen);
+ virtual void setCursorPos(int x, int y);
+
+ virtual QPlatformFontDatabase *fontDatabase() const { return mFontDb; }
+
+#ifndef QT_NO_CLIPBOARD
+ virtual QPlatformClipboard *clipboard() const;
+#endif
+
+ bool paintUsingOpenGL() const { return mPaintUsingOpenGL; }
+
+private:
+ screen_context_t mContext;
+ QBBEventThread *mEventThread;
+ QBBNavigatorThread *mNavigatorThread;
+ QBBLocaleThread *mLocaleThread;
+ QPlatformFontDatabase *mFontDb;
+ bool mPaintUsingOpenGL;
+};
+
+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 0000000..88c9660
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbkeytranslator.h
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBBKEYTRANSLATOR_H
+#define QBBKEYTRANSLATOR_H
+
+#include <sys/keycodes.h>
+#include <QDebug>
+
+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/qbblocalethread.cpp b/src/plugins/platforms/blackberry/qbblocalethread.cpp
new file mode 100644
index 0000000..1da94e2
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbblocalethread.cpp
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QBBLOCALETHREAD_DEBUG
+
+#ifdef QBBLOCALETHREAD_ENABLED
+
+#include "qbblocalethread.h"
+
+#include <QtGui/QApplication>
+#include <QtGui/QWidget>
+#include <QtGui/QWindowSystemInterface>
+#include <QByteArray>
+#include <QList>
+#include <QDebug>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define NAV_CONTROL_PATH "/pps/services/confstr/_CS_LOCALE"
+#define PPS_BUFFER_SIZE 4096
+
+QBBLocaleThread::QBBLocaleThread()
+ : mFd(-1),
+ mQuit(false)
+{
+}
+
+QBBLocaleThread::~QBBLocaleThread()
+{
+ // block until thread terminates
+ shutdown();
+}
+
+void QBBLocaleThread::run()
+{
+#if defined(QBBLOCALETHREAD_DEBUG)
+ qDebug() << "QBB: Locale thread started";
+#endif
+
+ // open connection to Locale
+ errno = 0;
+ mFd = open(NAV_CONTROL_PATH, O_RDWR);
+ if (mFd == -1) {
+ qWarning("QBB: failed to open Locale pps, errno=%d", errno);
+ return;
+ }
+
+ // allocate buffer for pps data
+ char buffer[PPS_BUFFER_SIZE];
+
+ // loop indefinitely
+ while (!mQuit) {
+
+ // attempt to read pps data
+ errno = 0;
+ int bytes = read(mFd, buffer, PPS_BUFFER_SIZE - 1);
+ if (bytes == -1) {
+ qWarning("QBB: failed to read Locale pps, errno=%d", errno);
+ return;
+ }
+
+ // check if pps data was received
+ if (bytes > 0) {
+ // Notify the world that the locale has changed.
+ QWindowSystemInterface::handleLocaleChange();
+ }
+
+ // yield
+ msleep(5);
+ }
+
+ // close connection to Locale
+ close(mFd);
+
+#if defined(QBBLOCALETHREAD_DEBUG)
+ qDebug() << "QBB: Locale thread stopped";
+#endif
+}
+
+void QBBLocaleThread::shutdown()
+{
+ // signal thread to terminate
+ mQuit = true;
+
+#if defined(QBBLOCALETHREAD_DEBUG)
+ qDebug() << "QBB: Locale thread shutdown begin";
+#endif
+
+ // block until thread terminates
+ wait();
+
+#if defined(QBBLOCALETHREAD_DEBUG)
+ qDebug() << "QBB: Locale thread shutdown end";
+#endif
+}
+
+#endif // QBBLOCALETHREAD_ENABLED
diff --git a/src/plugins/platforms/blackberry/qbblocalethread.h b/src/plugins/platforms/blackberry/qbblocalethread.h
new file mode 100644
index 0000000..8a0413f
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbblocalethread.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifdef QBBLOCALETHREAD_ENABLED
+
+#ifndef QBBLOCALETHREAD_H
+#define QBBLOCALETHREAD_H
+
+#include <QThread>
+
+QT_BEGIN_NAMESPACE
+
+class QBBLocaleThread : public QThread
+{
+public:
+ QBBLocaleThread();
+ virtual ~QBBLocaleThread();
+
+protected:
+ virtual void run();
+
+private:
+ int mFd;
+ bool mQuit;
+
+ void shutdown();
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBLOCALETHREAD_H
+
+#endif // QBBLOCALETHREAD_ENABLED
diff --git a/src/plugins/platforms/blackberry/qbbnavigatorthread.cpp b/src/plugins/platforms/blackberry/qbbnavigatorthread.cpp
new file mode 100644
index 0000000..97d50a9
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbnavigatorthread.cpp
@@ -0,0 +1,271 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QBBNAVIGATORTHREAD_DEBUG
+
+
+#include "qbbnavigatorthread.h"
+#include "qbbscreen.h"
+
+#include <QtGui/QApplication>
+#include <QtGui/QWidget>
+#include <QtGui/QWindowSystemInterface>
+#include <QByteArray>
+#include <QList>
+#include <QDebug>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define NAV_CONTROL_PATH "/pps/services/navigator/control"
+#define PPS_BUFFER_SIZE 4096
+
+QBBNavigatorThread::QBBNavigatorThread(QBBScreen& primaryScreen)
+ : mPrimaryScreen(primaryScreen),
+ mFd(-1),
+ mQuit(false)
+{
+}
+
+QBBNavigatorThread::~QBBNavigatorThread()
+{
+ // block until thread terminates
+ shutdown();
+}
+
+void QBBNavigatorThread::run()
+{
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "QBB: navigator thread started";
+#endif
+
+ // open connection to navigator
+ errno = 0;
+ mFd = open(NAV_CONTROL_PATH, O_RDWR);
+ if (mFd == -1) {
+ qWarning("QBB: failed to open navigator pps, errno=%d", errno);
+ return;
+ }
+
+ // allocate buffer for pps data
+ char buffer[PPS_BUFFER_SIZE];
+
+ // loop indefinitely
+ while (!mQuit) {
+
+ // attempt to read pps data
+ errno = 0;
+ int bytes = read(mFd, buffer, PPS_BUFFER_SIZE - 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);
+ }
+
+ // yield
+ msleep(5);
+ }
+
+ // close connection to navigator
+ close(mFd);
+
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "QBB: navigator thread stopped";
+#endif
+}
+
+void QBBNavigatorThread::shutdown()
+{
+ // signal thread to terminate
+ mQuit = true;
+
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "QBB: navigator thread shutdown begin";
+#endif
+
+ // 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(mFd, 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
+ mPrimaryScreen.setRotation( dat.toInt() );
+ QWindowSystemInterface::handleScreenGeometryChange(0);
+ replyPPS(msg, id, "");
+
+ } else if (msg == "SWIPE_DOWN") {
+
+ // simulate menu key press
+#if defined(QBBNAVIGATORTHREAD_DEBUG)
+ qDebug() << "PPS: menu";
+#endif
+ QWidget *w = QApplication::activeWindow();
+ 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
+ QApplication::quit();
+ }
+}
diff --git a/src/plugins/platforms/blackberry/qbbnavigatorthread.h b/src/plugins/platforms/blackberry/qbbnavigatorthread.h
new file mode 100644
index 0000000..fa7e8ae
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbnavigatorthread.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBBNAVIGATORTHREAD_H
+#define QBBNAVIGATORTHREAD_H
+
+#include <QThread>
+
+QT_BEGIN_NAMESPACE
+
+class QBBScreen;
+
+class QBBNavigatorThread : public QThread
+{
+public:
+ QBBNavigatorThread(QBBScreen& primaryScreen);
+ virtual ~QBBNavigatorThread();
+
+protected:
+ virtual void run();
+
+private:
+ QBBScreen& mPrimaryScreen;
+ int mFd;
+ bool mQuit;
+
+ 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);
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBNAVIGATORTHREAD_H
diff --git a/src/plugins/platforms/blackberry/qbbrasterwindowsurface.cpp b/src/plugins/platforms/blackberry/qbbrasterwindowsurface.cpp
new file mode 100644
index 0000000..548ca4d
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbrasterwindowsurface.cpp
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// #define QBBRASTERWINDOWSURFACE_DEBUG
+
+
+#include "qbbrasterwindowsurface.h"
+#include "qbbwindow.h"
+
+#include <QtGui/QWidget>
+#include <QDebug>
+
+#include <errno.h>
+
+QT_BEGIN_NAMESPACE
+
+QBBRasterWindowSurface::QBBRasterWindowSurface(QWidget *window)
+ : QWindowSurface(window)
+{
+#if defined(QBBRASTERWINDOWSURFACE_DEBUG)
+ qDebug() << "QBBRasterWindowSurface::QBBRasterWindowSurface - w=" << window;
+#endif
+
+ // save platform window associated with widget
+ mPlatformWindow = static_cast<QBBWindow*>(window->platformWindow());
+}
+
+QBBRasterWindowSurface::~QBBRasterWindowSurface()
+{
+#if defined(QBBRASTERWINDOWSURFACE_DEBUG)
+ qDebug() << "QBBRasterWindowSurface::~QBBRasterWindowSurface - w=" << window();
+#endif
+}
+
+QPaintDevice *QBBRasterWindowSurface::paintDevice()
+{
+ return mPlatformWindow->renderBuffer().image();
+}
+
+void QBBRasterWindowSurface::flush(QWidget *widget, const QRegion &region, const QPoint &offset)
+{
+ Q_UNUSED(widget);
+ Q_UNUSED(offset);
+
+#if defined(QBBRASTERWINDOWSURFACE_DEBUG)
+ qDebug() << "QBBRasterWindowSurface::flush - w=" << window();
+#endif
+
+ // visit all pending scroll operations
+ for (int i = mScrollOpList.size() - 1; i >= 0; i--) {
+
+ // do the scroll operation
+ ScrollOp& op = mScrollOpList[i];
+ QRegion srcArea = op.totalArea.intersected( op.totalArea.translated(-op.dx, -op.dy) );
+ mPlatformWindow->scroll(srcArea, op.dx, op.dy);
+ }
+
+ // clear all pending scroll operations
+ mScrollOpList.clear();
+
+ // update the display with newly rendered content
+ mPlatformWindow->post(region);
+}
+
+void QBBRasterWindowSurface::resize(const QSize &size)
+{
+#if defined(QBBRASTERWINDOWSURFACE_DEBUG)
+ qDebug() << "QBBRasterWindowSurface::resize - w=" << window() << ", s=" << size;
+#endif
+
+ // call parent method
+ QWindowSurface::resize(size);
+
+ // NOTE: defer resizing window buffers until next paint as
+ // resize() can be called multiple times before a paint occurs
+}
+
+bool QBBRasterWindowSurface::scroll(const QRegion &area, int dx, int dy)
+{
+#if defined(QBBRASTERWINDOWSURFACE_DEBUG)
+ qDebug() << "QBBRasterWindowSurface::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 = mScrollOpList.size() - 1; i >= 0; i--) {
+
+ ScrollOp& op = mScrollOpList[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
+ mScrollOpList.append( ScrollOp(totalArea, dx, dy) );
+ return true;
+}
+
+void QBBRasterWindowSurface::beginPaint(const QRegion &region)
+{
+ Q_UNUSED(region);
+
+#if defined(QBBRASTERWINDOWSURFACE_DEBUG)
+ qDebug() << "QBBRasterWindowSurface::beginPaint - w=" << window();
+#endif
+
+ // resize window buffers if surface resized
+ QSize s = size();
+ if (s != mPlatformWindow->bufferSize()) {
+ mPlatformWindow->setBufferSize(s);
+ }
+}
+
+void QBBRasterWindowSurface::endPaint(const QRegion &region)
+{
+ Q_UNUSED(region);
+#if defined(QBBRASTERWINDOWSURFACE_DEBUG)
+ qDebug() << "QBBRasterWindowSurface::endPaint - w=" << window();
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/blackberry/qbbrasterwindowsurface.h b/src/plugins/platforms/blackberry/qbbrasterwindowsurface.h
new file mode 100644
index 0000000..02c8eb3
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbrasterwindowsurface.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBBRASTERWINDOWSURFACE_H
+#define QBBRASTERWINDOWSURFACE_H
+
+#include <QtGui/private/qwindowsurface_p.h>
+
+#include <screen/screen.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBBWindow;
+
+class QBBRasterWindowSurface : public QWindowSurface
+{
+public:
+ QBBRasterWindowSurface(QWidget *window);
+ virtual ~QBBRasterWindowSurface();
+
+ virtual QPaintDevice *paintDevice();
+ virtual void flush(QWidget *widget, const QRegion &region, const QPoint &offset);
+ virtual void resize(const QSize &size);
+ 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 *mPlatformWindow;
+ QList<ScrollOp> mScrollOpList;
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBRASTERWINDOWSURFACE_H
diff --git a/src/plugins/platforms/blackberry/qbbscreen.cpp b/src/plugins/platforms/blackberry/qbbscreen.cpp
new file mode 100644
index 0000000..31e3f43
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbscreen.cpp
@@ -0,0 +1,516 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// #define QBBSCREEN_DEBUG
+
+#include "qbbscreen.h"
+#include "qbbvirtualkeyboard.h"
+#include "qbbwindow.h"
+
+#include <QUuid>
+#include <QDebug>
+
+#include <errno.h>
+#include <unistd.h>
+
+QT_BEGIN_NAMESPACE
+
+#define MAGIC_ZORDER_FOR_NO_NAV 10
+
+QList<QPlatformScreen *> QBBScreen::sScreens;
+QList<QBBWindow*> QBBScreen::sChildren;
+
+QBBScreen::QBBScreen(screen_context_t context, screen_display_t display, bool primary)
+ : mContext(context),
+ mDisplay(display),
+ mAppWindow(0),
+ mPosted(false),
+ mUsingOpenGL(false),
+ mPrimaryDisplay(primary)
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << "QBBScreen::QBBScreen";
+#endif
+
+ // cache initial orientation of this display
+ // TODO: use ORIENTATION environment variable?
+ errno = 0;
+ int result = screen_get_display_property_iv(mDisplay, SCREEN_PROPERTY_ROTATION, &mStartRotation);
+ if (result != 0) {
+ qFatal("QBBScreen: failed to query display rotation, errno=%d", errno);
+ }
+
+ mCurrentRotation = mStartRotation;
+
+ // 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(mDisplay, SCREEN_PROPERTY_SIZE, val);
+ if (result != 0) {
+ qFatal("QBBScreen: failed to query display size, errno=%d", errno);
+ }
+
+ mCurrentGeometry = mStartGeometry = QRect(0, 0, val[0], val[1]);
+
+ // cache size of this display in millimeters
+ errno = 0;
+ result = screen_get_display_property_iv(mDisplay, 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 = mCurrentGeometry.width() / dpi * qreal(25.4) ;
+ int height = mCurrentGeometry.height() / dpi * qreal(25.4) ;
+
+ mCurrentPhysicalSize = mStartPhysicalSize = QSize(width,height);
+ }
+
+ // We only create the root window if we are not the primary display.
+ if (mPrimaryDisplay)
+ createRootWindow();
+}
+
+QBBScreen::~QBBScreen()
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << "QBBScreen::~QBBScreen";
+#endif
+
+ destroyRootWindow();
+}
+
+/* static */
+void QBBScreen::createDisplays(screen_context_t context)
+{
+ // get 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);
+ sScreens.push_back(screen);
+ }
+}
+
+/* static */
+void QBBScreen::destroyDisplays()
+{
+ while (sScreens.length()) {
+ delete sScreens.front();
+ sScreens.pop_front();
+ }
+
+ // We're not managing the child windows anymore so we need to clear the list.
+ sChildren.clear();
+}
+
+/* static */
+int QBBScreen::defaultDepth()
+{
+ 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;
+}
+
+void QBBScreen::ensureDisplayCreated()
+{
+ if (!mAppWindow)
+ createRootWindow();
+}
+
+void QBBScreen::createRootWindow()
+{
+ // 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(&mAppWindow, mContext);
+ int val[2];
+ if (result != 0) {
+ qFatal("QBBScreen: failed to create window, errno=%d", errno);
+ }
+
+ // move window to proper display
+ errno = 0;
+ result = screen_set_window_property_pv(mAppWindow, SCREEN_PROPERTY_DISPLAY, (void **)&mDisplay);
+ if (result != 0) {
+ qFatal("QBBScreen: 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(mAppWindow, SCREEN_PROPERTY_ZORDER, val);
+ if (result != 0) {
+ qFatal("QBBScreen: 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(mAppWindow, SCREEN_PROPERTY_USAGE, val);
+ if (result != 0) {
+ qFatal("QBBScreen: failed to set window buffer usage, errno=%d", errno);
+ }
+
+ errno = 0;
+ val[0] = nativeFormat();
+ result = screen_set_window_property_iv(mAppWindow, SCREEN_PROPERTY_FORMAT, val);
+ if (result != 0) {
+ qFatal("QBBScreen: failed to set window pixel format, errno=%d", errno);
+ }
+
+ errno = 0;
+ val[0] = 1;
+ val[1] = 1;
+ result = screen_set_window_property_iv(mAppWindow, SCREEN_PROPERTY_BUFFER_SIZE, val);
+ if (result != 0) {
+ qFatal("QBBScreen: failed to set window buffer size, errno=%d", errno);
+ }
+
+ errno = 0;
+ result = screen_create_window_buffers(mAppWindow, 1);
+ if (result != 0) {
+ qFatal("QBB: failed to create window buffer, errno=%d", errno);
+ }
+
+ // window is always the size of the display
+ errno = 0;
+ val[0] = mCurrentGeometry.width();
+ val[1] = mCurrentGeometry.height();
+ result = screen_set_window_property_iv(mAppWindow, SCREEN_PROPERTY_SIZE, val);
+ if (result != 0) {
+ qFatal("QBBScreen: 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(mAppWindow, SCREEN_PROPERTY_COLOR, val);
+ if (result != 0) {
+ qFatal("QBBScreen: 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(mAppWindow, SCREEN_PROPERTY_TRANSPARENCY, val);
+ if (result != 0) {
+ qFatal("QBBScreen: 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(mAppWindow, SCREEN_PROPERTY_SWAP_INTERVAL, val);
+ if (result != 0) {
+ qFatal("QBBScreen: 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] = mCurrentGeometry.width();
+ val[1] = mCurrentGeometry.height();
+ result = screen_set_window_property_iv(mAppWindow, SCREEN_PROPERTY_SOURCE_SIZE, val);
+ if (result != 0) {
+ qFatal("QBBScreen: failed to set window source size, errno=%d", errno);
+ }
+
+ errno = 0;
+ val[0] = 1;
+ val[1] = 0;
+ result = screen_set_window_property_iv(mAppWindow, SCREEN_PROPERTY_SOURCE_POSITION, val);
+ if (result != 0) {
+ qFatal("QBBScreen: failed to set window source position, errno=%d", errno);
+ }
+
+ // generate a random window group name
+ QUuid uuid;
+ mWindowGroupName = QUuid::createUuid().toString().toAscii();
+
+ // create window group so child windows can be parented by container window
+ errno = 0;
+ result = screen_create_window_group(mAppWindow, windowGroupName());
+ if (result != 0) {
+ qFatal("QBBScreen: failed to create app window group, errno=%d", errno);
+ }
+
+ errno = 0;
+ screen_buffer_t buffer;
+ result = screen_get_window_property_pv(mAppWindow, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)&buffer);
+ if (result != 0) {
+ qFatal("QBBScreen: failed to query window buffer, errno=%d", errno);
+ }
+
+ errno = 0;
+ int dirtyRect[] = {0, 0, 1, 1};
+ result = screen_post_window(mAppWindow, buffer, 1, dirtyRect, 0);
+ if (result != 0) {
+ qFatal("QBB: failed to post window buffer, errno=%d", errno);
+ }
+}
+
+void QBBScreen::destroyRootWindow()
+{
+ if (!mAppWindow)
+ return;
+
+ // cleanup top-level QNX window
+ screen_destroy_window(mAppWindow);
+ mAppWindow = 0;
+ mWindowGroupName = QByteArray();
+}
+
+QRect QBBScreen::availableGeometry() const
+{
+ // available geometry = total geometry - keyboard
+ int keyboardHeight = QBBVirtualKeyboard::instance().getHeight();
+ return QRect(mCurrentGeometry.x(), mCurrentGeometry.y(),
+ mCurrentGeometry.width(), mCurrentGeometry.height() - keyboardHeight);
+}
+
+void QBBScreen::setRotation(int rotation)
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << "QBBScreen::setRotation, o=" << rotation;
+#endif
+
+ // check if rotation changed
+ if (mCurrentRotation != rotation) {
+
+ // update rotation of app window
+ errno = 0;
+ int result = screen_set_window_property_iv(mAppWindow, SCREEN_PROPERTY_ROTATION, &rotation);
+ if (result != 0) {
+ qFatal("QBBScreen: failed to set window rotation, errno=%d", errno);
+ }
+
+ // swap dimensions if we've rotated 90 or 270 from initial orientation
+ if (orthogonal(mStartRotation, rotation)) {
+ mCurrentGeometry = QRect(0, 0, mStartGeometry.height(), mStartGeometry.width());
+ mCurrentPhysicalSize = QSize(mStartPhysicalSize.height(), mStartPhysicalSize.width());
+ } else {
+ mCurrentGeometry = QRect(0, 0, mStartGeometry.width(), mStartGeometry.height());
+ mCurrentPhysicalSize = mStartPhysicalSize;
+ }
+
+ // resize app window if we've rotated 90 or 270 from previous orientation
+ if (orthogonal(mCurrentRotation, rotation)) {
+
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << "QBBScreen::setRotation - resize, s=" << mCurrentGeometry.size();
+#endif
+ errno = 0;
+ int val[] = {mCurrentGeometry.width(), mCurrentGeometry.height()};
+ result = screen_set_window_property_iv(mAppWindow, SCREEN_PROPERTY_SIZE, val);
+ if (result != 0) {
+ qFatal("QBBScreen: failed to set window size, errno=%d", errno);
+ }
+
+ errno = 0;
+ result = screen_set_window_property_iv(mAppWindow, SCREEN_PROPERTY_SOURCE_SIZE, val);
+ if (result != 0) {
+ qFatal("QBBScreen: failed to set window source size, errno=%d", errno);
+ }
+
+ // NOTE: display will update when child windows relayout and repaint
+
+ } else {
+
+ // TODO: find one global place to flush display updates
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << "QBBScreen::setRotation - flush";
+#endif
+ // force immediate display update if no geometry changes required
+ errno = 0;
+ int result = screen_flush_context(mContext, 0);
+ if (result != 0) {
+ qFatal("QBBScreen: failed to flush context, errno=%d", errno);
+ }
+ }
+
+ // save new rotation
+ mCurrentRotation = rotation;
+ }
+}
+
+/*!
+ Check if the supplied angles are perpendicular to each other.
+*/
+bool QBBScreen::orthogonal(int rotation1, int rotation2)
+{
+ return ((rotation1 - rotation2) % 180) != 0;
+}
+
+void QBBScreen::addWindow(QBBWindow* window)
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << "QBBScreen::addWindow=" << window;
+#endif
+
+ if (sChildren.contains(window))
+ return;
+
+ sChildren.push_back(window);
+ QBBScreen::updateHierarchy();
+}
+
+void QBBScreen::removeWindow(QBBWindow* window)
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << "QBBScreen::removeWindow=" << window;
+#endif
+
+ sChildren.removeAll(window);
+ QBBScreen::updateHierarchy();
+}
+
+void QBBScreen::raiseWindow(QBBWindow* window)
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << "QBBScreen::raise window=" << window;
+#endif
+
+ removeWindow(window);
+ sChildren.push_back(window);
+ QBBScreen::updateHierarchy();
+}
+
+void QBBScreen::lowerWindow(QBBWindow* window)
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << "QBBScreen::lower window=" << window;
+#endif
+
+ removeWindow(window);
+ sChildren.push_front(window);
+ QBBScreen::updateHierarchy();
+}
+
+void QBBScreen::updateHierarchy()
+{
+#if defined(QBBSCREEN_DEBUG)
+ qDebug() << "QBBScreen::updateHierarchy";
+#endif
+
+ QList<QBBWindow*>::iterator it;
+ QList<QPlatformScreen *>::iterator sit;
+ QMap<QPlatformScreen *, int> map;
+ int topZorder = 0;
+
+ for (sit = sScreens.begin(); sit != sScreens.end(); sit++)
+ map[*sit] = 0;
+
+ for (it = sChildren.begin(); it != sChildren.end(); it++) {
+ (*it)->updateZorder(topZorder);
+ map[static_cast<QBBScreen*>((*it)->screen())] = 1;
+ }
+
+ // Check to see if any root windows need destruction
+ for (sit = sScreens.begin(); sit != sScreens.end(); sit++)
+ if (!static_cast<QBBScreen*>(*sit)->isPrimaryDisplay() && map[*sit] == 0)
+ static_cast<QBBScreen*>(*sit)->destroyRootWindow();
+
+ // After a hierarchy update, we need to force a flush on all screens.
+ // Right now, all screens share a context.
+ screen_flush_context( primaryDisplay()->mContext, 0 );
+}
+
+void QBBScreen::onWindowPost(QBBWindow* window)
+{
+ 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 (!mPosted) {
+
+ errno = 0;
+ screen_buffer_t buffer;
+ int result = screen_get_window_property_pv(mAppWindow, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)&buffer);
+ if (result != 0) {
+ qFatal("QBB: failed to query window buffer, errno=%d", errno);
+ }
+
+ errno = 0;
+ int dirtyRect[] = {0, 0, 1, 1};
+ result = screen_post_window(mAppWindow, buffer, 1, dirtyRect, 0);
+ if (result != 0) {
+ qFatal("QBB: failed to post window buffer, errno=%d", errno);
+ }
+
+ mPosted = 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 0000000..a061811
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbscreen.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBBSCREEN_H
+#define QBBSCREEN_H
+
+#include <QtGui/QPlatformScreen>
+#include <QByteArray>
+
+#include <screen/screen.h>
+
+QT_BEGIN_NAMESPACE
+
+class QBBWindow;
+
+class QBBScreen : public QPlatformScreen
+{
+public:
+ static QList<QPlatformScreen *> screens() { return sScreens; }
+ static void createDisplays(screen_context_t context);
+ static void destroyDisplays();
+ static QBBScreen* primaryDisplay() { return static_cast<QBBScreen*>(sScreens.at(0)); }
+ static int defaultDepth();
+
+ virtual QRect geometry() const { return mCurrentGeometry; }
+ 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 QSize physicalSize() const { return mCurrentPhysicalSize; }
+
+ int rotation() const { return mCurrentRotation; }
+ void setRotation(int rotation);
+
+ int nativeFormat() const { return (depth() == 32) ? SCREEN_FORMAT_RGBA8888 : SCREEN_FORMAT_RGB565; }
+ screen_display_t nativeDisplay() const { return mDisplay; }
+ screen_context_t nativeContext() const { return mContext; }
+ const char *windowGroupName() const { return mWindowGroupName.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);
+ void ensureDisplayCreated();
+
+private:
+ screen_context_t mContext;
+ screen_display_t mDisplay;
+ screen_window_t mAppWindow;
+ QByteArray mWindowGroupName;
+ bool mPosted;
+ bool mUsingOpenGL;
+ bool mPrimaryDisplay;
+
+ int mStartRotation;
+ int mCurrentRotation;
+ QSize mStartPhysicalSize;
+ QSize mCurrentPhysicalSize;
+ QRect mStartGeometry;
+ QRect mCurrentGeometry;
+
+ static QList<QPlatformScreen *> sScreens;
+ static QList<QBBWindow*> sChildren;
+
+ QBBScreen(screen_context_t context, screen_display_t display, bool primary);
+ virtual ~QBBScreen();
+
+ static bool orthogonal(int rotation1, int rotation2);
+ void createRootWindow();
+ void destroyRootWindow();
+ bool isPrimaryDisplay() { return mPrimaryDisplay; }
+};
+
+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 0000000..5e7d1fe
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbvirtualkeyboard.cpp
@@ -0,0 +1,475 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QBBVIRTUALKEYBOARD_DEBUG
+
+#include "qbbvirtualkeyboard.h"
+
+#include <QDebug>
+#include <QtGui/QApplication>
+#include <QtGui/QPlatformScreen>
+#include <QtGui/QPlatformWindow>
+
+#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::sPPSPath = "/pps/services/input/control?wait";
+const size_t QBBVirtualKeyboard::sBufferSize = 2048;
+
+static QBBVirtualKeyboard* s_instance = NULL;
+
+// Huge hack for keyboard shadow (see QNX PR 88400). Should be removed ASAP.
+#define KEYBOARD_SHADOW_HEIGHT 8
+
+QBBVirtualKeyboard::QBBVirtualKeyboard() :
+ mEncoder(NULL),
+ mDecoder(NULL),
+ mBuffer(NULL),
+ mHeight(0),
+ mFd(-1),
+ mKeyboardMode(Default),
+ mVisible(false),
+ mLanguageId(QString::fromLatin1("en")),
+ mCountryId(QString::fromLatin1("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 (mFd) {
+ // any reads will fail after we close the fd, which is basically what we want.
+ ::close(mFd);
+ }
+
+ // Wait for the thread to die (should be immediate), then continue the cleanup.
+ wait();
+
+ if (mFd) {
+ mFd = -1;
+ }
+
+
+ if (mDecoder)
+ {
+ pps_decoder_cleanup(mDecoder);
+ delete mDecoder;
+ mDecoder = NULL;
+ }
+
+ if (mEncoder)
+ {
+ pps_encoder_cleanup(mEncoder);
+ delete mEncoder;
+ mEncoder = NULL;
+ }
+
+ delete [] mBuffer;
+ mBuffer = NULL;
+}
+
+bool QBBVirtualKeyboard::connect()
+{
+ close();
+
+ mEncoder = new pps_encoder_t;
+ mDecoder = new pps_decoder_t;
+
+ pps_encoder_initialize(mEncoder, false);
+ pps_decoder_initialize(mDecoder, NULL);
+
+ errno = 0;
+ mFd = ::open(sPPSPath, O_RDWR);
+ if (mFd == -1)
+ {
+ qCritical("QBBVirtualKeyboard: Unable to open \"%s\" for keyboard: %s (%d).",
+ sPPSPath, strerror(errno), errno);
+ close();
+ return false;
+ }
+
+ mBuffer = new char[sBufferSize];
+ if (!mBuffer) {
+ qCritical("QBBVirtualKeyboard: Unable to allocate buffer of %d bytes. Size is unavailable.", sBufferSize);
+ return false;
+ }
+
+ if (!queryPPSInfo())
+ return false;
+
+ start();
+
+ return true;
+}
+
+bool QBBVirtualKeyboard::queryPPSInfo()
+{
+ // Request info, requires id to regenerate res message.
+ pps_encoder_add_string(mEncoder, "msg", "info");
+ pps_encoder_add_string(mEncoder, "id", "libWebView");
+
+ if (::write(mFd, pps_encoder_buffer(mEncoder), pps_encoder_length(mEncoder)) == -1) {
+ close();
+ return false;
+ }
+
+ pps_encoder_reset(mEncoder);
+
+ return true;
+}
+
+void QBBVirtualKeyboard::notifyClientActiveStateChange(bool active)
+{
+ if (!active)
+ hideKeyboard();
+}
+
+void QBBVirtualKeyboard::run()
+{
+ ppsDataReady();
+}
+
+void QBBVirtualKeyboard::ppsDataReady()
+{
+ forever {
+ ssize_t nread = read(mFd, mBuffer, sBufferSize - 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) > sBufferSize - 1) {
+ qCritical("QBBVirtualKeyboard: Keyboard buffer size too short; need %u.", nread + 1);
+ break;
+ }
+
+ mBuffer[nread] = 0;
+ pps_decoder_parse_pps_str(mDecoder, mBuffer);
+ pps_decoder_push(mDecoder, NULL);
+#ifdef QBBVIRTUALKEYBOARD_DEBUG
+ pps_decoder_dump_tree(mDecoder, stderr);
+#endif
+
+ const char* value;
+ if (pps_decoder_get_string(mDecoder, "error", &value) == PPS_DECODER_OK) {
+ qCritical("QBBVirtualKeyboard: Keyboard PPS decoder error: %s", value ? value : "[null]");
+ continue;
+ }
+
+ if (pps_decoder_get_string(mDecoder, "msg", &value) == PPS_DECODER_OK) {
+ if (strcmp(value, "show") == 0) {
+ mVisible = true;
+ handleKeyboardStateChangeMessage(true);
+ } else if (strcmp(value, "hide") == 0) {
+ mVisible = false;
+ handleKeyboardStateChangeMessage(false);
+ } 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(mDecoder, "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 (mDecoder)
+ pps_decoder_cleanup(mDecoder);
+}
+
+void QBBVirtualKeyboard::handleKeyboardInfoMessage()
+{
+ int newHeight = 0;
+ const char* value;
+
+ if (pps_decoder_push(mDecoder, "dat") != PPS_DECODER_OK) {
+ qCritical("QBBVirtualKeyboard: Keyboard PPS dat object not found");
+ return;
+ }
+ if (pps_decoder_get_int(mDecoder, "size", &newHeight) != PPS_DECODER_OK) {
+ qCritical("QBBVirtualKeyboard: Keyboard PPS size field not found");
+ return;
+ }
+ if (pps_decoder_push(mDecoder, "locale") != PPS_DECODER_OK) {
+ qCritical("QBBVirtualKeyboard: Keyboard PPS locale object not found");
+ return;
+ }
+ if (pps_decoder_get_string(mDecoder, "languageId", &value) != PPS_DECODER_OK) {
+ qCritical("QBBVirtualKeyboard: Keyboard PPS languageId field not found");
+ mLanguageId = QString::fromLatin1(value);
+ return;
+ }
+ if (pps_decoder_get_string(mDecoder, "countryId", &value) != PPS_DECODER_OK) {
+ qCritical("QBBVirtualKeyboard: Keyboard PPS size countryId not found");
+ mCountryId = QString::fromLatin1(value);
+ return;
+ }
+
+
+ // 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 != mHeight) {
+ mHeight = newHeight;
+ handleKeyboardStateChangeMessage(true);
+ }
+
+#ifdef QBBVIRTUALKEYBOARD_DEBUG
+ qDebug() << "QBB: handleKeyboardInfoMessage size=" << mHeight << "languageId=" << mLanguageId << " countryId=" << mCountryId;
+#endif
+}
+
+void QBBVirtualKeyboard::handleKeyboardStateChangeMessage(bool visible)
+{
+
+#ifdef QBBVIRTUALKEYBOARD_DEBUG
+ qDebug() << "QBB: handleKeyboardStateChangeMessage " << visible;
+#endif
+
+ // TODO: What screen index should be used? I assume 0 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.
+ QWindowSystemInterface::handleScreenAvailableGeometryChange(0);
+}
+
+bool QBBVirtualKeyboard::showKeyboard()
+{
+#ifdef QBBVIRTUALKEYBOARD_DEBUG
+ qDebug() << "QBB: showKeyboard()";
+#endif
+
+ // Try to connect.
+ if (mFd == -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(mEncoder);
+
+ // Send the show message.
+ pps_encoder_add_string(mEncoder, "msg", "show");
+
+ if (::write(mFd, pps_encoder_buffer(mEncoder), pps_encoder_length(mEncoder)) == -1) {
+ close();
+ return false;
+ }
+
+ pps_encoder_reset(mEncoder);
+
+ // 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 (mFd == -1 && !connect())
+ return false;
+
+ pps_encoder_add_string(mEncoder, "msg", "hide");
+
+ if (::write(mFd, pps_encoder_buffer(mEncoder), pps_encoder_length(mEncoder)) == -1) {
+ close();
+
+ //Try again.
+ if (connect()) {
+ if (::write(mFd, pps_encoder_buffer(mEncoder), pps_encoder_length(mEncoder)) == -1) {
+ close();
+ return false;
+ }
+ }
+ else
+ return false;
+ }
+
+ pps_encoder_reset(mEncoder);
+
+ // Return true if no error occurs. Sizing response will be triggered when confirmation of
+ // the change arrives.
+ return true;
+}
+
+void QBBVirtualKeyboard::setKeyboardMode(KeyboardMode mode)
+{
+ mKeyboardMode = mode;
+}
+
+void QBBVirtualKeyboard::applyKeyboardModeOptions()
+{
+ // Try to connect.
+ if (mFd == -1 && !connect())
+ return;
+
+ // Send the options message.
+ pps_encoder_add_string(mEncoder, "msg", "options");
+
+ pps_encoder_start_object(mEncoder, "dat");
+ switch (mKeyboardMode) {
+ 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(mEncoder);
+
+ if (::write(mFd, pps_encoder_buffer(mEncoder), pps_encoder_length(mEncoder)) == -1) {
+ close();
+ }
+
+ pps_encoder_reset(mEncoder);
+}
+
+void QBBVirtualKeyboard::addDefaultModeOptions()
+{
+ pps_encoder_add_string(mEncoder, "enter", "enter.default");
+ pps_encoder_add_string(mEncoder, "type", "default");
+}
+
+void QBBVirtualKeyboard::addUrlModeOptions()
+{
+ pps_encoder_add_string(mEncoder, "enter", "enter.default");
+ pps_encoder_add_string(mEncoder, "type", "url");
+}
+
+void QBBVirtualKeyboard::addEmailModeOptions()
+{
+ pps_encoder_add_string(mEncoder, "enter", "enter.default");
+ pps_encoder_add_string(mEncoder, "type", "email");
+}
+
+void QBBVirtualKeyboard::addWebModeOptions()
+{
+ pps_encoder_add_string(mEncoder, "enter", "enter.default");
+ pps_encoder_add_string(mEncoder, "type", "web");
+}
+
+void QBBVirtualKeyboard::addNumPuncModeOptions()
+{
+ pps_encoder_add_string(mEncoder, "enter", "enter.default");
+ pps_encoder_add_string(mEncoder, "type", "numPunc");
+}
+
+void QBBVirtualKeyboard::addPhoneModeOptions()
+{
+ pps_encoder_add_string(mEncoder, "enter", "enter.default");
+ pps_encoder_add_string(mEncoder, "type", "phone");
+}
+
+void QBBVirtualKeyboard::addPinModeOptions()
+{
+ pps_encoder_add_string(mEncoder, "enter", "enter.default");
+ pps_encoder_add_string(mEncoder, "type", "pin");
+}
+
+void QBBVirtualKeyboard::addSymbolModeOptions()
+{
+ pps_encoder_add_string(mEncoder, "enter", "enter.default");
+ pps_encoder_add_string(mEncoder, "type", "symbol");
+}
diff --git a/src/plugins/platforms/blackberry/qbbvirtualkeyboard.h b/src/plugins/platforms/blackberry/qbbvirtualkeyboard.h
new file mode 100644
index 0000000..bedcbe0
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbvirtualkeyboard.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef VIRTUALKEYBOARD_H_
+#define VIRTUALKEYBOARD_H_
+
+#include <QtGui/QPlatformScreen>
+#include <QtGui/QWindowSystemInterface>
+#include <QThread>
+
+#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 : QThread
+{
+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 getHeight() { return mVisible ? mHeight : 0; }
+ void setKeyboardMode(KeyboardMode);
+ void notifyClientActiveStateChange(bool);
+ bool isVisible() const { return mVisible; }
+ QString languageId() const { return mLanguageId; }
+ QString countryId() const { return mCountryId; }
+
+private:
+ QBBVirtualKeyboard();
+ virtual ~QBBVirtualKeyboard();
+
+ pps_encoder_t *mEncoder;
+ pps_decoder_t *mDecoder;
+ char *mBuffer;
+ int mHeight;
+ int mFd;
+ KeyboardMode mKeyboardMode;
+ bool mVisible;
+ QString mLanguageId;
+ QString mCountryId;
+
+ // Path to keyboardManager in PPS.
+ static const char *sPPSPath;
+ static const size_t sBufferSize;
+
+ // Will be called internally if needed.
+ bool connect();
+ void close();
+ void ppsDataReady();
+ bool queryPPSInfo();
+ void handleKeyboardStateChangeMessage(bool visible);
+ void handleKeyboardInfoMessage();
+
+ void applyKeyboardModeOptions();
+ void addDefaultModeOptions();
+ void addUrlModeOptions();
+ void addEmailModeOptions();
+ void addWebModeOptions();
+ void addNumPuncModeOptions();
+ void addSymbolModeOptions();
+ void addPhoneModeOptions();
+ void addPinModeOptions();
+
+ // QThread overrides
+ virtual void run();
+
+};
+
+#endif /* VIRTUALKEYBOARD_H_ */
diff --git a/src/plugins/platforms/blackberry/qbbwindow.cpp b/src/plugins/platforms/blackberry/qbbwindow.cpp
new file mode 100644
index 0000000..ffdb118
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbwindow.cpp
@@ -0,0 +1,669 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// #define QBBWINDOW_DEBUG
+
+#include "qbbwindow.h"
+#include "qbbglcontext.h"
+#include "qbbscreen.h"
+
+#include <QtGui/QWidget>
+#include <QDebug>
+#include <QtGui/QPlatformWindowFormat>
+#include <QtGui/QWindowSystemInterface>
+
+#include <errno.h>
+
+QT_BEGIN_NAMESPACE
+
+QBBWindow::QBBWindow(QWidget *window, screen_context_t context)
+ : QPlatformWindow(window),
+ mContext(context),
+ mCurrentBufferIndex(-1),
+ mPreviousBufferIndex(-1),
+ mPlatformGlContext(NULL),
+ mScreen(NULL),
+ mParent(NULL),
+ mVisible(true)
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << "QBBWindow::QBBWindow - w=" << window << ", s=" << window->size();
+#endif
+ int result;
+
+ // create child QNX window
+ errno = 0;
+ result = screen_create_window_type(&mWindow, mContext, 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;
+ QPlatformWindowFormat format = widget()->platformWindowFormat();
+ switch (format.windowApi()) {
+ case QPlatformWindowFormat::Raster:
+ val = SCREEN_USAGE_NATIVE | SCREEN_USAGE_READ | SCREEN_USAGE_WRITE;
+ break;
+ case QPlatformWindowFormat::OpenGL:
+ val = SCREEN_USAGE_OPENGL_ES2;
+ break;
+ default:
+ qFatal("QBBWindow: unsupported window API");
+ break;
+ }
+
+ errno = 0;
+ result = screen_set_window_property_iv(mWindow, 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(mWindow, 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(mWindow, 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(mWindow, SCREEN_PROPERTY_SWAP_INTERVAL, &val);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to set window swap interval, errno=%d", errno);
+ }
+
+ // Set the screen 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);
+}
+
+QBBWindow::~QBBWindow()
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << "QBBWindow::~QBBWindow - w=" << widget();
+#endif
+
+ // 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 (mChildren.size() > 0)
+ qFatal("QBBWindow: window destroyed before children!");
+
+ // cleanup OpenGL/OpenVG context if it exists
+ if (mPlatformGlContext != NULL) {
+ delete mPlatformGlContext;
+ }
+
+ // cleanup QNX window and its buffers
+ screen_destroy_window(mWindow);
+}
+
+void QBBWindow::setGeometry(const QRect &rect)
+{
+ int val[2];
+
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << "QBBWindow::setGeometry - w=" << widget() << ", (" << rect.x() << "," << rect.y() << "," << rect.width() << "," << rect.height() << ")";
+#endif
+
+ QRect oldGeometry = geometry();
+
+ // call parent method
+ QPlatformWindow::setGeometry(rect);
+
+ // set window geometry equal to widget geometry
+ errno = 0;
+ val[0] = rect.x();
+ val[1] = rect.y();
+ int result = screen_set_window_property_iv(mWindow, 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(mWindow, 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(mWindow, 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 = mChildren.begin(); it != mChildren.end(); it++) {
+ (*it)->offset(offset);
+ }
+ }
+}
+
+void QBBWindow::offset(const QPoint &offset)
+{
+ // 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(mWindow, SCREEN_PROPERTY_POSITION, val);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to set window position, errno=%d", errno);
+ }
+
+ QList<QBBWindow*>::iterator it;
+ for (it = mChildren.begin(); it != mChildren.end(); it++) {
+ (*it)->offset(offset);
+ }
+}
+
+void QBBWindow::setVisible(bool visible)
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << "QBBWindow::setVisible - w=" << widget() << ", v=" << visible;
+#endif
+
+ mVisible = visible;
+
+ QBBWindow* root = this;
+ while (root->mParent)
+ root = root->mParent;
+
+ root->updateVisibility(root->mVisible);
+
+ widget()->activateWindow();
+}
+
+void QBBWindow::updateVisibility(bool parentVisible)
+{
+ // set window visibility
+ errno = 0;
+ int val = (mVisible && parentVisible) ? 1 : 0;
+ int result = screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_VISIBLE, &val);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to set window visibility, errno=%d", errno);
+ }
+
+ QList<QBBWindow*>::iterator it;
+ for (it = mChildren.begin(); it != mChildren.end(); it++) {
+ (*it)->updateVisibility(mVisible && parentVisible);
+ }
+}
+
+void QBBWindow::setOpacity(qreal level)
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << "QBBWindow::setOpacity - w=" << widget() << ", o=" << level;
+#endif
+
+ // set window global alpha
+ errno = 0;
+ int val = (int)(level * 255);
+ int result = screen_set_window_property_iv(mWindow, 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() << "QBBWindow::setBufferSize - w=" << widget() << ", s=" << size;
+#endif
+
+ // set window buffer size
+ errno = 0;
+ int val[2] = { size.width(), size.height() };
+ int result = screen_set_window_property_iv(mWindow, 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()) {
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << "QBBWindow::setBufferSize - create buffers";
+#endif
+
+ // get pixel format from EGL config if using OpenGL;
+ // otherwise inherit pixel format of window's screen
+ if (mPlatformGlContext != NULL) {
+ val[0] = platformWindowFormatToNativeFormat(mPlatformGlContext->platformWindowFormat());
+ } else {
+ val[0] = mScreen->nativeFormat();
+ }
+
+ errno = 0;
+ result = screen_set_window_property_iv(mWindow, 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(mWindow, MAX_BUFFER_COUNT);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to create window buffers, errno=%d", errno);
+ }
+ }
+
+ // cache new buffer size
+ mBufferSize = size;
+
+ // buffers were destroyed; reacquire them
+ mCurrentBufferIndex = -1;
+ mPreviousDirty = QRegion();
+ mScrolled = QRegion();
+}
+
+QBBBuffer &QBBWindow::renderBuffer()
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << "QBBWindow::renderBuffer - w=" << widget();
+#endif
+
+ // check if render buffer is invalid
+ if (mCurrentBufferIndex == -1) {
+
+ // get all buffers available for rendering
+ errno = 0;
+ screen_buffer_t buffers[MAX_BUFFER_COUNT];
+ int result = screen_get_window_property_pv(mWindow, 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++) {
+ mBuffers[i] = QBBBuffer(buffers[i]);
+ }
+
+ // use the first available render buffer
+ mCurrentBufferIndex = 0;
+ mPreviousBufferIndex = -1;
+ }
+
+ return mBuffers[mCurrentBufferIndex];
+}
+
+void QBBWindow::scroll(const QRegion &region, int dx, int dy, bool flush)
+{
+ copyBack(region, dx, dy, flush);
+ mScrolled += region;
+}
+
+void QBBWindow::post(const QRegion &dirty)
+{
+ // check if render buffer exists and something was rendered
+ if (mCurrentBufferIndex != -1 && !dirty.isEmpty()) {
+
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << "QBBWindow::post - w=" << widget();
+#endif
+ QBBBuffer &currentBuffer = mBuffers[mCurrentBufferIndex];
+
+ // copy unmodified region from old render buffer to new render buffer;
+ // required to allow partial updates
+ QRegion preserve = mPreviousDirty - dirty - mScrolled;
+ copyBack(preserve, 0, 0);
+
+ // calculate region that changed
+ QRegion modified = preserve + dirty + mScrolled;
+ 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(mWindow, currentBuffer.nativeBuffer(), 1, dirtyRect, 0);
+ if (result != 0) {
+ qFatal("QBBWindow: failed to post window buffer, errno=%d", errno);
+ }
+
+ // advance to next nender buffer
+ mPreviousBufferIndex = mCurrentBufferIndex++;
+ if (mCurrentBufferIndex >= MAX_BUFFER_COUNT) {
+ mCurrentBufferIndex = 0;
+ }
+
+ // save modified region and clear scrolled region
+ mPreviousDirty = dirty;
+ mScrolled = QRegion();
+
+ // notify screen that window posted
+ if (mScreen != NULL) {
+ mScreen->onWindowPost(this);
+ }
+ }
+}
+
+QPlatformGLContext *QBBWindow::glContext() const
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << "QBBWindow::glContext - w=" << widget();
+#endif
+ // create opengl context on first access if rendering API is correct
+ QPlatformWindowFormat format = widget()->platformWindowFormat();
+ if (mPlatformGlContext == NULL && format.windowApi() == QPlatformWindowFormat::OpenGL) {
+ mPlatformGlContext = new QBBGLContext( const_cast<QBBWindow*>(this) );
+ }
+ return mPlatformGlContext;
+}
+
+void QBBWindow::setScreen(QBBScreen *platformScreen)
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << "QBBWindow::setScreen - w=" << widget();
+#endif
+
+ if (mScreen == platformScreen)
+ return;
+
+ mScreen = platformScreen;
+
+ // The display may not have a root (desktop) window yet so we must ensure that one has been
+ // created before we can join its group or get its native display property.
+ mScreen->ensureDisplayCreated();
+
+ // move window to proper display
+ errno = 0;
+ screen_display_t display = platformScreen->nativeDisplay();
+ int result = screen_set_window_property_pv(mWindow, 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(mWindow, platformScreen->windowGroupName());
+ if (result != 0) {
+ qFatal("QBBWindow: failed to join window group, errno=%d", errno);
+ }
+
+ QList<QBBWindow*>::iterator it;
+ for (it = mChildren.begin(); it != mChildren.end(); it++) {
+ // Only subwindows and tooltips need necessarily be moved to another display with
+ // the window.
+ if ((widget()->windowType() & Qt::WindowType_Mask) == Qt::SubWindow ||
+ (widget()->windowType() & Qt::WindowType_Mask) == Qt::ToolTip)
+ (*it)->setScreen(platformScreen);
+ }
+
+ QBBScreen::updateHierarchy();
+}
+
+void QBBWindow::removeFromParent()
+{
+ // Remove from old Hierarchy position
+ if (mParent) {
+ if (mParent->mChildren.removeAll(this))
+ mParent = 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() << "QBBWindow::setParent - w=" << widget() << " p=" << 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 == mParent)
+ return;
+
+ removeFromParent();
+ mParent = newParent;
+
+ // Add to new Hierarchy position.
+ if (mParent) {
+ if (mParent->mScreen != mScreen)
+ setScreen(mParent->mScreen);
+
+ mParent->mChildren.push_back(this);
+ } else {
+ QBBScreen::addWindow(this);
+ }
+
+ QBBScreen::updateHierarchy();
+}
+
+void QBBWindow::raise()
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << "QBBWindow::raise - w=" << widget();
+#endif
+
+ QBBWindow* oldParent = mParent;
+ if (oldParent) {
+ removeFromParent();
+ oldParent->mChildren.push_back(this);
+ } else {
+ QBBScreen::raiseWindow(this);
+ }
+
+ QBBScreen::updateHierarchy();
+}
+
+void QBBWindow::lower()
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << "QBBWindow::lower - w=" << widget();
+#endif
+
+ QBBWindow* oldParent = mParent;
+ if (oldParent) {
+ removeFromParent();
+ oldParent->mChildren.push_front(this);
+ } else {
+ QBBScreen::lowerWindow(this);
+ }
+
+ QBBScreen::updateHierarchy();
+}
+
+void QBBWindow::requestActivateWindow()
+{
+#if defined(QBBWINDOW_DEBUG)
+ qDebug() << "QBBWindow::requestActivateWindow - w=" << widget();
+#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() << "QBBWindow::gainedFocus - w=" << widget();
+#endif
+
+ // Got focus
+ QWindowSystemInterface::handleWindowActivated(widget());
+}
+
+void QBBWindow::updateZorder(int &topZorder)
+{
+ errno = 0;
+ int result = screen_set_window_property_iv(mWindow, SCREEN_PROPERTY_ZORDER, &topZorder);
+ topZorder++;
+
+ if (result != 0)
+ qFatal("QBBWindow: failed to set window z-order=%d, errno=%d, mWindow=0x%08x", topZorder, errno, mWindow);
+
+ QList<QBBWindow*>::const_iterator it;
+
+ for (it = mChildren.begin(); it != mChildren.end(); it++)
+ (*it)->updateZorder(topZorder);
+}
+
+void QBBWindow::copyBack(const QRegion &region, int dx, int dy, bool flush)
+{
+ int result;
+
+ // abort if previous buffer is invalid
+ if (mPreviousBufferIndex == -1) {
+ return;
+ }
+
+ // abort if nothing to copy
+ if (region.isEmpty()) {
+ return;
+ }
+
+ QBBBuffer &currentBuffer = mBuffers[mCurrentBufferIndex];
+ QBBBuffer &previousBuffer = mBuffers[mPreviousBufferIndex];
+
+ // 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(mContext, 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(mContext, 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 QPlatformWindowFormat &format)
+{
+ // 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 0000000..5168dfa
--- /dev/null
+++ b/src/plugins/platforms/blackberry/qbbwindow.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 - 2012 Research In Motion
+**
+** Contact: Research In Motion <blackberry-qt@qnx.com>
+** Contact: Klarälvdalens Datakonsult AB <info@kdab.com>
+**
+** This file is part of the QtCore module 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.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBBWINDOW_H
+#define QBBWINDOW_H
+
+#include "qbbbuffer.h"
+
+#include <QImage>
+#include <QtGui/QPlatformWindow>
+
+#include <screen/screen.h>
+#include <EGL/egl.h>
+
+QT_BEGIN_NAMESPACE
+
+// all surfaces double buffered
+#define MAX_BUFFER_COUNT 2
+
+class QPlatformWindowFormat;
+class QBBGLContext;
+class QBBScreen;
+
+class QBBWindow : public QPlatformWindow
+{
+friend class QBBScreen;
+public:
+ QBBWindow(QWidget *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)mWindow; }
+
+ void setBufferSize(const QSize &size);
+ QSize bufferSize() const { return mBufferSize; }
+ bool hasBuffers() const { return !mBufferSize.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 QPlatformGLContext *glContext() const;
+
+ virtual void setParent(const QPlatformWindow *window);
+ virtual void raise();
+ virtual void lower();
+ virtual void requestActivateWindow();
+
+ void gainedFocus();
+
+ QBBScreen* screen() const { return mScreen; }
+ const QList<QBBWindow*>& children() const { return mChildren; }
+
+private:
+ screen_context_t mContext;
+ screen_window_t mWindow;
+ QSize mBufferSize;
+ QBBBuffer mBuffers[MAX_BUFFER_COUNT];
+ int mCurrentBufferIndex;
+ int mPreviousBufferIndex;
+ QRegion mPreviousDirty;
+ QRegion mScrolled;
+
+ mutable QBBGLContext* mPlatformGlContext;
+ QBBScreen* mScreen;
+ QList<QBBWindow*> mChildren;
+ QBBWindow *mParent;
+ bool mVisible;
+
+ 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 QPlatformWindowFormat &format);
+};
+
+QT_END_NAMESPACE
+
+#endif // QBBWINDOW_H