Initial import of the Blackberry QPA plugin for Qt5

This is dependent upon the following Change Id's:

I5ebcffb7153f4216d69921d4818051e6b3d14d8a
Iec065f528f5edd848be580807a607488dc2e401f

Change-Id: I234e3c4272d7474d8f8e20fc4fea20d95c829cb5
Reviewed-by: Kevin Krammer <kevin.krammer@kdab.com>
Reviewed-by: Jørgen Lind <jorgen.lind@nokia.com>
This commit is contained in:
Sean Harmer 2012-01-19 20:10:43 +00:00 committed by Qt by Nokia
parent 151f17d7e6
commit 87366cc7ab
32 changed files with 7553 additions and 0 deletions

View File

@ -0,0 +1,71 @@
TARGET = blackberry
include(../../qpluginbase.pri)
QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms
QT += opengl opengl-private platformsupport platformsupport-private widgets-private
# Uncomment this to build with support for IMF once it becomes available in the BBNDK
#CONFIG += qbb_imf
# Uncomment these to enable debugging output for various aspects of the plugin
#DEFINES += QBBBUFFER_DEBUG
#DEFINES += QBBCLIPBOARD_DEBUG
#DEFINES += QBBEVENTTHREAD_DEBUG
#DEFINES += QBBGLBACKINGSTORE_DEBUG
#DEFINES += QBBGLCONTEXT_DEBUG
#DEFINES += QBBINPUTCONTEXT_DEBUG
#DEFINES += QBBINPUTCONTEXT_IMF_EVENT_DEBUG
#DEFINES += QBBINTEGRATION_DEBUG
#DEFINES += QBBNAVIGATORTHREAD_DEBUG
#DEFINES += QBBRASTERBACKINGSTORE_DEBUG
#DEFINES += QBBROOTWINDOW_DEBUG
#DEFINES += QBBSCREEN_DEBUG
#DEFINES += QBBVIRTUALKEYBOARD_DEBUG
#DEFINES += QBBWINDOW_DEBUG
SOURCES = main.cpp \
qbbbuffer.cpp \
qbbeventthread.cpp \
qbbglcontext.cpp \
qbbglbackingstore.cpp \
qbbintegration.cpp \
qbbnavigatorthread.cpp \
qbbscreen.cpp \
qbbwindow.cpp \
qbbrasterbackingstore.cpp \
qbbvirtualkeyboard.cpp \
qbbclipboard.cpp \
qbbrootwindow.cpp
HEADERS = qbbbuffer.h \
qbbeventthread.h \
qbbkeytranslator.h \
qbbintegration.h \
qbbnavigatorthread.h \
qbbglcontext.h \
qbbglbackingstore.h \
qbbscreen.h \
qbbwindow.h \
qbbrasterbackingstore.h \
qbbvirtualkeyboard.h \
qbbclipboard.h \
qbbrootwindow.h
CONFIG(qbb_imf) {
DEFINES += QBB_IMF
HEADERS += qbbinputcontext_imf.h
SOURCES += qbbinputcontext_imf.cpp
} else {
HEADERS += qbbinputcontext_noimf.h
SOURCES += qbbinputcontext_noimf.cpp
}
QMAKE_CXXFLAGS += -I./private
LIBS += -lpps -lscreen -lEGL -lclipboard
include (../../../platformsupport/eglconvenience/eglconvenience.pri)
include (../../../platformsupport/fontdatabases/fontdatabases.pri)
target.path += $$[QT_INSTALL_PLUGINS]/platforms
INSTALLS += target

View File

@ -0,0 +1,72 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtGui/QPlatformIntegrationPlugin>
#include "qbbintegration.h"
QT_BEGIN_NAMESPACE
class QBBIntegrationPlugin : public QPlatformIntegrationPlugin
{
public:
QStringList keys() const;
QPlatformIntegration *create(const QString&, const QStringList&);
};
QStringList QBBIntegrationPlugin::keys() const
{
QStringList list;
list << QLatin1String("blackberry");
return list;
}
QPlatformIntegration *QBBIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
Q_UNUSED(paramList);
if (system.toLower() == QLatin1String("blackberry"))
return new QBBIntegration;
return 0;
}
Q_EXPORT_PLUGIN2(blackberry, QBBIntegrationPlugin)
QT_END_NAMESPACE

View File

@ -0,0 +1,165 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qbbbuffer.h"
#include <QtCore/QDebug>
#include <errno.h>
#include <sys/mman.h>
QT_BEGIN_NAMESPACE
QBBBuffer::QBBBuffer()
: m_buffer(0)
{
#if defined(QBBBUFFER_DEBUG)
qDebug() << "QBBBuffer::QBBBuffer - empty";
#endif
}
QBBBuffer::QBBBuffer(screen_buffer_t buffer)
: m_buffer(buffer)
{
#if defined(QBBBUFFER_DEBUG)
qDebug() << "QBBBuffer::QBBBuffer - normal";
#endif
// Get size of buffer
errno = 0;
int size[2];
int result = screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_BUFFER_SIZE, size);
if (result != 0) {
qFatal("QBB: failed to query buffer size, errno=%d", errno);
}
// Get stride of buffer
errno = 0;
int stride;
result = screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_STRIDE, &stride);
if (result != 0) {
qFatal("QBB: failed to query buffer stride, errno=%d", errno);
}
// Get access to buffer's data
errno = 0;
uchar *dataPtr = 0;
result = screen_get_buffer_property_pv(buffer, SCREEN_PROPERTY_POINTER, (void **)&dataPtr);
if (result != 0) {
qFatal("QBB: failed to query buffer pointer, errno=%d", errno);
}
if (dataPtr == NULL) {
qFatal("QBB: buffer pointer is NULL, errno=%d", errno);
}
// Get format of buffer
errno = 0;
int screenFormat;
result = screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_FORMAT, &screenFormat);
if (result != 0) {
qFatal("QBB: failed to query buffer format, errno=%d", errno);
}
// Convert screen format to QImage format
QImage::Format imageFormat = QImage::Format_Invalid;
switch (screenFormat) {
case SCREEN_FORMAT_RGBX4444:
imageFormat = QImage::Format_RGB444;
break;
case SCREEN_FORMAT_RGBA4444:
imageFormat = QImage::Format_ARGB4444_Premultiplied;
break;
case SCREEN_FORMAT_RGBX5551:
imageFormat = QImage::Format_RGB555;
break;
case SCREEN_FORMAT_RGB565:
imageFormat = QImage::Format_RGB16;
break;
case SCREEN_FORMAT_RGBX8888:
imageFormat = QImage::Format_RGB32;
break;
case SCREEN_FORMAT_RGBA8888:
imageFormat = QImage::Format_ARGB32_Premultiplied;
break;
default:
qFatal("QBB: unsupported buffer format, format=%d", screenFormat);
}
// wrap buffer in an image
m_image = QImage(dataPtr, size[0], size[1], stride, imageFormat);
}
QBBBuffer::QBBBuffer(const QBBBuffer &other)
: m_buffer(other.m_buffer),
m_image(other.m_image)
{
#if defined(QBBBUFFER_DEBUG)
qDebug() << "QBBBuffer::QBBBuffer - copy";
#endif
}
QBBBuffer::~QBBBuffer()
{
#if defined(QBBBUFFER_DEBUG)
qDebug() << "QBBBuffer::~QBBBuffer";
#endif
}
void QBBBuffer::invalidateInCache()
{
#if defined(QBBBUFFER_DEBUG)
qDebug() << "QBBBuffer::invalidateInCache";
#endif
// Verify native buffer exists
if (m_buffer == 0) {
qFatal("QBB: can't invalidate cache for null buffer");
}
// Evict buffer's data from cache
errno = 0;
int result = msync(m_image.bits(), m_image.height() * m_image.bytesPerLine(), MS_INVALIDATE | MS_CACHE_ONLY);
if (result != 0) {
qFatal("QBB: failed to invalidate cache, errno=%d", errno);
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,74 @@
/****************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBBBUFFER_H
#define QBBBUFFER_H
#include <QtGui/QImage>
#include <screen/screen.h>
QT_BEGIN_NAMESPACE
class QBBBuffer
{
public:
QBBBuffer();
QBBBuffer(screen_buffer_t buffer);
QBBBuffer(const QBBBuffer &other);
virtual ~QBBBuffer();
screen_buffer_t nativeBuffer() const { return m_buffer; }
const QImage *image() const { return (m_buffer != NULL) ? &m_image : NULL; }
QImage *image() { return (m_buffer != NULL) ? &m_image : NULL; }
QRect rect() const { return m_image.rect(); }
void invalidateInCache();
private:
screen_buffer_t m_buffer;
QImage m_image;
};
QT_END_NAMESPACE
#endif // QBBBUFFER_H

View File

@ -0,0 +1,132 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QT_NO_CLIPBOARD
#include "qbbclipboard.h"
#include <QtGui/QColor>
#include <QtCore/QDebug>
#include <QtCore/QStringList>
#include <QtCore/QUrl>
#include <clipboard/clipboard.h>
#include <errno.h>
QT_BEGIN_NAMESPACE
static const char *typeList[] = {"text/html", "text/plain", "application/x-color"};
QBBClipboard::QBBClipboard()
{
m_mimeData = 0;
}
QBBClipboard::~QBBClipboard()
{
delete m_mimeData;
}
void QBBClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
{
if (mode != QClipboard::Clipboard)
return;
if (m_mimeData != data) {
delete m_mimeData;
m_mimeData = data;
}
empty_clipboard();
if (data == 0)
return;
QStringList format = data->formats();
for (int i = 0; i < format.size(); ++i) {
QString type = format.at(i);
QByteArray buf = data->data(type);
if (!buf.size())
continue;
int ret = set_clipboard_data(type.toUtf8().data(), buf.size(), buf.data());
#if defined(QBBCLIPBOARD_DEBUG)
qDebug() << "QBB: set " << type.toUtf8().data() << "to clipboard, size=" << buf.size() << ";ret=" << ret;
#else
Q_UNUSED(ret);
#endif
}
}
void QBBClipboard::readClipboardBuff(const char *type)
{
char *pbuffer;
if (is_clipboard_format_present(type) == 0) {
int size = get_clipboard_data(type, &pbuffer);
if (size != -1 && pbuffer) {
QString qtype = type;
#if defined(QBBCLIPBOARD_DEBUG)
qDebug() << "QBB: clipboard has " << qtype;
#endif
m_mimeData->setData(qtype, QByteArray(pbuffer, size));
delete pbuffer;
}
}
}
QMimeData *QBBClipboard::mimeData(QClipboard::Mode mode)
{
if (mode != QClipboard::Clipboard)
return 0;
if (!m_mimeData)
m_mimeData = new QMimeData();
m_mimeData->clear();
for (int i = 0; i < 3; i++)
readClipboardBuff(typeList[i]);
return m_mimeData;
}
QT_END_NAMESPACE
#endif //QT_NO_CLIPBOAR

View File

@ -0,0 +1,67 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBBCLIPBOARD_H
#define QBBCLIPBOARD_H
#ifndef QT_NO_CLIPBOARD
#include <QtGui/QPlatformClipboard>
#include <QMimeData>
QT_BEGIN_NAMESPACE
class QBBClipboard : public QPlatformClipboard
{
public:
QBBClipboard();
virtual ~QBBClipboard();
virtual QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard);
virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard);
private:
QMimeData *m_mimeData;
void readClipboardBuff(const char *type);
};
QT_END_NAMESPACE
#endif //QT_NO_CLIPBOARD
#endif //QBBCLIPBOARD_H

View File

@ -0,0 +1,559 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qbbeventthread.h"
#include "qbbintegration.h"
#include "qbbkeytranslator.h"
#if defined(QBB_IMF)
#include "qbbinputcontext_imf.h"
#else
#include "qbbinputcontext_noimf.h"
#endif
#include <QtGui/QWindow>
#include <QtGui/QPlatformScreen>
#include <QtGui/QGuiApplication>
#include <QtCore/QDebug>
#include <errno.h>
#include <unistd.h>
#include <sys/keycodes.h>
#include <cctype>
QBBEventThread::QBBEventThread(screen_context_t context, QPlatformScreen& screen)
: QThread(),
m_screenContext(context),
m_platformScreen(screen),
m_quit(false),
m_lastButtonState(Qt::NoButton),
m_lastMouseWindow(0)
{
// Create a touch device
m_touchDevice = new QTouchDevice;
m_touchDevice->setType(QTouchDevice::TouchScreen);
m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition);
QWindowSystemInterface::registerTouchDevice(m_touchDevice);
// initialize array of touch points
for (int i = 0; i < MaximumTouchPoints; i++) {
// map array index to id
m_touchPoints[i].id = i;
// pressure is not supported - use default
m_touchPoints[i].pressure = 1.0;
// nothing touching
m_touchPoints[i].state = Qt::TouchPointReleased;
}
}
QBBEventThread::~QBBEventThread()
{
// block until thread terminates
shutdown();
}
void QBBEventThread::run()
{
screen_event_t event;
// create screen event
errno = 0;
int result = screen_create_event(&event);
if (result) {
qFatal("QBB: failed to create event, errno=%d", errno);
}
#if defined(QBBEVENTTHREAD_DEBUG)
qDebug() << "QBB: event loop started";
#endif
// loop indefinitely
while (!m_quit) {
// block until screen event is available
errno = 0;
result = screen_get_event(m_screenContext, event, -1);
if (result) {
qFatal("QBB: failed to get event, errno=%d", errno);
}
// process received event
dispatchEvent(event);
}
#if defined(QBBEVENTTHREAD_DEBUG)
qDebug() << "QBB: event loop stopped";
#endif
// cleanup
screen_destroy_event(event);
}
void QBBEventThread::shutdown()
{
screen_event_t event;
// create screen event
errno = 0;
int result = screen_create_event(&event);
if (result) {
qFatal("QBB: failed to create event, errno=%d", errno);
}
// set the event type as user
errno = 0;
int type = SCREEN_EVENT_USER;
result = screen_set_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type);
if (result) {
qFatal("QBB: failed to set event type, errno=%d", errno);
}
// NOTE: ignore SCREEN_PROPERTY_USER_DATA; treat all user events as shutdown events
// post event to event loop so it will wake up and die
errno = 0;
result = screen_send_event(m_screenContext, event, getpid());
if (result) {
qFatal("QBB: failed to set event type, errno=%d", errno);
}
// cleanup
screen_destroy_event(event);
#if defined(QBBEVENTTHREAD_DEBUG)
qDebug() << "QBB: event loop shutdown begin";
#endif
// block until thread terminates
wait();
#if defined(QBBEVENTTHREAD_DEBUG)
qDebug() << "QBB: event loop shutdown end";
#endif
}
void QBBEventThread::dispatchEvent(screen_event_t event)
{
// get the event type
errno = 0;
int qnxType;
int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &qnxType);
if (result) {
qFatal("QBB: failed to query event type, errno=%d", errno);
}
switch (qnxType) {
case SCREEN_EVENT_MTOUCH_TOUCH:
case SCREEN_EVENT_MTOUCH_MOVE:
case SCREEN_EVENT_MTOUCH_RELEASE:
handleTouchEvent(event, qnxType);
break;
case SCREEN_EVENT_KEYBOARD:
handleKeyboardEvent(event);
break;
case SCREEN_EVENT_POINTER:
handlePointerEvent(event);
break;
case SCREEN_EVENT_CLOSE:
handleCloseEvent(event);
break;
case SCREEN_EVENT_USER:
// treat all user events as shutdown requests
#if defined(QBBEVENTTHREAD_DEBUG)
qDebug() << "QBB: QNX user event";
#endif
m_quit = true;
break;
default:
// event ignored
#if defined(QBBEVENTTHREAD_DEBUG)
qDebug() << "QBB: QNX unknown event";
#endif
break;
}
}
void QBBEventThread::handleKeyboardEvent(screen_event_t event)
{
// get flags of key event
errno = 0;
int flags;
int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_FLAGS, &flags);
if (result) {
qFatal("QBB: failed to query event flags, errno=%d", errno);
}
// get key code
errno = 0;
int sym;
result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_SYM, &sym);
if (result) {
qFatal("QBB: failed to query event sym, errno=%d", errno);
}
int modifiers;
result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_MODIFIERS, &modifiers);
if (result) {
qFatal("QBB: failed to query event modifiers, errno=%d", errno);
}
int scan;
result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_SCAN, &scan);
if (result) {
qFatal("QBB: failed to query event modifiers, errno=%d", errno);
}
int cap;
result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_CAP, &cap);
if (result) {
qFatal("QBB: failed to query event cap, errno=%d", errno);
}
injectKeyboardEvent(flags, sym, modifiers, scan, cap);
}
void QBBEventThread::injectKeyboardEvent(int flags, int sym, int modifiers, int scan, int cap)
{
Q_UNUSED(scan);
Qt::KeyboardModifiers qtMod = Qt::NoModifier;
if (modifiers & KEYMOD_SHIFT)
qtMod |= Qt::ShiftModifier;
if (modifiers & KEYMOD_CTRL)
qtMod |= Qt::ControlModifier;
if (modifiers & KEYMOD_ALT)
qtMod |= Qt::AltModifier;
// determine event type
QEvent::Type type = (flags & KEY_DOWN) ? QEvent::KeyPress : QEvent::KeyRelease;
// Check if the key cap is valid
if (flags & KEY_CAP_VALID) {
Qt::Key key;
QString keyStr;
if (cap >= 0x20 && cap <= 0x0ff) {
key = Qt::Key(std::toupper(cap)); // Qt expects the CAP to be upper case.
if ( qtMod & Qt::ControlModifier ) {
keyStr = QChar((int)(key & 0x3f));
} else {
if (flags & KEY_SYM_VALID) {
keyStr = QChar(sym);
}
}
} else if ((cap > 0x0ff && cap < UNICODE_PRIVATE_USE_AREA_FIRST) || cap > UNICODE_PRIVATE_USE_AREA_LAST) {
key = (Qt::Key)cap;
keyStr = QChar(sym);
} else {
if (isKeypadKey(cap))
qtMod |= Qt::KeypadModifier; // Is this right?
key = keyTranslator(cap);
}
QWindowSystemInterface::handleKeyEvent(QGuiApplication::focusWindow(), type, key, qtMod, keyStr);
#if defined(QBBEVENTTHREAD_DEBUG)
qDebug() << "QBB: Qt key t=" << type << ", k=" << key << ", s=" << keyStr;
#endif
}
}
void QBBEventThread::handlePointerEvent(screen_event_t event)
{
errno = 0;
// Query the window that was clicked
screen_window_t qnxWindow;
void *handle;
int result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle);
if (result) {
qFatal("QBB: failed to query event window, errno=%d", errno);
}
qnxWindow = static_cast<screen_window_t>(handle);
// Query the button states
int buttonState = 0;
result = screen_get_event_property_iv(event, SCREEN_PROPERTY_BUTTONS, &buttonState);
if (result) {
qFatal("QBB: failed to query event button state, errno=%d", errno);
}
// Query the window position
int windowPos[2];
result = screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos);
if (result) {
qFatal("QBB: failed to query event window position, errno=%d", errno);
}
// Query the screen position
int pos[2];
result = screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos);
if (result) {
qFatal("QBB: failed to query event position, errno=%d", errno);
}
// Query the wheel delta
int wheelDelta = 0;
result = screen_get_event_property_iv(event, SCREEN_PROPERTY_MOUSE_WHEEL, &wheelDelta);
if (result) {
qFatal("QBB: failed to query event wheel delta, errno=%d", errno);
}
// Map window handle to top-level QWindow
QWindow *w = QBBIntegration::window(qnxWindow);
// Generate enter and leave events as needed.
if (qnxWindow != m_lastMouseWindow) {
QWindow *wOld = QBBIntegration::window(m_lastMouseWindow);
if (wOld) {
QWindowSystemInterface::handleLeaveEvent(wOld);
#if defined(QBBEVENTTHREAD_DEBUG)
qDebug() << "QBB: Qt leave, w=" << wOld;
#endif
}
if (w) {
QWindowSystemInterface::handleEnterEvent(w);
#if defined(QBBEVENTTHREAD_DEBUG)
qDebug() << "QBB: Qt enter, w=" << w;
#endif
}
}
m_lastMouseWindow = qnxWindow;
// Apply scaling to wheel delta and invert value for Qt. We'll probably want to scale
// this via a system preference at some point. But for now this is a sane value and makes
// the wheel usable.
wheelDelta *= -10;
// convert point to local coordinates
QPoint globalPoint(pos[0], pos[1]);
QPoint localPoint(windowPos[0], windowPos[1]);
// Convert buttons.
Qt::MouseButtons buttons = Qt::NoButton;
if (buttonState & 1)
buttons |= Qt::LeftButton;
if (buttonState & 2)
buttons |= Qt::MidButton;
if (buttonState & 4)
buttons |= Qt::RightButton;
if (w) {
// Inject mouse event into Qt only if something has changed.
if (m_lastGlobalMousePoint != globalPoint ||
m_lastLocalMousePoint != localPoint ||
m_lastButtonState != buttons) {
QWindowSystemInterface::handleMouseEvent(w, localPoint, globalPoint, buttons);
#if defined(QBBEVENTTHREAD_DEBUG)
qDebug() << "QBB: Qt mouse, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), b=" << static_cast<int>(buttons);
#endif
}
if (wheelDelta) {
// Screen only supports a single wheel, so we will assume Vertical orientation for
// now since that is pretty much standard.
QWindowSystemInterface::handleWheelEvent(w, localPoint, globalPoint, wheelDelta, Qt::Vertical);
#if defined(QBBEVENTTHREAD_DEBUG)
qDebug() << "QBB: Qt wheel, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), d=" << static_cast<int>(wheelDelta);
#endif
}
}
m_lastGlobalMousePoint = globalPoint;
m_lastLocalMousePoint = localPoint;
m_lastButtonState = buttons;
}
void QBBEventThread::handleTouchEvent(screen_event_t event, int qnxType)
{
// get display coordinates of touch
errno = 0;
int pos[2];
int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos);
if (result) {
qFatal("QBB: failed to query event position, errno=%d", errno);
}
// get window coordinates of touch
errno = 0;
int windowPos[2];
result = screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos);
if (result) {
qFatal("QBB: failed to query event window position, errno=%d", errno);
}
// determine which finger touched
errno = 0;
int touchId;
result = screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_ID, &touchId);
if (result) {
qFatal("QBB: failed to query event touch id, errno=%d", errno);
}
// determine which window was touched
errno = 0;
void *handle;
result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle);
if (result) {
qFatal("QBB: failed to query event window, errno=%d", errno);
}
screen_window_t qnxWindow = static_cast<screen_window_t>(handle);
// check if finger is valid
if (touchId < MaximumTouchPoints) {
// Map window handle to top-level QWindow
QWindow *w = QBBIntegration::window(qnxWindow);
// Generate enter and leave events as needed.
if (qnxWindow != m_lastMouseWindow) {
QWindow *wOld = QBBIntegration::window(m_lastMouseWindow);
if (wOld) {
QWindowSystemInterface::handleLeaveEvent(wOld);
#if defined(QBBEVENTTHREAD_DEBUG)
qDebug() << "QBB: Qt leave, w=" << wOld;
#endif
}
if (w) {
QWindowSystemInterface::handleEnterEvent(w);
#if defined(QBBEVENTTHREAD_DEBUG)
qDebug() << "QBB: Qt enter, w=" << w;
#endif
}
}
m_lastMouseWindow = qnxWindow;
if (w) {
// convert primary touch to mouse event
if (touchId == 0) {
// convert point to local coordinates
QPoint globalPoint(pos[0], pos[1]);
QPoint localPoint(windowPos[0], windowPos[1]);
// map touch state to button state
Qt::MouseButtons buttons = (qnxType == SCREEN_EVENT_MTOUCH_RELEASE) ? Qt::NoButton : Qt::LeftButton;
// inject event into Qt
QWindowSystemInterface::handleMouseEvent(w, localPoint, globalPoint, buttons);
#if defined(QBBEVENTTHREAD_DEBUG)
qDebug() << "QBB: Qt mouse, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), b=" << buttons;
#endif
}
// get size of screen which contains window
QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(w);
QSizeF screenSize = platformScreen->physicalSize();
// update cached position of current touch point
m_touchPoints[touchId].normalPosition = QPointF( static_cast<qreal>(pos[0]) / screenSize.width(), static_cast<qreal>(pos[1]) / screenSize.height() );
m_touchPoints[touchId].area = QRectF( pos[0], pos[1], 0.0, 0.0 );
// determine event type and update state of current touch point
QEvent::Type type = QEvent::None;
switch (qnxType) {
case SCREEN_EVENT_MTOUCH_TOUCH:
m_touchPoints[touchId].state = Qt::TouchPointPressed;
type = QEvent::TouchBegin;
break;
case SCREEN_EVENT_MTOUCH_MOVE:
m_touchPoints[touchId].state = Qt::TouchPointMoved;
type = QEvent::TouchUpdate;
break;
case SCREEN_EVENT_MTOUCH_RELEASE:
m_touchPoints[touchId].state = Qt::TouchPointReleased;
type = QEvent::TouchEnd;
break;
}
// build list of active touch points
QList<QWindowSystemInterface::TouchPoint> pointList;
for (int i = 0; i < MaximumTouchPoints; i++) {
if (i == touchId) {
// current touch point is always active
pointList.append(m_touchPoints[i]);
} else if (m_touchPoints[i].state != Qt::TouchPointReleased) {
// finger is down but did not move
m_touchPoints[i].state = Qt::TouchPointStationary;
pointList.append(m_touchPoints[i]);
}
}
// inject event into Qt
QWindowSystemInterface::handleTouchEvent(w, m_touchDevice, pointList);
#if defined(QBBEVENTTHREAD_DEBUG)
qDebug() << "QBB: Qt touch, w=" << w << ", p=(" << pos[0] << "," << pos[1] << "), t=" << type;
#endif
}
}
}
void QBBEventThread::handleCloseEvent(screen_event_t event)
{
// Query the window that was closed
void *handle;
int result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle);
if (result != 0) {
qFatal("QBB: failed to query event window, errno=%d", errno);
}
screen_window_t qnxWindow = static_cast<screen_window_t>(handle);
// Map window handle to top-level QWindow
QWindow *w = QBBIntegration::window(qnxWindow);
if (w != 0) {
QWindowSystemInterface::handleCloseEvent(w);
}
}

View File

@ -0,0 +1,90 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBBEVENTTHREAD_H
#define QBBEVENTTHREAD_H
#include <QtCore/QThread>
#include <QtGui/QPlatformScreen>
#include <QtGui/QWindowSystemInterface>
#include <screen/screen.h>
QT_BEGIN_NAMESPACE
class QBBEventThread : public QThread
{
public:
QBBEventThread(screen_context_t context, QPlatformScreen& screen);
virtual ~QBBEventThread();
static void injectKeyboardEvent(int flags, int sym, int mod, int scan, int cap);
protected:
virtual void run();
private:
enum {
MaximumTouchPoints = 10
};
void shutdown();
void dispatchEvent(screen_event_t event);
void handleKeyboardEvent(screen_event_t event);
void handlePointerEvent(screen_event_t event);
void handleTouchEvent(screen_event_t event, int type);
void handleCloseEvent(screen_event_t event);
screen_context_t m_screenContext;
QPlatformScreen& m_platformScreen;
bool m_quit;
QPoint m_lastGlobalMousePoint;
QPoint m_lastLocalMousePoint;
Qt::MouseButtons m_lastButtonState;
screen_window_t m_lastMouseWindow;
QTouchDevice *m_touchDevice;
QWindowSystemInterface::TouchPoint m_touchPoints[MaximumTouchPoints];
};
QT_END_NAMESPACE
#endif // QBBEVENTTHREAD_H

View File

@ -0,0 +1,189 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qbbglbackingstore.h"
#include "qbbglcontext.h"
#include "qbbwindow.h"
#include "qbbscreen.h"
#include <QtGui/qwindow.h>
#include <QtOpenGL/private/qgl_p.h>
#include <QtOpenGL/QGLContext>
#include <QtCore/QDebug>
#include <errno.h>
QT_BEGIN_NAMESPACE
QBBGLPaintDevice::QBBGLPaintDevice(QWindow *window)
: QGLPaintDevice(),
m_window(0),
m_glContext(0)
{
m_window = static_cast<QBBWindow*>(window->handle());
// Extract the QPlatformOpenGLContext from the window
QPlatformOpenGLContext *platformOpenGLContext = m_window->platformOpenGLContext();
// Convert this to a QGLContext
m_glContext = QGLContext::fromOpenGLContext(platformOpenGLContext->context());
}
QBBGLPaintDevice::~QBBGLPaintDevice()
{
// Cleanup GL context
delete m_glContext;
}
QPaintEngine *QBBGLPaintDevice::paintEngine() const
{
// Select a paint engine based on configued OpenGL version
return qt_qgl_paint_engine();
}
QSize QBBGLPaintDevice::size() const
{
// Get size of EGL surface
return m_window->geometry().size();
}
QBBGLBackingStore::QBBGLBackingStore(QWindow *window)
: QPlatformBackingStore(window),
m_openGLContext(0),
m_paintDevice(0),
m_requestedSize(),
m_size()
{
#if defined(QBBGLBACKINGSTORE_DEBUG)
qDebug() << "QBBGLBackingStore::QBBGLBackingStore - w=" << window;
#endif
// Create an OpenGL paint device which in turn creates a QGLContext for us
m_paintDevice = new QBBGLPaintDevice(window);
m_openGLContext = m_paintDevice->context()->contextHandle();
}
QBBGLBackingStore::~QBBGLBackingStore()
{
#if defined(QBBGLBACKINGSTORE_DEBUG)
qDebug() << "QBBGLBackingStore::~QBBGLBackingStore - w=" << window();
#endif
// cleanup OpenGL paint device
delete m_paintDevice;
}
void QBBGLBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
{
Q_UNUSED(region);
Q_UNUSED(offset);
#if defined(QBBGLBACKINGSTORE_DEBUG)
qDebug() << "QBBGLBackingStore::flush - w=" << window;
#endif
// update the display with newly rendered content
m_openGLContext->swapBuffers(window);
}
void QBBGLBackingStore::resize(const QSize &size, const QRegion &staticContents)
{
Q_UNUSED(staticContents);
#if defined(QBBGLBACKINGSTORE_DEBUG)
qDebug() << "QBBGLBackingStore::resize - w=" << window() << ", s=" << size;
#endif
// NOTE: defer resizing window buffers until next paint as
// resize() can be called multiple times before a paint occurs
m_requestedSize = size;
}
void QBBGLBackingStore::beginPaint(const QRegion &region)
{
Q_UNUSED(region);
#if defined(QBBGLBACKINGSTORE_DEBUG)
qDebug() << "QBBGLBackingStore::beginPaint - w=" << window();
#endif
// resize EGL surface if window surface resized
if (m_size != m_requestedSize) {
resizeSurface(m_requestedSize);
}
}
void QBBGLBackingStore::endPaint(const QRegion &region)
{
Q_UNUSED(region);
#if defined(QBBGLBACKINGSTORE_DEBUG)
qDebug() << "QBBGLBackingStore::endPaint - w=" << window();
#endif
}
void QBBGLBackingStore::resizeSurface(const QSize &size)
{
// need to destroy surface so make sure its not current
bool restoreCurrent = false;
QBBGLContext *platformContext = static_cast<QBBGLContext *>(m_openGLContext->handle());
if (platformContext->isCurrent()) {
m_openGLContext->doneCurrent();
restoreCurrent = true;
}
// destroy old EGL surface
platformContext->destroySurface();
// resize window's buffers
static_cast<QBBWindow*>(window()->handle())->setBufferSize(size);
// re-create EGL surface with new size
m_size = size;
platformContext->createSurface(window()->handle());
// make context current again
if (restoreCurrent) {
m_openGLContext->makeCurrent(window());
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,95 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBBGLBACKINGSTORE_H
#define QBBGLBACKINGSTORE_H
#include <QtGui/qplatformbackingstore_qpa.h>
#include <QtOpenGL/private/qglpaintdevice_p.h>
#include <screen/screen.h>
QT_BEGIN_NAMESPACE
class QGLContext;
class QBBGLContext;
class QBBScreen;
class QBBWindow;
class QBBGLPaintDevice : public QGLPaintDevice
{
public:
QBBGLPaintDevice(QWindow *window);
virtual ~QBBGLPaintDevice();
virtual QPaintEngine *paintEngine() const;
virtual QSize size() const;
virtual QGLContext *context() const { return m_glContext; }
private:
QBBWindow *m_window;
QGLContext *m_glContext;
};
class QBBGLBackingStore : public QPlatformBackingStore
{
public:
QBBGLBackingStore(QWindow *window);
virtual ~QBBGLBackingStore();
virtual QPaintDevice *paintDevice() { return m_paintDevice; }
virtual void flush(QWindow *window, const QRegion &region, const QPoint &offset);
virtual void resize(const QSize &size, const QRegion &staticContents);
virtual void beginPaint(const QRegion &region);
virtual void endPaint(const QRegion &region);
void resizeSurface(const QSize &size);
private:
QOpenGLContext *m_openGLContext;
QBBGLPaintDevice *m_paintDevice;
QSize m_requestedSize;
QSize m_size;
};
QT_END_NAMESPACE
#endif // QBBGLBACKINGSTORE_H

View File

@ -0,0 +1,356 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qbbglcontext.h"
#include "qbbrootwindow.h"
#include "qbbscreen.h"
#include "qbbwindow.h"
#include "private/qeglconvenience_p.h"
#include <QtCore/QDebug>
#include <QtGui/QOpenGLContext>
QT_BEGIN_NAMESPACE
EGLDisplay QBBGLContext::ms_eglDisplay = EGL_NO_DISPLAY;
static EGLenum checkEGLError(const char *msg)
{
static const char *errmsg[] =
{
"EGL function succeeded",
"EGL is not initialized, or could not be initialized, for the specified display",
"EGL cannot access a requested resource",
"EGL failed to allocate resources for the requested operation",
"EGL fail to access an unrecognized attribute or attribute value was passed in an attribute list",
"EGLConfig argument does not name a valid EGLConfig",
"EGLContext argument does not name a valid EGLContext",
"EGL current surface of the calling thread is no longer valid",
"EGLDisplay argument does not name a valid EGLDisplay",
"EGL arguments are inconsistent",
"EGLNativePixmapType argument does not refer to a valid native pixmap",
"EGLNativeWindowType argument does not refer to a valid native window",
"EGL one or more argument values are invalid",
"EGLSurface argument does not name a valid surface configured for rendering",
"EGL power management event has occurred",
};
EGLenum error = eglGetError();
fprintf(stderr, "%s: %s\n", msg, errmsg[error - EGL_SUCCESS]);
return error;
}
QBBGLContext::QBBGLContext(QOpenGLContext *glContext)
: QPlatformOpenGLContext(),
m_glContext(glContext),
m_eglSurface(EGL_NO_SURFACE)
{
#if defined(QBBGLCONTEXT_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
QSurfaceFormat format = m_glContext->format();
// Set current rendering API
EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
if (eglResult != EGL_TRUE) {
qFatal("QBB: failed to set EGL API, err=%d", eglGetError());
}
// Get colour channel sizes from window format
int alphaSize = format.alphaBufferSize();
int redSize = format.redBufferSize();
int greenSize = format.greenBufferSize();
int blueSize = format.blueBufferSize();
// Check if all channels are don't care
if (alphaSize == -1 && redSize == -1 && greenSize == -1 && blueSize == -1) {
// Set colour channels based on depth of window's screen
QBBScreen *screen = static_cast<QBBScreen*>(QBBScreen::screens().first());
int depth = screen->depth();
if (depth == 32) {
// SCREEN_FORMAT_RGBA8888
alphaSize = 8;
redSize = 8;
greenSize = 8;
blueSize = 8;
} else {
// SCREEN_FORMAT_RGB565
alphaSize = 0;
redSize = 5;
greenSize = 6;
blueSize = 5;
}
} else {
// Choose best match based on supported pixel formats
if (alphaSize <= 0 && redSize <= 5 && greenSize <= 6 && blueSize <= 5) {
// SCREEN_FORMAT_RGB565
alphaSize = 0;
redSize = 5;
greenSize = 6;
blueSize = 5;
} else {
// SCREEN_FORMAT_RGBA8888
alphaSize = 8;
redSize = 8;
greenSize = 8;
blueSize = 8;
}
}
// Update colour channel sizes in window format
format.setAlphaBufferSize(alphaSize);
format.setRedBufferSize(redSize);
format.setGreenBufferSize(greenSize);
format.setBlueBufferSize(blueSize);
format.setSamples(2);
// Select EGL config based on requested window format
m_eglConfig = q_configFromGLFormat(ms_eglDisplay, format);
if (m_eglConfig == 0) {
qFatal("QBB: failed to find EGL config");
}
m_eglContext = eglCreateContext(ms_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, contextAttrs());
if (m_eglContext == EGL_NO_CONTEXT) {
checkEGLError("eglCreateContext");
qFatal("QBB: failed to create EGL context, err=%d", eglGetError());
}
// Query/cache window format of selected EGL config
m_windowFormat = q_glFormatFromConfig(ms_eglDisplay, m_eglConfig);
}
QBBGLContext::~QBBGLContext()
{
#if defined(QBBGLCONTEXT_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// Cleanup EGL context if it exists
if (m_eglContext != EGL_NO_CONTEXT) {
eglDestroyContext(ms_eglDisplay, m_eglContext);
}
// Cleanup EGL surface if it exists
destroySurface();
}
void QBBGLContext::initialize()
{
#if defined(QBBGLCONTEXT_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// Initialize connection to EGL
ms_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (ms_eglDisplay == EGL_NO_DISPLAY) {
checkEGLError("eglGetDisplay");
qFatal("QBB: failed to obtain EGL display");
}
EGLBoolean eglResult = eglInitialize(ms_eglDisplay, 0, 0);
if (eglResult != EGL_TRUE) {
checkEGLError("eglInitialize");
qFatal("QBB: failed to initialize EGL display, err=%d", eglGetError());
}
}
void QBBGLContext::shutdown()
{
#if defined(QBBGLCONTEXT_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// Close connection to EGL
eglTerminate(ms_eglDisplay);
}
bool QBBGLContext::makeCurrent(QPlatformSurface *surface)
{
#if defined(QBBGLCONTEXT_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// Set current rendering API
EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
if (eglResult != EGL_TRUE) {
qFatal("QBB: failed to set EGL API, err=%d", eglGetError());
}
if (m_eglSurface == EGL_NO_SURFACE)
createSurface(surface);
eglResult = eglMakeCurrent(ms_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
if (eglResult != EGL_TRUE) {
checkEGLError("eglMakeCurrent");
qFatal("QBB: failed to set current EGL context, err=%d", eglGetError());
}
return (eglResult == EGL_TRUE);
}
void QBBGLContext::doneCurrent()
{
#if defined(QBBGLCONTEXT_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// set current rendering API
EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
if (eglResult != EGL_TRUE) {
qFatal("QBB: failed to set EGL API, err=%d", eglGetError());
}
// clear curent EGL context and unbind EGL surface
eglResult = eglMakeCurrent(ms_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (eglResult != EGL_TRUE) {
qFatal("QBB: failed to clear current EGL context, err=%d", eglGetError());
}
}
void QBBGLContext::swapBuffers(QPlatformSurface *surface)
{
Q_UNUSED(surface);
#if defined(QBBGLCONTEXT_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// Set current rendering API
EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
if (eglResult != EGL_TRUE) {
qFatal("QBB: failed to set EGL API, err=%d", eglGetError());
}
// Post EGL surface to window
eglResult = eglSwapBuffers(ms_eglDisplay, m_eglSurface);
if (eglResult != EGL_TRUE) {
qFatal("QBB: failed to swap EGL buffers, err=%d", eglGetError());
}
}
QFunctionPointer QBBGLContext::getProcAddress(const QByteArray &procName)
{
#if defined(QBBGLCONTEXT_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// Set current rendering API
EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API);
if (eglResult != EGL_TRUE) {
qFatal("QBB: failed to set EGL API, err=%d", eglGetError());
}
// Lookup EGL extension function pointer
return static_cast<QFunctionPointer>(eglGetProcAddress(procName.constData()));
}
EGLint *QBBGLContext::contextAttrs()
{
#if defined(QBBGLCONTEXT_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// Choose EGL settings based on OpenGL version
#if defined(QT_OPENGL_ES_2)
static EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
return attrs;
#else
return 0;
#endif
}
bool QBBGLContext::isCurrent() const
{
#if defined(QBBGLCONTEXT_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
return (eglGetCurrentContext() == m_eglContext);
}
void QBBGLContext::createSurface(QPlatformSurface *surface)
{
#if defined(QBBGLCONTEXT_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// Get a pointer to the corresponding platform window
QBBWindow *platformWindow = dynamic_cast<QBBWindow*>(surface);
if (!platformWindow) {
qFatal("QBB: unable to create EGLSurface without a QBBWindow");
}
// If the platform window does not yet have any buffers, we create
// a temporary set of buffers with a size of 1x1 pixels. This will
// suffice until such time as the platform window has obtained
// buffers of the proper size
if (!platformWindow->hasBuffers()) {
platformWindow->setPlatformOpenGLContext(this);
m_surfaceSize = platformWindow->geometry().size();
platformWindow->setBufferSize(m_surfaceSize);
}
// Obtain the native handle for our window
screen_window_t handle = platformWindow->nativeHandle();
const EGLint eglSurfaceAttrs[] =
{
EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
EGL_NONE
};
// Create EGL surface
m_eglSurface = eglCreateWindowSurface(ms_eglDisplay, m_eglConfig, (EGLNativeWindowType) handle, eglSurfaceAttrs);
if (m_eglSurface == EGL_NO_SURFACE) {
checkEGLError("eglCreateWindowSurface");
qFatal("QBB: failed to create EGL surface, err=%d", eglGetError());
}
}
void QBBGLContext::destroySurface()
{
#if defined(QBBGLCONTEXT_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// Destroy EGL surface if it exists
if (m_eglSurface != EGL_NO_SURFACE) {
EGLBoolean eglResult = eglDestroySurface(ms_eglDisplay, m_eglSurface);
if (eglResult != EGL_TRUE) {
qFatal("QBB: failed to destroy EGL surface, err=%d", eglGetError());
}
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,93 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBBGLCONTEXT_H
#define QBBGLCONTEXT_H
#include <QtGui/QPlatformOpenGLContext>
#include <QtGui/QSurfaceFormat>
#include <QtCore/QSize>
#include <EGL/egl.h>
QT_BEGIN_NAMESPACE
class QBBWindow;
class QBBGLContext : public QPlatformOpenGLContext
{
public:
QBBGLContext(QOpenGLContext *glContext);
virtual ~QBBGLContext();
static void initialize();
static void shutdown();
virtual bool makeCurrent(QPlatformSurface *surface);
virtual void doneCurrent();
virtual void swapBuffers(QPlatformSurface *surface);
virtual QFunctionPointer getProcAddress(const QByteArray &procName);
virtual QSurfaceFormat format() const { return m_windowFormat; }
bool isCurrent() const;
void createSurface(QPlatformSurface *surface);
void destroySurface();
private:
/** \todo Should this be non-static so we can use additional displays? */
static EGLDisplay ms_eglDisplay;
QSurfaceFormat m_windowFormat;
QOpenGLContext *m_glContext;
EGLConfig m_eglConfig;
EGLContext m_eglContext;
EGLSurface m_eglSurface;
QSize m_surfaceSize;
static EGLint *contextAttrs();
};
QT_END_NAMESPACE
#endif // QBBGLCONTEXT_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,132 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBBINPUTCONTEXT_H
#define QBBINPUTCONTEXT_H
#include <QtGui/QPlatformInputContext>
#include <QtCore/QLocale>
#include <QtCore/QMetaType>
#include <QtGui/QPlatformIntegration>
#include "imf/imf_client.h"
#include "imf/input_control.h"
QT_BEGIN_NAMESPACE
class QBBInputContext : public QPlatformInputContext
{
Q_OBJECT
public:
QBBInputContext();
~QBBInputContext();
virtual bool isValid() const;
virtual bool filterEvent(const QEvent *event);
virtual void reset();
virtual void update(Qt::InputMethodQueries);
bool handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap);
virtual void showInputPanel();
virtual void hideInputPanel();
virtual bool isInputPanelVisible() const;
virtual QLocale locale() const;
protected:
// Filters only for IMF events.
bool eventFilter(QObject *obj, QEvent *event);
private Q_SLOTS:
void keyboardVisibilityChanged(bool visible);
void keyboardLocaleChanged(const QLocale &locale);
void inputItemChanged();
private:
// IMF Event dispatchers
bool dispatchFocusEvent(FocusEventId id, int hints = Qt::ImhNone);
bool dispatchRequestSoftwareInputPanel();
bool dispatchCloseSoftwareInputPanel();
int32_t processEvent(event_t *event);
void closeSession();
void openSession();
bool hasSession();
void endComposition();
void setComposingText(QString const &composingText);
bool hasSelectedText();
// IMF Event handlers - these events will come in from QCoreApplication.
int32_t onBeginBatchEdit(input_session_t *ic);
int32_t onClearMetaKeyStates(input_session_t *ic, int32_t states);
int32_t onCommitText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position);
int32_t onDeleteSurroundingText(input_session_t *ic, int32_t left_length, int32_t right_length);
int32_t onEndBatchEdit(input_session_t *ic);
int32_t onFinishComposingText(input_session_t *ic);
int32_t onGetCursorCapsMode(input_session_t *ic, int32_t req_modes);
int32_t onGetCursorPosition(input_session_t *ic);
extracted_text_t *onGetExtractedText(input_session_t *ic, extracted_text_request_t *request, int32_t flags);
spannable_string_t *onGetSelectedText(input_session_t *ic, int32_t flags);
spannable_string_t *onGetTextAfterCursor(input_session_t *ic, int32_t n, int32_t flags);
spannable_string_t *onGetTextBeforeCursor(input_session_t *ic, int32_t n, int32_t flags);
int32_t onPerformEditorAction(input_session_t *ic, int32_t editor_action);
int32_t onReportFullscreenMode(input_session_t *ic, int32_t enabled);
int32_t onSendEvent(input_session_t *ic, event_t *event);
int32_t onSendAsyncEvent(input_session_t *ic, event_t *event);
int32_t onSetComposingRegion(input_session_t *ic, int32_t start, int32_t end);
int32_t onSetComposingText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position);
int32_t onSetSelection(input_session_t *ic, int32_t start, int32_t end);
int32_t onForceUpdate();
int m_lastCaretPos;
bool m_isComposing;
QString m_composingText;
bool m_inputPanelVisible;
QLocale m_inputPanelLocale;
};
Q_DECLARE_METATYPE(extracted_text_t*)
QT_END_NAMESPACE
#endif // QBBINPUTCONTEXT_H

View File

@ -0,0 +1,187 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qbbinputcontext_noimf.h"
#include "qbbvirtualkeyboard.h"
#include <QtCore/QDebug>
#include <QtGui/QGuiApplication>
#include <QtWidgets/QAbstractSpinBox>
QBBInputContext::QBBInputContext() :
QPlatformInputContext(),
m_inputPanelVisible(false),
m_inputPanelLocale(QLocale::c())
{
QBBVirtualKeyboard &keyboard = QBBVirtualKeyboard::instance();
connect(&keyboard, SIGNAL(visibilityChanged(bool)), this, SLOT(keyboardVisibilityChanged(bool)));
connect(&keyboard, SIGNAL(localeChanged(QLocale)), this, SLOT(keyboardLocaleChanged(QLocale)));
keyboardVisibilityChanged(keyboard.isVisible());
keyboardLocaleChanged(keyboard.locale());
QInputMethod *inputMethod = qApp->inputMethod();
connect(inputMethod, SIGNAL(inputItemChanged()), this, SLOT(inputItemChanged()));
}
QBBInputContext::~QBBInputContext()
{
}
bool QBBInputContext::isValid() const
{
return true;
}
bool QBBInputContext::hasPhysicalKeyboard()
{
// TODO: This should query the system to check if a USB keyboard is connected.
return false;
}
void QBBInputContext::reset()
{
}
bool QBBInputContext::filterEvent( const QEvent *event )
{
if (hasPhysicalKeyboard())
return false;
if (event->type() == QEvent::CloseSoftwareInputPanel) {
QBBVirtualKeyboard::instance().hideKeyboard();
#if defined(QBBINPUTCONTEXT_DEBUG)
qDebug() << "QBB: hiding virtual keyboard";
#endif
return false;
}
if (event->type() == QEvent::RequestSoftwareInputPanel) {
QBBVirtualKeyboard::instance().showKeyboard();
#if defined(QBBINPUTCONTEXT_DEBUG)
qDebug() << "QBB: requesting virtual keyboard";
#endif
return false;
}
return false;
}
bool QBBInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap)
{
Q_UNUSED(flags);
Q_UNUSED(sym);
Q_UNUSED(mod);
Q_UNUSED(scan);
Q_UNUSED(cap);
return false;
}
void QBBInputContext::showInputPanel()
{
#if defined(QBBINPUTCONTEXT_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
QBBVirtualKeyboard::instance().showKeyboard();
}
void QBBInputContext::hideInputPanel()
{
#if defined(QBBINPUTCONTEXT_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
QBBVirtualKeyboard::instance().hideKeyboard();
}
bool QBBInputContext::isInputPanelVisible() const
{
return m_inputPanelVisible;
}
QLocale QBBInputContext::locale() const
{
return m_inputPanelLocale;
}
void QBBInputContext::keyboardVisibilityChanged(bool visible)
{
#if defined(QBBINPUTCONTEXT_DEBUG)
qDebug() << Q_FUNC_INFO << "visible=" << visible;
#endif
if (m_inputPanelVisible != visible) {
m_inputPanelVisible = visible;
emitInputPanelVisibleChanged();
}
}
void QBBInputContext::keyboardLocaleChanged(const QLocale &locale)
{
#if defined(QBBINPUTCONTEXT_DEBUG)
qDebug() << Q_FUNC_INFO << "locale=" << locale;
#endif
if (m_inputPanelLocale != locale) {
m_inputPanelLocale = locale;
emitLocaleChanged();
}
}
void QBBInputContext::inputItemChanged()
{
QInputMethod *inputMethod = qApp->inputMethod();
QObject *inputItem = inputMethod->inputItem();
#if defined(QBBINPUTCONTEXT_DEBUG)
qDebug() << Q_FUNC_INFO << "input item=" << inputItem;
#endif
if (!inputItem) {
if (m_inputPanelVisible)
hideInputPanel();
} else {
if (qobject_cast<QAbstractSpinBox*>(inputItem)) {
QBBVirtualKeyboard::instance().setKeyboardMode(QBBVirtualKeyboard::NumPunc);
} else {
QBBVirtualKeyboard::instance().setKeyboardMode(QBBVirtualKeyboard::Default);
}
if (!m_inputPanelVisible)
showInputPanel();
}
}

View File

@ -0,0 +1,84 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBBINPUTCONTEXT_H
#define QBBINPUTCONTEXT_H
#include <QtCore/QLocale>
#include <QtGui/QPlatformInputContext>
#include <QtGui/QPlatformIntegration>
QT_BEGIN_NAMESPACE
class QBBInputContext : public QPlatformInputContext
{
Q_OBJECT
public:
explicit QBBInputContext();
~QBBInputContext();
virtual bool isValid() const;
void reset();
virtual bool filterEvent( const QEvent *event );
bool handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap);
virtual void showInputPanel();
virtual void hideInputPanel();
virtual bool isInputPanelVisible() const;
virtual QLocale locale() const;
private Q_SLOTS:
void keyboardVisibilityChanged(bool visible);
void keyboardLocaleChanged(const QLocale &locale);
void inputItemChanged();
private:
bool hasPhysicalKeyboard();
bool m_inputPanelVisible;
QLocale m_inputPanelLocale;
};
QT_END_NAMESPACE
#endif // QBBINPUTCONTEXT_H

View File

@ -0,0 +1,293 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qbbintegration.h"
#include "qbbeventthread.h"
#include "qbbglbackingstore.h"
#include "qbbglcontext.h"
#include "qbbnavigatorthread.h"
#include "qbbrasterbackingstore.h"
#include "qbbscreen.h"
#include "qbbwindow.h"
#include "qbbvirtualkeyboard.h"
#include "qbbclipboard.h"
#include "qbbglcontext.h"
#if defined(QBB_IMF)
#include "qbbinputcontext_imf.h"
#else
#include "qbbinputcontext_noimf.h"
#endif
#include "private/qgenericunixfontdatabase_p.h"
#include "private/qgenericunixeventdispatcher_p.h"
#include <QtGui/QPlatformWindow>
#include <QtGui/QWindowSystemInterface>
#include <QtGui/QOpenGLContext>
#include <QtCore/QDebug>
#include <QtCore/QHash>
#include <errno.h>
QT_BEGIN_NAMESPACE
QBBWindowMapper QBBIntegration::ms_windowMapper;
QMutex QBBIntegration::ms_windowMapperMutex;
QBBIntegration::QBBIntegration()
: QPlatformIntegration()
, m_eventThread(0)
, m_navigatorThread(0)
, m_inputContext(0)
, m_fontDatabase(new QGenericUnixFontDatabase())
, m_paintUsingOpenGL(false)
, m_eventDispatcher(createUnixEventDispatcher())
#ifndef QT_NO_CLIPBOARD
, m_clipboard(0)
#endif
{
#if defined(QBBINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// Open connection to QNX composition manager
errno = 0;
int result = screen_create_context(&m_screenContext, SCREEN_APPLICATION_CONTEXT);
if (result != 0) {
qFatal("QBB: failed to connect to composition manager, errno=%d", errno);
}
// Create displays for all possible screens (which may not be attached)
QBBScreen::createDisplays(m_screenContext);
Q_FOREACH (QPlatformScreen *screen, QBBScreen::screens()) {
screenAdded(screen);
}
// Initialize global OpenGL resources
QBBGLContext::initialize();
// Create/start event thread
m_eventThread = new QBBEventThread(m_screenContext, *QBBScreen::primaryDisplay());
m_eventThread->start();
// Create/start navigator thread
m_navigatorThread = new QBBNavigatorThread(*QBBScreen::primaryDisplay());
m_navigatorThread->start();
// Create/start the keyboard class.
QBBVirtualKeyboard::instance();
// Set up the input context
m_inputContext = new QBBInputContext;
}
QBBIntegration::~QBBIntegration()
{
#if defined(QBBINTEGRATION_DEBUG)
qDebug() << "QBB: platform plugin shutdown begin";
#endif
// Destroy the keyboard class.
QBBVirtualKeyboard::destroy();
#ifndef QT_NO_CLIPBOARD
// Delete the clipboard
delete m_clipboard;
#endif
// Stop/destroy event thread
delete m_eventThread;
// Stop/destroy navigator thread
delete m_navigatorThread;
// Destroy all displays
QBBScreen::destroyDisplays();
// Close connection to QNX composition manager
screen_destroy_context(m_screenContext);
// Cleanup global OpenGL resources
QBBGLContext::shutdown();
#if defined(QBBINTEGRATION_DEBUG)
qDebug() << "QBB: platform plugin shutdown end";
#endif
}
bool QBBIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
#if defined(QBBINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
switch (cap) {
case ThreadedPixmaps: return true;
#if defined(QT_OPENGL_ES)
case OpenGL:
return true;
#endif
default: return QPlatformIntegration::hasCapability(cap);
}
}
QPlatformWindow *QBBIntegration::createPlatformWindow(QWindow *window) const
{
#if defined(QBBINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// New windows are created on the primary display.
return new QBBWindow(window, m_screenContext);
}
QPlatformBackingStore *QBBIntegration::createPlatformBackingStore(QWindow *window) const
{
#if defined(QBBINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
if (paintUsingOpenGL())
return new QBBGLBackingStore(window);
else
return new QBBRasterBackingStore(window);
}
QPlatformOpenGLContext *QBBIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
#if defined(QBBINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
return new QBBGLContext(context);
}
QPlatformInputContext *QBBIntegration::inputContext() const
{
#if defined(QBBINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
return m_inputContext;
}
void QBBIntegration::moveToScreen(QWindow *window, int screen)
{
#if defined(QBBINTEGRATION_DEBUG)
qDebug() << "QBBIntegration::moveToScreen - w=" << window << ", s=" << screen;
#endif
// get platform window used by widget
QBBWindow *platformWindow = static_cast<QBBWindow *>(window->handle());
// lookup platform screen by index
QBBScreen *platformScreen = static_cast<QBBScreen*>(QBBScreen::screens().at(screen));
// move the platform window to the platform screen
platformWindow->setScreen(platformScreen);
}
QList<QPlatformScreen *> QBBIntegration::screens() const
{
#if defined(QBBINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
return QBBScreen::screens();
}
QAbstractEventDispatcher *QBBIntegration::guiThreadEventDispatcher() const
{
#if defined(QBBINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
return m_eventDispatcher;
}
#ifndef QT_NO_CLIPBOARD
QPlatformClipboard *QBBIntegration::clipboard() const
{
#if defined(QBBINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
if (!m_clipboard) {
m_clipboard = new QBBClipboard;
}
return m_clipboard;
}
#endif
QVariant QBBIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
{
#if defined(QBBINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
if (hint == ShowIsFullScreen)
return true;
return QPlatformIntegration::styleHint(hint);
}
QWindow *QBBIntegration::window(screen_window_t qnxWindow)
{
#if defined(QBBINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
QMutexLocker locker(&ms_windowMapperMutex);
Q_UNUSED(locker);
return ms_windowMapper.value(qnxWindow, 0);
}
void QBBIntegration::addWindow(screen_window_t qnxWindow, QWindow *window)
{
#if defined(QBBINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
QMutexLocker locker(&ms_windowMapperMutex);
Q_UNUSED(locker);
ms_windowMapper.insert(qnxWindow, window);
}
void QBBIntegration::removeWindow(screen_window_t qnxWindow)
{
#if defined(QBBINTEGRATION_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
QMutexLocker locker(&ms_windowMapperMutex);
Q_UNUSED(locker);
ms_windowMapper.remove(qnxWindow);
}
QT_END_NAMESPACE

View File

@ -0,0 +1,119 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBBINTEGRATION_H
#define QBBINTEGRATION_H
#include <QtGui/qplatformintegration_qpa.h>
#include <QtCore/qmutex.h>
#include <screen/screen.h>
QT_BEGIN_NAMESPACE
class QBBEventThread;
class QBBInputContext;
class QBBNavigatorThread;
class QBBWindow;
#ifndef QT_NO_CLIPBOARD
class QBBClipboard;
#endif
template<class K, class V> class QHash;
typedef QHash<screen_window_t, QWindow *> QBBWindowMapper;
class QBBIntegration : public QPlatformIntegration
{
public:
QBBIntegration();
virtual ~QBBIntegration();
virtual bool hasCapability(QPlatformIntegration::Capability cap) const;
virtual QPlatformWindow *createPlatformWindow(QWindow *window) const;
virtual QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
virtual QPlatformInputContext *inputContext() const;
virtual QList<QPlatformScreen *> screens() const;
virtual void moveToScreen(QWindow *window, int screen);
virtual QAbstractEventDispatcher *guiThreadEventDispatcher() const;
virtual QPlatformFontDatabase *fontDatabase() const { return m_fontDatabase; }
#ifndef QT_NO_CLIPBOARD
virtual QPlatformClipboard *clipboard() const;
#endif
virtual QVariant styleHint(StyleHint hint) const;
bool paintUsingOpenGL() const { return m_paintUsingOpenGL; }
static QWindow *window(screen_window_t qnxWindow);
private:
static void addWindow(screen_window_t qnxWindow, QWindow *window);
static void removeWindow(screen_window_t qnxWindow);
screen_context_t m_screenContext;
QBBEventThread *m_eventThread;
QBBNavigatorThread *m_navigatorThread;
QBBInputContext *m_inputContext;
QPlatformFontDatabase *m_fontDatabase;
bool m_paintUsingOpenGL;
QAbstractEventDispatcher *m_eventDispatcher;
#ifndef QT_NO_CLIPBOARD
mutable QBBClipboard* m_clipboard;
#endif
static QBBWindowMapper ms_windowMapper;
static QMutex ms_windowMapperMutex;
friend class QBBWindow;
};
QT_END_NAMESPACE
#endif // QBBINTEGRATION_H

View File

@ -0,0 +1,269 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBBKEYTRANSLATOR_H
#define QBBKEYTRANSLATOR_H
#include <sys/keycodes.h>
#if defined(QBBEVENTTHREAD_DEBUG)
#include <QtCore/QDebug>
#endif
QT_BEGIN_NAMESPACE
Qt::Key keyTranslator( int key )
{
switch (key) {
case KEYCODE_PAUSE:
return Qt::Key_Pause;
case KEYCODE_SCROLL_LOCK:
return Qt::Key_ScrollLock;
case KEYCODE_PRINT:
return Qt::Key_Print;
case KEYCODE_SYSREQ:
return Qt::Key_SysReq;
// case KEYCODE_BREAK:
case KEYCODE_ESCAPE:
return Qt::Key_Escape;
case KEYCODE_BACKSPACE:
return Qt::Key_Backspace;
case KEYCODE_TAB:
return Qt::Key_Tab;
case KEYCODE_BACK_TAB:
return Qt::Key_Backtab;
case KEYCODE_RETURN:
return Qt::Key_Return;
case KEYCODE_CAPS_LOCK:
return Qt::Key_CapsLock;
case KEYCODE_LEFT_SHIFT:
case KEYCODE_RIGHT_SHIFT:
return Qt::Key_Shift;
case KEYCODE_LEFT_CTRL:
case KEYCODE_RIGHT_CTRL:
return Qt::Key_Control;
case KEYCODE_LEFT_ALT:
case KEYCODE_RIGHT_ALT:
return Qt::Key_Alt;
case KEYCODE_MENU:
return Qt::Key_Menu;
case KEYCODE_LEFT_HYPER:
return Qt::Key_Hyper_L;
case KEYCODE_RIGHT_HYPER:
return Qt::Key_Hyper_R;
case KEYCODE_INSERT:
return Qt::Key_Insert;
case KEYCODE_HOME:
return Qt::Key_Home;
case KEYCODE_PG_UP:
return Qt::Key_PageUp;
case KEYCODE_DELETE:
return Qt::Key_Delete;
case KEYCODE_END:
return Qt::Key_End;
case KEYCODE_PG_DOWN:
return Qt::Key_PageDown;
case KEYCODE_LEFT:
return Qt::Key_Left;
case KEYCODE_RIGHT:
return Qt::Key_Right;
case KEYCODE_UP:
return Qt::Key_Up;
case KEYCODE_DOWN:
return Qt::Key_Down;
case KEYCODE_NUM_LOCK:
return Qt::Key_NumLock;
case KEYCODE_KP_PLUS:
return Qt::Key_Plus;
case KEYCODE_KP_MINUS:
return Qt::Key_Minus;
case KEYCODE_KP_MULTIPLY:
return Qt::Key_Asterisk;
case KEYCODE_KP_DIVIDE:
return Qt::Key_Slash;
case KEYCODE_KP_ENTER:
return Qt::Key_Enter;
case KEYCODE_KP_HOME:
return Qt::Key_Home;
case KEYCODE_KP_UP:
return Qt::Key_Up;
case KEYCODE_KP_PG_UP:
return Qt::Key_PageUp;
case KEYCODE_KP_LEFT:
return Qt::Key_Left;
// Is this right?
case KEYCODE_KP_FIVE:
return Qt::Key_5;
case KEYCODE_KP_RIGHT:
return Qt::Key_Right;
case KEYCODE_KP_END:
return Qt::Key_End;
case KEYCODE_KP_DOWN:
return Qt::Key_Down;
case KEYCODE_KP_PG_DOWN:
return Qt::Key_PageDown;
case KEYCODE_KP_INSERT:
return Qt::Key_Insert;
case KEYCODE_KP_DELETE:
return Qt::Key_Delete;
case KEYCODE_F1:
return Qt::Key_F1;
case KEYCODE_F2:
return Qt::Key_F2;
case KEYCODE_F3:
return Qt::Key_F3;
case KEYCODE_F4:
return Qt::Key_F4;
case KEYCODE_F5:
return Qt::Key_F5;
case KEYCODE_F6:
return Qt::Key_F6;
case KEYCODE_F7:
return Qt::Key_F7;
case KEYCODE_F8:
return Qt::Key_F8;
case KEYCODE_F9:
return Qt::Key_F9;
case KEYCODE_F10:
return Qt::Key_F10;
case KEYCODE_F11:
return Qt::Key_F11;
case KEYCODE_F12:
return Qt::Key_F12;
// See keycodes.h for more, but these are all the basics. And printables are already included.
default:
#if defined(QBBEVENTTHREAD_DEBUG)
qDebug() << "QBB: unknown key for translation:" << key;
#endif
break;
}
return Qt::Key_Escape;
}
bool isKeypadKey( int key )
{
switch (key)
{
case KEYCODE_KP_PLUS:
case KEYCODE_KP_MINUS:
case KEYCODE_KP_MULTIPLY:
case KEYCODE_KP_DIVIDE:
case KEYCODE_KP_ENTER:
case KEYCODE_KP_HOME:
case KEYCODE_KP_UP:
case KEYCODE_KP_PG_UP:
case KEYCODE_KP_LEFT:
case KEYCODE_KP_FIVE:
case KEYCODE_KP_RIGHT:
case KEYCODE_KP_END:
case KEYCODE_KP_DOWN:
case KEYCODE_KP_PG_DOWN:
case KEYCODE_KP_INSERT:
case KEYCODE_KP_DELETE:
return true;
default:
break;
}
return false;
}
QT_END_NAMESPACE
#endif // QBBKEYTRANSLATOR_H

View File

@ -0,0 +1,279 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qbbnavigatorthread.h"
#include "qbbscreen.h"
#include <QtGui/QGuiApplication>
#include <QtGui/QWindow>
#include <QtGui/QWindowSystemInterface>
#include <QtCore/QByteArray>
#include <QtCore/QDebug>
#include <QtCore/QList>
#include <QtCore/QSocketNotifier>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
static const char *navigatorControlPath = "/pps/services/navigator/control";
static const int ppsBufferSize = 4096;
QBBNavigatorThread::QBBNavigatorThread(QBBScreen& primaryScreen)
: m_primaryScreen(primaryScreen),
m_fd(-1),
m_readNotifier(0)
{
}
QBBNavigatorThread::~QBBNavigatorThread()
{
// block until thread terminates
shutdown();
delete m_readNotifier;
}
void QBBNavigatorThread::run()
{
#if defined(QBBNAVIGATORTHREAD_DEBUG)
qDebug() << "QBB: navigator thread started";
#endif
// open connection to navigator
errno = 0;
m_fd = open(navigatorControlPath, O_RDWR);
if (m_fd == -1) {
qWarning("QBB: failed to open navigator pps, errno=%d", errno);
return;
}
m_readNotifier = new QSocketNotifier(m_fd, QSocketNotifier::Read);
// using direct connection to get the slot called in this thread's context
connect(m_readNotifier, SIGNAL(activated(int)), this, SLOT(readData()), Qt::DirectConnection);
exec();
// close connection to navigator
close(m_fd);
#if defined(QBBNAVIGATORTHREAD_DEBUG)
qDebug() << "QBB: navigator thread stopped";
#endif
}
void QBBNavigatorThread::shutdown()
{
#if defined(QBBNAVIGATORTHREAD_DEBUG)
qDebug() << "QBB: navigator thread shutdown begin";
#endif
// signal thread to terminate
quit();
// block until thread terminates
wait();
#if defined(QBBNAVIGATORTHREAD_DEBUG)
qDebug() << "QBB: navigator thread shutdown end";
#endif
}
void QBBNavigatorThread::parsePPS(const QByteArray &ppsData, QByteArray &msg, QByteArray &dat, QByteArray &id)
{
#if defined(QBBNAVIGATORTHREAD_DEBUG)
qDebug() << "PPS: data=" << ppsData;
#endif
// tokenize pps data into lines
QList<QByteArray> lines = ppsData.split('\n');
// validate pps object
if (lines.size() == 0 || lines.at(0) != "@control") {
qFatal("QBB: unrecognized pps object, data=%s", ppsData.constData());
}
// parse pps object attributes and extract values
for (int i = 1; i < lines.size(); i++) {
// tokenize current attribute
const QByteArray &attr = lines.at(i);
#if defined(QBBNAVIGATORTHREAD_DEBUG)
qDebug() << "PPS: attr=" << attr;
#endif
int firstColon = attr.indexOf(':');
if (firstColon == -1) {
// abort - malformed attribute
continue;
}
int secondColon = attr.indexOf(':', firstColon + 1);
if (secondColon == -1) {
// abort - malformed attribute
continue;
}
QByteArray key = attr.left(firstColon);
QByteArray value = attr.mid(secondColon + 1);
#if defined(QBBNAVIGATORTHREAD_DEBUG)
qDebug() << "PPS: key=" << key;
qDebug() << "PPS: val=" << value;
#endif
// save attribute value
if (key == "msg") {
msg = value;
} else if (key == "dat") {
dat = value;
} else if (key == "id") {
id = value;
} else {
qFatal("QBB: unrecognized pps attribute, attr=%s", key.constData());
}
}
}
void QBBNavigatorThread::replyPPS(const QByteArray &res, const QByteArray &id, const QByteArray &dat)
{
// construct pps message
QByteArray ppsData = "res::";
ppsData += res;
ppsData += "\nid::";
ppsData += id;
if (!dat.isEmpty()) {
ppsData += "\ndat::";
ppsData += dat;
}
ppsData += "\n";
#if defined(QBBNAVIGATORTHREAD_DEBUG)
qDebug() << "PPS reply=" << ppsData;
#endif
// send pps message to navigator
errno = 0;
int bytes = write(m_fd, ppsData.constData(), ppsData.size());
if (bytes == -1) {
qFatal("QBB: failed to write navigator pps, errno=%d", errno);
}
}
void QBBNavigatorThread::handleMessage(const QByteArray &msg, const QByteArray &dat, const QByteArray &id)
{
#if defined(QBBNAVIGATORTHREAD_DEBUG)
qDebug() << "PPS: msg=" << msg << ", dat=" << dat << ", id=" << id;
#endif
// check message type
if (msg == "orientationCheck") {
// reply to navigator that (any) orientation is acceptable
#if defined(QBBNAVIGATORTHREAD_DEBUG)
qDebug() << "PPS: orientation check, o=" << dat;
#endif
replyPPS(msg, id, "true");
} else if (msg == "orientation") {
// update screen geometry and reply to navigator that we're ready
#if defined(QBBNAVIGATORTHREAD_DEBUG)
qDebug() << "PPS: orientation, o=" << dat;
#endif
m_primaryScreen.setRotation( dat.toInt() );
QWindowSystemInterface::handleScreenGeometryChange(0, m_primaryScreen.geometry());
replyPPS(msg, id, "");
} else if (msg == "SWIPE_DOWN") {
// simulate menu key press
#if defined(QBBNAVIGATORTHREAD_DEBUG)
qDebug() << "PPS: menu";
#endif
QWindow *w = QGuiApplication::focusWindow();
QWindowSystemInterface::handleKeyEvent(w, QEvent::KeyPress, Qt::Key_Menu, Qt::NoModifier);
QWindowSystemInterface::handleKeyEvent(w, QEvent::KeyRelease, Qt::Key_Menu, Qt::NoModifier);
} else if (msg == "exit") {
// shutdown everything
#if defined(QBBNAVIGATORTHREAD_DEBUG)
qDebug() << "PPS: exit";
#endif
QCoreApplication::quit();
}
}
void QBBNavigatorThread::readData()
{
#if defined(QBBNAVIGATORTHREAD_DEBUG)
qDebug() << "QBB: reading navigator data";
#endif
// allocate buffer for pps data
char buffer[ppsBufferSize];
// attempt to read pps data
errno = 0;
int bytes = read(m_fd, buffer, ppsBufferSize - 1);
if (bytes == -1) {
qFatal("QBB: failed to read navigator pps, errno=%d", errno);
}
// check if pps data was received
if (bytes > 0) {
// ensure data is null terminated
buffer[bytes] = '\0';
// process received message
QByteArray ppsData(buffer);
QByteArray msg;
QByteArray dat;
QByteArray id;
parsePPS(ppsData, msg, dat, id);
handleMessage(msg, dat, id);
}
}

View File

@ -0,0 +1,78 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBBNAVIGATORTHREAD_H
#define QBBNAVIGATORTHREAD_H
#include <QThread>
QT_BEGIN_NAMESPACE
class QBBScreen;
class QSocketNotifier;
class QBBNavigatorThread : public QThread
{
Q_OBJECT
public:
QBBNavigatorThread(QBBScreen &primaryScreen);
virtual ~QBBNavigatorThread();
protected:
virtual void run();
private Q_SLOTS:
void readData();
private:
void shutdown();
void parsePPS(const QByteArray &ppsData, QByteArray &msg, QByteArray &dat, QByteArray &id);
void replyPPS(const QByteArray &res, const QByteArray &id, const QByteArray &dat);
void handleMessage(const QByteArray &msg, const QByteArray &dat, const QByteArray &id);
QBBScreen &m_primaryScreen;
int m_fd;
QSocketNotifier *m_readNotifier;
};
QT_END_NAMESPACE
#endif // QBBNAVIGATORTHREAD_H

View File

@ -0,0 +1,166 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qbbrasterbackingstore.h"
#include "qbbwindow.h"
#include <QtCore/QDebug>
#include <errno.h>
QT_BEGIN_NAMESPACE
QBBRasterBackingStore::QBBRasterBackingStore(QWindow *window)
: QPlatformBackingStore(window)
{
#if defined(QBBRASTERBACKINGSTORE_DEBUG)
qDebug() << "QBBRasterBackingStore::QBBRasterBackingStore - w=" << window;
#endif
// save platform window associated with widget
m_platformWindow = static_cast<QBBWindow*>(window->handle());
}
QBBRasterBackingStore::~QBBRasterBackingStore()
{
#if defined(QBBRasterBackingStore_DEBUG)
qDebug() << "QBBRasterBackingStore::~QBBRasterBackingStore - w=" << window();
#endif
}
QPaintDevice *QBBRasterBackingStore::paintDevice()
{
return m_platformWindow->renderBuffer().image();
}
void QBBRasterBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
{
Q_UNUSED(window);
Q_UNUSED(offset);
#if defined(QBBRASTERBACKINGSTORE_DEBUG)
qDebug() << "QBBRasterBackingStore::flush - w=" << this->window();
#endif
// visit all pending scroll operations
for (int i = m_scrollOpList.size() - 1; i >= 0; i--) {
// do the scroll operation
ScrollOp &op = m_scrollOpList[i];
QRegion srcArea = op.totalArea.intersected( op.totalArea.translated(-op.dx, -op.dy) );
m_platformWindow->scroll(srcArea, op.dx, op.dy);
}
// clear all pending scroll operations
m_scrollOpList.clear();
// update the display with newly rendered content
m_platformWindow->post(region);
}
void QBBRasterBackingStore::resize(const QSize &size, const QRegion &staticContents)
{
Q_UNUSED(size);
Q_UNUSED(staticContents);
#if defined(QBBRASTERBACKINGSTORE_DEBUG)
qDebug() << "QBBRasterBackingStore::resize - w=" << window() << ", s=" << size;
#endif
// NOTE: defer resizing window buffers until next paint as
// resize() can be called multiple times before a paint occurs
}
bool QBBRasterBackingStore::scroll(const QRegion &area, int dx, int dy)
{
#if defined(QBBRASTERBACKINGSTORE_DEBUG)
qDebug() << "QBBRasterBackingStore::scroll - w=" << window();
#endif
// calculate entire region affected by scroll operation (src + dst)
QRegion totalArea = area.translated(dx, dy);
totalArea += area;
// visit all pending scroll operations
for (int i = m_scrollOpList.size() - 1; i >= 0; i--) {
ScrollOp &op = m_scrollOpList[i];
if (op.totalArea == totalArea) {
// same area is being scrolled again - update delta
op.dx += dx;
op.dy += dy;
return true;
} else if (op.totalArea.intersects(totalArea)) {
// current scroll overlaps previous scroll but is
// not equal in area - just paint everything
qWarning("QBB: pending scroll operations overlap but not equal");
return false;
}
}
// create new scroll operation
m_scrollOpList.append( ScrollOp(totalArea, dx, dy) );
return true;
}
void QBBRasterBackingStore::beginPaint(const QRegion &region)
{
Q_UNUSED(region);
#if defined(QBBRASTERBACKINGSTORE_DEBUG)
qDebug() << "QBBRasterBackingStore::beginPaint - w=" << window();
#endif
// resize window buffers if surface resized
QSize s = window()->size();
if (s != m_platformWindow->bufferSize()) {
m_platformWindow->setBufferSize(s);
}
}
void QBBRasterBackingStore::endPaint(const QRegion &region)
{
Q_UNUSED(region);
#if defined(QBBRasterBackingStore_DEBUG)
qDebug() << "QBBRasterBackingStore::endPaint - w=" << window();
#endif
}
QT_END_NAMESPACE

View File

@ -0,0 +1,81 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBBRASTERWINDOWSURFACE_H
#define QBBRASTERWINDOWSURFACE_H
#include <QtGui/qplatformbackingstore_qpa.h>
#include <screen/screen.h>
QT_BEGIN_NAMESPACE
class QBBWindow;
class QBBRasterBackingStore : public QPlatformBackingStore
{
public:
QBBRasterBackingStore(QWindow *window);
virtual ~QBBRasterBackingStore();
virtual QPaintDevice *paintDevice();
virtual void flush(QWindow *window, const QRegion &region, const QPoint &offset);
virtual void resize(const QSize &size, const QRegion &staticContents);
virtual bool scroll(const QRegion &area, int dx, int dy);
virtual void beginPaint(const QRegion &region);
virtual void endPaint(const QRegion &region);
private:
class ScrollOp {
public:
ScrollOp(const QRegion &a, int x, int y) : totalArea(a), dx(x), dy(y) {}
QRegion totalArea;
int dx;
int dy;
};
QBBWindow *m_platformWindow;
QList<ScrollOp> m_scrollOpList;
};
QT_END_NAMESPACE
#endif // QBBRASTERWINDOWSURFACE_H

View File

@ -0,0 +1,257 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qbbrootwindow.h"
#include "qbbscreen.h"
#include <QtCore/QUuid>
#if defined(QBBROOTWINDOW_DEBUG)
#include <QtCore/QDebug>
#endif
#include <errno.h>
#include <unistd.h>
static const int MAGIC_ZORDER_FOR_NO_NAV = 10;
QBBRootWindow::QBBRootWindow(QBBScreen *screen)
: m_screen(screen),
m_window(0),
m_windowGroupName()
{
#if defined(QBBROOTWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// Create one top-level QNX window to act as a container for child windows
// since navigator only supports one application window
errno = 0;
int result = screen_create_window(&m_window, m_screen->nativeContext());
int val[2];
if (result != 0) {
qFatal("QBBRootWindow: failed to create window, errno=%d", errno);
}
// Move window to proper display
errno = 0;
screen_display_t display = m_screen->nativeDisplay();
result = screen_set_window_property_pv(m_window, SCREEN_PROPERTY_DISPLAY, (void **)&display);
if (result != 0) {
qFatal("QBBRootWindow: failed to set window display, errno=%d", errno);
}
// Make sure window is above navigator but below keyboard if running as root
// since navigator won't automatically set our z-order in this case
if (getuid() == 0) {
errno = 0;
val[0] = MAGIC_ZORDER_FOR_NO_NAV;
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ZORDER, val);
if (result != 0) {
qFatal("QBBRootWindow: failed to set window z-order, errno=%d", errno);
}
}
// Window won't be visible unless it has some buffers so make one dummy buffer that is 1x1
errno = 0;
val[0] = SCREEN_USAGE_NATIVE;
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_USAGE, val);
if (result != 0) {
qFatal("QBBRootWindow: failed to set window buffer usage, errno=%d", errno);
}
errno = 0;
val[0] = m_screen->nativeFormat();
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, val);
if (result != 0) {
qFatal("QBBRootWindow: failed to set window pixel format, errno=%d", errno);
}
errno = 0;
val[0] = 1;
val[1] = 1;
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BUFFER_SIZE, val);
if (result != 0) {
qFatal("QBBRootWindow: failed to set window buffer size, errno=%d", errno);
}
errno = 0;
result = screen_create_window_buffers(m_window, 1);
if (result != 0) {
qFatal("QBB: failed to create window buffer, errno=%d", errno);
}
// Window is always the size of the display
errno = 0;
QRect geometry = m_screen->geometry();
val[0] = geometry.width();
val[1] = geometry.height();
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val);
if (result != 0) {
qFatal("QBBRootWindow: failed to set window size, errno=%d", errno);
}
// Fill the window with solid black
errno = 0;
val[0] = 0;
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_COLOR, val);
if (result != 0) {
qFatal("QBBRootWindow: failed to set window colour, errno=%d", errno);
}
// Make the window opaque
errno = 0;
val[0] = SCREEN_TRANSPARENCY_NONE;
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_TRANSPARENCY, val);
if (result != 0) {
qFatal("QBBRootWindow: failed to set window transparency, errno=%d", errno);
}
// Set the swap interval to 1
errno = 0;
val[0] = 1;
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SWAP_INTERVAL, val);
if (result != 0) {
qFatal("QBBRootWindow: failed to set window swap interval, errno=%d", errno);
}
// Set viewport size equal to window size but move outside buffer so the fill colour is used exclusively
errno = 0;
val[0] = geometry.width();
val[1] = geometry.height();
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val);
if (result != 0) {
qFatal("QBBRootWindow: failed to set window source size, errno=%d", errno);
}
errno = 0;
val[0] = 1;
val[1] = 0;
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_POSITION, val);
if (result != 0) {
qFatal("QBBRootWindow: failed to set window source position, errno=%d", errno);
}
createWindowGroup();
post();
}
QBBRootWindow::~QBBRootWindow()
{
// Cleanup top-level QNX window
screen_destroy_window(m_window);
}
void QBBRootWindow::post() const
{
#if defined(QBBROOTWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
errno = 0;
screen_buffer_t buffer;
int result = screen_get_window_property_pv(m_window, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)&buffer);
if (result != 0) {
qFatal("QBBRootWindow: failed to query window buffer, errno=%d", errno);
}
errno = 0;
int dirtyRect[] = {0, 0, 1, 1};
result = screen_post_window(m_window, buffer, 1, dirtyRect, 0);
if (result != 0) {
qFatal("QBB: failed to post window buffer, errno=%d", errno);
}
}
void QBBRootWindow::flush() const
{
#if defined(QBBROOTWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// Force immediate display update
errno = 0;
int result = screen_flush_context(m_screen->nativeContext(), 0);
if (result != 0) {
qFatal("QBBRootWindow: failed to flush context, errno=%d", errno);
}
}
void QBBRootWindow::setRotation(int rotation)
{
#if defined(QBBROOTWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "angle =" << rotation;
#endif
errno = 0;
int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ROTATION, &rotation);
if (result != 0) {
qFatal("QBBRootWindow: failed to set window rotation, errno=%d", errno);
}
}
void QBBRootWindow::resize(const QSize &size)
{
errno = 0;
int val[] = {size.width(), size.height()};
int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val);
if (result != 0) {
qFatal("QBBRootWindow: failed to set window size, errno=%d", errno);
}
errno = 0;
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val);
if (result != 0) {
qFatal("QBBRootWindow: failed to set window source size, errno=%d", errno);
}
// NOTE: display will update when child windows relayout and repaint
}
void QBBRootWindow::createWindowGroup()
{
// Generate a random window group name
m_windowGroupName = QUuid::createUuid().toString().toAscii();
// Create window group so child windows can be parented by container window
errno = 0;
int result = screen_create_window_group(m_window, m_windowGroupName.constData());
if (result != 0) {
qFatal("QBBRootWindow: failed to create app window group, errno=%d", errno);
}
}

View File

@ -0,0 +1,81 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBBROOTWINDOW_H
#define QBBROOTWINDOW_H
#include <QtCore/QByteArray>
#include <QtCore/QRect>
#include <screen/screen.h>
QT_BEGIN_NAMESPACE
class QBBScreen;
class QBBRootWindow
{
public:
QBBRootWindow(QBBScreen *screen);
~QBBRootWindow();
screen_window_t nativeHandle() const { return m_window; }
void post() const;
void flush() const;
void setRotation(int rotation);
void resize(const QSize &size);
QByteArray groupName() const { return m_windowGroupName; }
private:
void createWindowGroup();
QBBScreen *m_screen;
screen_window_t m_window;
QByteArray m_windowGroupName;
};
QT_END_NAMESPACE
#endif // QBBROOTWINDOW_H

View File

@ -0,0 +1,315 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qbbscreen.h"
#include "qbbvirtualkeyboard.h"
#include "qbbwindow.h"
#include <QtCore/QDebug>
#include <QtCore/QUuid>
#include <errno.h>
QT_BEGIN_NAMESPACE
QList<QPlatformScreen *> QBBScreen::ms_screens;
QList<QBBWindow*> QBBScreen::ms_childWindows;
QBBScreen::QBBScreen(screen_context_t screenContext, screen_display_t display, bool primaryScreen)
: m_screenContext(screenContext),
m_display(display),
m_rootWindow(),
m_primaryScreen(primaryScreen),
m_posted(false),
m_platformContext(0)
{
#if defined(QBBSCREEN_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// Cache initial orientation of this display
// TODO: use ORIENTATION environment variable?
errno = 0;
int result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_ROTATION, &m_initialRotation);
if (result != 0) {
qFatal("QBBScreen: failed to query display rotation, errno=%d", errno);
}
m_currentRotation = m_initialRotation;
// Cache size of this display in pixels
// TODO: use WIDTH and HEIGHT environment variables?
errno = 0;
int val[2];
result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_SIZE, val);
if (result != 0) {
qFatal("QBBScreen: failed to query display size, errno=%d", errno);
}
m_currentGeometry = m_initialGeometry = QRect(0, 0, val[0], val[1]);
// Cache size of this display in millimeters
errno = 0;
result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_PHYSICAL_SIZE, val);
if (result != 0) {
qFatal("QBBScreen: failed to query display physical size, errno=%d", errno);
}
// Peg the DPI to 96 (for now) so fonts are a reasonable size. We'll want to match
// everything with a QStyle later, and at that point the physical size can be used
// instead.
{
static const int dpi = 96;
int width = m_currentGeometry.width() / dpi * qreal(25.4) ;
int height = m_currentGeometry.height() / dpi * qreal(25.4) ;
m_currentPhysicalSize = m_initialPhysicalSize = QSize(width,height);
}
// We only create the root window if we are the primary display.
if (primaryScreen)
m_rootWindow = QSharedPointer<QBBRootWindow>(new QBBRootWindow(this));
}
QBBScreen::~QBBScreen()
{
#if defined(QBBSCREEN_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
}
/* static */
void QBBScreen::createDisplays(screen_context_t context)
{
#if defined(QBBSCREEN_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// Query number of displays
errno = 0;
int displayCount;
int result = screen_get_context_property_iv(context, SCREEN_PROPERTY_DISPLAY_COUNT, &displayCount);
if (result != 0) {
qFatal("QBBScreen: failed to query display count, errno=%d", errno);
}
// Get all displays
errno = 0;
screen_display_t *displays = (screen_display_t *)alloca(sizeof(screen_display_t) * displayCount);
result = screen_get_context_property_pv(context, SCREEN_PROPERTY_DISPLAYS, (void **)displays);
if (result != 0) {
qFatal("QBBScreen: failed to query displays, errno=%d", errno);
}
for (int i=0; i<displayCount; i++) {
#if defined(QBBSCREEN_DEBUG)
qDebug() << "QBBScreen::Creating screen for display " << i;
#endif
QBBScreen *screen = new QBBScreen(context, displays[i], i==0);
ms_screens.append(screen);
}
}
/* static */
void QBBScreen::destroyDisplays()
{
#if defined(QBBSCREEN_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
qDeleteAll(ms_screens);
ms_screens.clear();
// We're not managing the child windows anymore so we need to clear the list.
ms_childWindows.clear();
}
/* static */
int QBBScreen::defaultDepth()
{
#if defined(QBBSCREEN_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
static int defaultDepth = 0;
if (defaultDepth == 0) {
// check if display depth was specified in environment variable;
// use default value if no valid value found
defaultDepth = qgetenv("QBB_DISPLAY_DEPTH").toInt();
if (defaultDepth != 16 && defaultDepth != 32) {
defaultDepth = 32;
}
}
return defaultDepth;
}
QRect QBBScreen::availableGeometry() const
{
#if defined(QBBSCREEN_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// available geometry = total geometry - keyboard
int keyboardHeight = QBBVirtualKeyboard::instance().height();
return QRect(m_currentGeometry.x(), m_currentGeometry.y(),
m_currentGeometry.width(), m_currentGeometry.height() - keyboardHeight);
}
/*!
Check if the supplied angles are perpendicular to each other.
*/
static bool isOrthogonal(int angle1, int angle2)
{
return ((angle1 - angle2) % 180) != 0;
}
void QBBScreen::setRotation(int rotation)
{
#if defined(QBBSCREEN_DEBUG)
qDebug() << Q_FUNC_INFO << "orientation =" << rotation;
#endif
// Check if rotation changed
if (m_currentRotation != rotation) {
// Update rotation of root window
if (m_rootWindow)
m_rootWindow->setRotation(rotation);
// Swap dimensions if we've rotated 90 or 270 from initial orientation
if (isOrthogonal(m_currentRotation, rotation)) {
m_currentGeometry = QRect(0, 0, m_initialGeometry.height(), m_initialGeometry.width());
m_currentPhysicalSize = QSize(m_initialPhysicalSize.height(), m_initialPhysicalSize.width());
} else {
m_currentGeometry = QRect(0, 0, m_initialGeometry.width(), m_initialGeometry.height());
m_currentPhysicalSize = m_initialPhysicalSize;
}
// Resize root window if we've rotated 90 or 270 from previous orientation
if (isOrthogonal(m_currentRotation, rotation)) {
#if defined(QBBSCREEN_DEBUG)
qDebug() << Q_FUNC_INFO << "resize, size =" << m_currentGeometry.size();
#endif
if (m_rootWindow)
m_rootWindow->resize(m_currentGeometry.size());
} else {
// TODO: Find one global place to flush display updates
// Force immediate display update if no geometry changes required
if (m_rootWindow)
m_rootWindow->flush();
}
// Save new rotation
m_currentRotation = rotation;
}
}
void QBBScreen::addWindow(QBBWindow *window)
{
#if defined(QBBSCREEN_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window;
#endif
if (ms_childWindows.contains(window))
return;
ms_childWindows.push_back(window);
QBBScreen::updateHierarchy();
}
void QBBScreen::removeWindow(QBBWindow *window)
{
#if defined(QBBSCREEN_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window;
#endif
ms_childWindows.removeAll(window);
QBBScreen::updateHierarchy();
}
void QBBScreen::raiseWindow(QBBWindow *window)
{
#if defined(QBBSCREEN_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window;
#endif
removeWindow(window);
ms_childWindows.push_back(window);
QBBScreen::updateHierarchy();
}
void QBBScreen::lowerWindow(QBBWindow *window)
{
#if defined(QBBSCREEN_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window;
#endif
removeWindow(window);
ms_childWindows.push_front(window);
QBBScreen::updateHierarchy();
}
void QBBScreen::updateHierarchy()
{
#if defined(QBBSCREEN_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
QList<QBBWindow*>::iterator it;
int topZorder = 0;
for (it = ms_childWindows.begin(); it != ms_childWindows.end(); it++)
(*it)->updateZorder(topZorder);
// After a hierarchy update, we need to force a flush on all screens.
// Right now, all screens share a context.
screen_flush_context( primaryDisplay()->m_screenContext, 0 );
}
void QBBScreen::onWindowPost(QBBWindow *window)
{
#if defined(QBBSCREEN_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
Q_UNUSED(window)
// post app window (so navigator will show it) after first child window
// has posted; this only needs to happen once as the app window's content
// never changes
if (!m_posted && m_rootWindow) {
m_rootWindow->post();
m_posted = true;
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,121 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBBSCREEN_H
#define QBBSCREEN_H
#include <QtGui/QPlatformScreen>
#include "qbbrootwindow.h"
#include <QtCore/QByteArray>
#include <QtCore/QScopedPointer>
#include <screen/screen.h>
QT_BEGIN_NAMESPACE
class QBBWindow;
class QBBScreen : public QPlatformScreen
{
public:
static QList<QPlatformScreen *> screens() { return ms_screens; }
static void createDisplays(screen_context_t context);
static void destroyDisplays();
static QBBScreen *primaryDisplay() { return static_cast<QBBScreen*>(ms_screens.at(0)); }
static int defaultDepth();
virtual QRect geometry() const { return m_currentGeometry; }
virtual QRect availableGeometry() const;
virtual int depth() const { return defaultDepth(); }
virtual QImage::Format format() const { return (depth() == 32) ? QImage::Format_RGB32 : QImage::Format_RGB16; }
virtual QSizeF physicalSize() const { return m_currentPhysicalSize; }
bool isPrimaryScreen() const { return m_primaryScreen; }
int rotation() const { return m_currentRotation; }
void setRotation(int rotation);
int nativeFormat() const { return (depth() == 32) ? SCREEN_FORMAT_RGBA8888 : SCREEN_FORMAT_RGB565; }
screen_display_t nativeDisplay() const { return m_display; }
screen_context_t nativeContext() const { return m_screenContext; }
const char *windowGroupName() const { return m_rootWindow->groupName().constData(); }
/* Window hierarchy management */
static void addWindow(QBBWindow *child);
static void removeWindow(QBBWindow *child);
static void raiseWindow(QBBWindow *window);
static void lowerWindow(QBBWindow *window);
static void updateHierarchy();
void onWindowPost(QBBWindow *window);
QSharedPointer<QBBRootWindow> rootWindow() const { return m_rootWindow; }
private:
QBBScreen(screen_context_t context, screen_display_t display, bool primaryScreen);
virtual ~QBBScreen();
static bool orthogonal(int rotation1, int rotation2);
screen_context_t m_screenContext;
screen_display_t m_display;
QSharedPointer<QBBRootWindow> m_rootWindow;
bool m_primaryScreen;
bool m_posted;
bool m_usingOpenGL;
int m_initialRotation;
int m_currentRotation;
QSize m_initialPhysicalSize;
QSize m_currentPhysicalSize;
QRect m_initialGeometry;
QRect m_currentGeometry;
QPlatformOpenGLContext *m_platformContext;
static QList<QPlatformScreen *> ms_screens;
static QList<QBBWindow *> ms_childWindows;
};
QT_END_NAMESPACE
#endif // QBBSCREEN_H

View File

@ -0,0 +1,500 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qbbvirtualkeyboard.h"
#include "qbbscreen.h"
#include <QtGui/QPlatformScreen>
#include <QtGui/QPlatformWindow>
#include <QtCore/QDebug>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/iomsg.h>
#include <sys/pps.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
const char *QBBVirtualKeyboard::ms_PPSPath = "/pps/services/input/control?wait";
const size_t QBBVirtualKeyboard::ms_bufferSize = 2048;
static QBBVirtualKeyboard *s_instance = 0;
// Huge hack for keyboard shadow (see QNX PR 88400). Should be removed ASAP.
#define KEYBOARD_SHADOW_HEIGHT 8
QBBVirtualKeyboard::QBBVirtualKeyboard() :
m_encoder(NULL),
m_decoder(NULL),
m_buffer(NULL),
m_height(0),
m_fd(-1),
m_keyboardMode(Default),
m_visible(false),
m_locale(QLatin1String("en_US"))
{
connect();
}
QBBVirtualKeyboard::~QBBVirtualKeyboard()
{
close();
}
/* static */
QBBVirtualKeyboard& QBBVirtualKeyboard::instance()
{
if (!s_instance) {
s_instance = new QBBVirtualKeyboard();
s_instance->start();
}
return *s_instance;
}
/* static */
void QBBVirtualKeyboard::destroy()
{
if (s_instance) {
delete s_instance;
s_instance = 0;
}
}
void QBBVirtualKeyboard::close()
{
if (m_fd) {
// any reads will fail after we close the fd, which is basically what we want.
::close(m_fd);
}
// Wait for the thread to die (should be immediate), then continue the cleanup.
wait();
if (m_fd) {
m_fd = -1;
}
if (m_decoder)
{
pps_decoder_cleanup(m_decoder);
delete m_decoder;
m_decoder = NULL;
}
if (m_encoder)
{
pps_encoder_cleanup(m_encoder);
delete m_encoder;
m_encoder = NULL;
}
delete [] m_buffer;
m_buffer = NULL;
}
bool QBBVirtualKeyboard::connect()
{
close();
m_encoder = new pps_encoder_t;
m_decoder = new pps_decoder_t;
pps_encoder_initialize(m_encoder, false);
pps_decoder_initialize(m_decoder, NULL);
errno = 0;
m_fd = ::open(ms_PPSPath, O_RDWR);
if (m_fd == -1)
{
qCritical("QBBVirtualKeyboard: Unable to open \"%s\" for keyboard: %s (%d).",
ms_PPSPath, strerror(errno), errno);
close();
return false;
}
m_buffer = new char[ms_bufferSize];
if (!m_buffer) {
qCritical("QBBVirtualKeyboard: Unable to allocate buffer of %d bytes. Size is unavailable.", ms_bufferSize);
return false;
}
if (!queryPPSInfo())
return false;
start();
return true;
}
bool QBBVirtualKeyboard::queryPPSInfo()
{
// Request info, requires id to regenerate res message.
pps_encoder_add_string(m_encoder, "msg", "info");
pps_encoder_add_string(m_encoder, "id", "libWebView");
if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) {
close();
return false;
}
pps_encoder_reset(m_encoder);
return true;
}
void QBBVirtualKeyboard::notifyClientActiveStateChange(bool active)
{
if (!active)
hideKeyboard();
}
void QBBVirtualKeyboard::run()
{
ppsDataReady();
}
void QBBVirtualKeyboard::ppsDataReady()
{
while (1) {
ssize_t nread = read(m_fd, m_buffer, ms_bufferSize - 1);
#ifdef QBBVIRTUALKEYBOARD_DEBUG
qDebug() << "QBB: keyboardMessage size: " << nread;
#endif
if (nread < 0)
break;
// nread is the real space necessary, not the amount read.
if (static_cast<size_t>(nread) > ms_bufferSize - 1) {
qCritical("QBBVirtualKeyboard: Keyboard buffer size too short; need %u.", nread + 1);
break;
}
m_buffer[nread] = 0;
pps_decoder_parse_pps_str(m_decoder, m_buffer);
pps_decoder_push(m_decoder, NULL);
#ifdef QBBVIRTUALKEYBOARD_DEBUG
pps_decoder_dump_tree(m_decoder, stderr);
#endif
const char *value;
if (pps_decoder_get_string(m_decoder, "error", &value) == PPS_DECODER_OK) {
qCritical("QBBVirtualKeyboard: Keyboard PPS decoder error: %s", value ? value : "[null]");
continue;
}
if (pps_decoder_get_string(m_decoder, "msg", &value) == PPS_DECODER_OK) {
if (strcmp(value, "show") == 0) {
const bool oldVisible = m_visible;
m_visible = true;
handleKeyboardStateChangeMessage(true);
if (oldVisible != m_visible)
emit visibilityChanged(m_visible);
} else if (strcmp(value, "hide") == 0) {
const bool oldVisible = m_visible;
m_visible = false;
handleKeyboardStateChangeMessage(false);
if (oldVisible != m_visible)
emit visibilityChanged(m_visible);
} else if (strcmp(value, "info") == 0)
handleKeyboardInfoMessage();
else if (strcmp(value, "connect") == 0) { }
else
qCritical("QBBVirtualKeyboard: Unexpected keyboard PPS msg value: %s", value ? value : "[null]");
} else if (pps_decoder_get_string(m_decoder, "res", &value) == PPS_DECODER_OK) {
if (strcmp(value, "info") == 0)
handleKeyboardInfoMessage();
else
qCritical("QBBVirtualKeyboard: Unexpected keyboard PPS res value: %s", value ? value : "[null]");
} else
qCritical("QBBVirtualKeyboard: Unexpected keyboard PPS message type");
}
#ifdef QBBVIRTUALKEYBOARD_DEBUG
qDebug() << "QBB: exiting keyboard thread";
#endif
if (m_decoder)
pps_decoder_cleanup(m_decoder);
}
void QBBVirtualKeyboard::handleKeyboardInfoMessage()
{
int newHeight = 0;
const char *value;
if (pps_decoder_push(m_decoder, "dat") != PPS_DECODER_OK) {
qCritical("QBBVirtualKeyboard: Keyboard PPS dat object not found");
return;
}
if (pps_decoder_get_int(m_decoder, "size", &newHeight) != PPS_DECODER_OK) {
qCritical("QBBVirtualKeyboard: Keyboard PPS size field not found");
return;
}
if (pps_decoder_push(m_decoder, "locale") != PPS_DECODER_OK) {
qCritical("QBBVirtualKeyboard: Keyboard PPS locale object not found");
return;
}
if (pps_decoder_get_string(m_decoder, "languageId", &value) != PPS_DECODER_OK) {
qCritical("QBBVirtualKeyboard: Keyboard PPS languageId field not found");
return;
}
const QString languageId = QString::fromLatin1(value);
if (pps_decoder_get_string(m_decoder, "countryId", &value) != PPS_DECODER_OK) {
qCritical("QBBVirtualKeyboard: Keyboard PPS size countryId not found");
return;
}
const QString countryId = QString::fromLatin1(value);
// HUGE hack, should be removed ASAP.
newHeight -= KEYBOARD_SHADOW_HEIGHT; // We want to ignore the 8 pixel shadow above the keyboard. (PR 88400)
if (newHeight != m_height) {
m_height = newHeight;
updateAvailableScreenGeometry();
}
const QLocale locale = QLocale(languageId + QLatin1Char('_') + countryId);
if (locale != m_locale) {
m_locale = locale;
emit localeChanged(locale);
}
#ifdef QBBVIRTUALKEYBOARD_DEBUG
qDebug() << "QBB: handleKeyboardInfoMessage size=" << m_height << "locale=" << m_locale;
#endif
}
void QBBVirtualKeyboard::handleKeyboardStateChangeMessage(bool visible)
{
#ifdef QBBVIRTUALKEYBOARD_DEBUG
qDebug() << "QBB: handleKeyboardStateChangeMessage " << visible;
#endif
updateAvailableScreenGeometry();
if (visible)
showKeyboard();
else
hideKeyboard();
}
void QBBVirtualKeyboard::updateAvailableScreenGeometry()
{
#ifdef QBBVIRTUALKEYBOARD_DEBUG
qDebug() << "QBB: updateAvailableScreenGeometry: keyboard visible=" << m_visible << ", keyboard height=" << m_height;
#endif
// TODO: What screen index should be used? I assume primaryScreen here because it works, and
// we do it for handleScreenGeometryChange elsewhere but since we have support
// for more than one screen, that's not going to always work.
QBBScreen *platformScreen = QBBScreen::primaryDisplay();
QWindowSystemInterface::handleScreenAvailableGeometryChange(platformScreen->screen(), platformScreen->availableGeometry());
}
bool QBBVirtualKeyboard::showKeyboard()
{
#ifdef QBBVIRTUALKEYBOARD_DEBUG
qDebug() << "QBB: showKeyboard()";
#endif
// Try to connect.
if (m_fd == -1 && !connect())
return false;
// NOTE: This must be done everytime the keyboard is shown even if there is no change because
// hiding the keyboard wipes the setting.
applyKeyboardModeOptions();
pps_encoder_reset(m_encoder);
// Send the show message.
pps_encoder_add_string(m_encoder, "msg", "show");
if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) {
close();
return false;
}
pps_encoder_reset(m_encoder);
// Return true if no error occurs. Sizing response will be triggered when confirmation of
// the change arrives.
return true;
}
bool QBBVirtualKeyboard::hideKeyboard()
{
#ifdef QBBVIRTUALKEYBOARD_DEBUG
qDebug() << "QBB: hideKeyboard()";
#endif
if (m_fd == -1 && !connect())
return false;
pps_encoder_add_string(m_encoder, "msg", "hide");
if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) {
close();
//Try again.
if (connect()) {
if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) {
close();
return false;
}
}
else
return false;
}
pps_encoder_reset(m_encoder);
// Return true if no error occurs. Sizing response will be triggered when confirmation of
// the change arrives.
return true;
}
void QBBVirtualKeyboard::setKeyboardMode(KeyboardMode mode)
{
m_keyboardMode = mode;
}
void QBBVirtualKeyboard::applyKeyboardModeOptions()
{
// Try to connect.
if (m_fd == -1 && !connect())
return;
// Send the options message.
pps_encoder_add_string(m_encoder, "msg", "options");
pps_encoder_start_object(m_encoder, "dat");
switch (m_keyboardMode) {
case Url:
addUrlModeOptions();
break;
case Email:
addEmailModeOptions();
break;
case Web:
addWebModeOptions();
break;
case NumPunc:
addNumPuncModeOptions();
break;
case Symbol:
addSymbolModeOptions();
break;
case Phone:
addPhoneModeOptions();
break;
case Pin:
addPinModeOptions();
break;
case Default:
default:
addDefaultModeOptions();
break;
}
pps_encoder_end_object(m_encoder);
if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) {
close();
}
pps_encoder_reset(m_encoder);
}
void QBBVirtualKeyboard::addDefaultModeOptions()
{
pps_encoder_add_string(m_encoder, "enter", "enter.default");
pps_encoder_add_string(m_encoder, "type", "default");
}
void QBBVirtualKeyboard::addUrlModeOptions()
{
pps_encoder_add_string(m_encoder, "enter", "enter.default");
pps_encoder_add_string(m_encoder, "type", "url");
}
void QBBVirtualKeyboard::addEmailModeOptions()
{
pps_encoder_add_string(m_encoder, "enter", "enter.default");
pps_encoder_add_string(m_encoder, "type", "email");
}
void QBBVirtualKeyboard::addWebModeOptions()
{
pps_encoder_add_string(m_encoder, "enter", "enter.default");
pps_encoder_add_string(m_encoder, "type", "web");
}
void QBBVirtualKeyboard::addNumPuncModeOptions()
{
pps_encoder_add_string(m_encoder, "enter", "enter.default");
pps_encoder_add_string(m_encoder, "type", "numPunc");
}
void QBBVirtualKeyboard::addPhoneModeOptions()
{
pps_encoder_add_string(m_encoder, "enter", "enter.default");
pps_encoder_add_string(m_encoder, "type", "phone");
}
void QBBVirtualKeyboard::addPinModeOptions()
{
pps_encoder_add_string(m_encoder, "enter", "enter.default");
pps_encoder_add_string(m_encoder, "type", "pin");
}
void QBBVirtualKeyboard::addSymbolModeOptions()
{
pps_encoder_add_string(m_encoder, "enter", "enter.default");
pps_encoder_add_string(m_encoder, "type", "symbol");
}

View File

@ -0,0 +1,130 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef VIRTUALKEYBOARD_H_
#define VIRTUALKEYBOARD_H_
#include <QtCore/QThread>
#include <QtCore/QLocale>
#include <QtGui/QPlatformScreen>
#include <QtGui/QWindowSystemInterface>
#include <stddef.h>
#include <vector>
#include <string>
#include <sys/pps.h>
QT_BEGIN_NAMESPACE
/* Shamelessly copied from the browser - this should be rewritten once we have a proper PPS wrapper class */
class QBBVirtualKeyboard : public QThread
{
Q_OBJECT
public:
// NOTE: Not all the following keyboard modes are currently used.
// Default - Regular Keyboard
// Url/Email - Enhanced keys for each types.
// Web - Regular keyboard with two blank keys, currently unused.
// NumPunc - Numbers & Punctionation, alternate to Symbol
// Symbol - All symbols, alternate to NumPunc, currently unused.
// Phone - Phone enhanced keyboard - currently unused as no alternate keyboard available to access a-zA-Z
// Pin - Keyboard for entering Pins (Hex values) currently unused.
//
// SPECIAL NOTE: Usage of NumPunc may have to be removed, ABC button is non-functional.
//
enum KeyboardMode { Default, Url, Email, Web, NumPunc, Symbol, Phone, Pin };
static QBBVirtualKeyboard& instance();
static void destroy();
bool showKeyboard();
bool hideKeyboard();
int height() { return m_visible ? m_height : 0; }
void setKeyboardMode(KeyboardMode);
void notifyClientActiveStateChange(bool);
bool isVisible() const { return m_visible; }
QLocale locale() const { return m_locale; }
Q_SIGNALS:
void localeChanged(const QLocale &locale);
void visibilityChanged(bool visible);
private:
QBBVirtualKeyboard();
virtual ~QBBVirtualKeyboard();
// Will be called internally if needed.
bool connect();
void close();
void ppsDataReady();
bool queryPPSInfo();
void handleKeyboardInfoMessage();
void handleKeyboardStateChangeMessage(bool visible);
void updateAvailableScreenGeometry();
void applyKeyboardModeOptions();
void addDefaultModeOptions();
void addUrlModeOptions();
void addEmailModeOptions();
void addWebModeOptions();
void addNumPuncModeOptions();
void addSymbolModeOptions();
void addPhoneModeOptions();
void addPinModeOptions();
// QThread overrides
virtual void run();
pps_encoder_t *m_encoder;
pps_decoder_t *m_decoder;
char *m_buffer;
int m_height;
int m_fd;
KeyboardMode m_keyboardMode;
bool m_visible;
QLocale m_locale;
// Path to keyboardManager in PPS.
static const char *ms_PPSPath;
static const size_t ms_bufferSize;
};
#endif /* VIRTUALKEYBOARD_H_ */

View File

@ -0,0 +1,665 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qbbwindow.h"
#include "qbbglcontext.h"
#include "qbbintegration.h"
#include "qbbscreen.h"
#include <QtGui/QWindow>
#include <QtGui/QWindowSystemInterface>
#include <QtCore/QDebug>
#include <errno.h>
QT_BEGIN_NAMESPACE
QBBWindow::QBBWindow(QWindow *window, screen_context_t context)
: QPlatformWindow(window),
m_screenContext(context),
m_window(0),
m_currentBufferIndex(-1),
m_previousBufferIndex(-1),
m_platformOpenGLContext(0),
m_screen(0),
m_parentWindow(0),
m_visible(true)
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window << ", size =" << window->size();
#endif
int result;
// Create child QNX window
errno = 0;
result = screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW);
if (result != 0) {
qFatal("QBBWindow: failed to create window, errno=%d", errno);
}
// Set window buffer usage based on rendering API
int val;
QSurface::SurfaceType surfaceType = window->surfaceType();
switch (surfaceType) {
case QSurface::RasterSurface:
val = SCREEN_USAGE_NATIVE | SCREEN_USAGE_READ | SCREEN_USAGE_WRITE;
break;
case QSurface::OpenGLSurface:
val = SCREEN_USAGE_OPENGL_ES2;
break;
default:
qFatal("QBBWindow: unsupported window API");
break;
}
errno = 0;
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_USAGE, &val);
if (result != 0) {
qFatal("QBBWindow: failed to set window buffer usage, errno=%d", errno);
}
// Alpha channel is always pre-multiplied if present
errno = 0;
val = SCREEN_PRE_MULTIPLIED_ALPHA;
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ALPHA_MODE, &val);
if (result != 0) {
qFatal("QBBWindow: failed to set window alpha mode, errno=%d", errno);
}
// Make the window opaque
errno = 0;
val = SCREEN_TRANSPARENCY_NONE;
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_TRANSPARENCY, &val);
if (result != 0) {
qFatal("QBBWindow: failed to set window transparency, errno=%d", errno);
}
// Set the window swap interval
errno = 0;
val = 1;
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SWAP_INTERVAL, &val);
if (result != 0) {
qFatal("QBBWindow: failed to set window swap interval, errno=%d", errno);
}
// Assign the window to the primary display (this is the default specified by screen).
setScreen(QBBScreen::primaryDisplay());
// Add the window to the root of the hierarchy
QBBScreen::addWindow(this);
// Add window to plugin's window mapper
QBBIntegration::addWindow(m_window, window);
}
QBBWindow::~QBBWindow()
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window();
#endif
// Remove from plugin's window mapper
QBBIntegration::removeWindow(m_window);
// Remove from parent's Hierarchy.
removeFromParent();
QBBScreen::updateHierarchy();
// We shouldn't allow this case unless QT allows it. Does it? Or should we send the
// handleCloseEvent on all children when this window is deleted?
if (m_childWindows.size() > 0)
qFatal("QBBWindow: window destroyed before children!");
// Cleanup QNX window and its buffers
screen_destroy_window(m_window);
}
void QBBWindow::setGeometry(const QRect &rect)
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window() << ", (" << rect.x() << "," << rect.y() << "," << rect.width() << "," << rect.height() << ")";
#endif
QRect oldGeometry = geometry();
// Call base class method
QPlatformWindow::setGeometry(rect);
// Set window geometry equal to widget geometry
errno = 0;
int val[2];
val[0] = rect.x();
val[1] = rect.y();
int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, val);
if (result != 0) {
qFatal("QBBWindow: failed to set window position, errno=%d", errno);
}
errno = 0;
val[0] = rect.width();
val[1] = rect.height();
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val);
if (result != 0) {
qFatal("QBBWindow: failed to set window size, errno=%d", errno);
}
// Set viewport size equal to window size
errno = 0;
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val);
if (result != 0) {
qFatal("QBBWindow: failed to set window source size, errno=%d", errno);
}
// Now move all children.
QPoint offset;
if (!oldGeometry.isEmpty()) {
offset = rect.topLeft();
offset -= oldGeometry.topLeft();
QList<QBBWindow*>::iterator it;
for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) {
(*it)->offset(offset);
}
}
}
void QBBWindow::offset(const QPoint &offset)
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window();
#endif
// Move self and then children.
QRect newGeometry = geometry();
newGeometry.translate(offset);
// Call the base class
QPlatformWindow::setGeometry(newGeometry);
int val[2];
errno = 0;
val[0] = newGeometry.x();
val[1] = newGeometry.y();
int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, val);
if (result != 0) {
qFatal("QBBWindow: failed to set window position, errno=%d", errno);
}
QList<QBBWindow*>::iterator it;
for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) {
(*it)->offset(offset);
}
}
void QBBWindow::setVisible(bool visible)
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window() << "visible =" << visible;
#endif
m_visible = visible;
QBBWindow *root = this;
while (root->m_parentWindow)
root = root->m_parentWindow;
root->updateVisibility(root->m_visible);
window()->requestActivateWindow();
}
void QBBWindow::updateVisibility(bool parentVisible)
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "parentVisible =" << parentVisible << "window =" << window();
#endif
// Set window visibility
errno = 0;
int val = (m_visible && parentVisible) ? 1 : 0;
int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_VISIBLE, &val);
if (result != 0) {
qFatal("QBBWindow: failed to set window visibility, errno=%d", errno);
}
QList<QBBWindow *>::iterator it;
for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) {
(*it)->updateVisibility(m_visible && parentVisible);
}
}
void QBBWindow::setOpacity(qreal level)
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window() << "opacity =" << level;
#endif
// Set window global alpha
errno = 0;
int val = (int)(level * 255);
int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_GLOBAL_ALPHA, &val);
if (result != 0) {
qFatal("QBBWindow: failed to set window global alpha, errno=%d", errno);
}
// TODO: How to handle children of this window? If we change all the visibilities, then
// the transparency will look wrong...
}
void QBBWindow::setBufferSize(const QSize &size)
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window() << "size =" << size;
#endif
// Set window buffer size
errno = 0;
int val[2] = { size.width(), size.height() };
int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BUFFER_SIZE, val);
if (result != 0) {
qFatal("QBBWindow: failed to set window buffer size, errno=%d", errno);
}
// Create window buffers if they do not exist
if (!hasBuffers()) {
// Get pixel format from EGL config if using OpenGL;
// otherwise inherit pixel format of window's screen
if (m_platformOpenGLContext != 0) {
val[0] = platformWindowFormatToNativeFormat(m_platformOpenGLContext->format());
} else {
val[0] = m_screen->nativeFormat();
}
errno = 0;
result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, val);
if (result != 0) {
qFatal("QBBWindow: failed to set window pixel format, errno=%d", errno);
}
errno = 0;
result = screen_create_window_buffers(m_window, MAX_BUFFER_COUNT);
if (result != 0) {
qFatal("QBBWindow: failed to create window buffers, errno=%d", errno);
}
}
// Cache new buffer size
m_bufferSize = size;
// Buffers were destroyed; reacquire them
m_currentBufferIndex = -1;
m_previousDirty = QRegion();
m_scrolled = QRegion();
}
QBBBuffer &QBBWindow::renderBuffer()
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window();
#endif
// Check if render buffer is invalid
if (m_currentBufferIndex == -1) {
// Get all buffers available for rendering
errno = 0;
screen_buffer_t buffers[MAX_BUFFER_COUNT];
int result = screen_get_window_property_pv(m_window, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)buffers);
if (result != 0) {
qFatal("QBBWindow: failed to query window buffers, errno=%d", errno);
}
// Wrap each buffer
for (int i = 0; i < MAX_BUFFER_COUNT; ++i) {
m_buffers[i] = QBBBuffer(buffers[i]);
}
// Use the first available render buffer
m_currentBufferIndex = 0;
m_previousBufferIndex = -1;
}
return m_buffers[m_currentBufferIndex];
}
void QBBWindow::scroll(const QRegion &region, int dx, int dy, bool flush)
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window();
#endif
copyBack(region, dx, dy, flush);
m_scrolled += region;
}
void QBBWindow::post(const QRegion &dirty)
{
// Check if render buffer exists and something was rendered
if (m_currentBufferIndex != -1 && !dirty.isEmpty()) {
#if defined(QBBWINDOW_DEBUG)
qDebug() << "QBBWindow::post - window =" << window();
#endif
QBBBuffer &currentBuffer = m_buffers[m_currentBufferIndex];
// Copy unmodified region from old render buffer to new render buffer;
// required to allow partial updates
QRegion preserve = m_previousDirty - dirty - m_scrolled;
copyBack(preserve, 0, 0);
// Calculate region that changed
QRegion modified = preserve + dirty + m_scrolled;
QRect rect = modified.boundingRect();
int dirtyRect[4] = { rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height() };
// Update the display with contents of render buffer
errno = 0;
int result = screen_post_window(m_window, currentBuffer.nativeBuffer(), 1, dirtyRect, 0);
if (result != 0) {
qFatal("QBBWindow: failed to post window buffer, errno=%d", errno);
}
// Advance to next nender buffer
m_previousBufferIndex = m_currentBufferIndex++;
if (m_currentBufferIndex >= MAX_BUFFER_COUNT) {
m_currentBufferIndex = 0;
}
// Save modified region and clear scrolled region
m_previousDirty = dirty;
m_scrolled = QRegion();
// Notify screen that window posted
if (m_screen != 0) {
m_screen->onWindowPost(this);
}
}
}
void QBBWindow::setScreen(QBBScreen *platformScreen)
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window() << "platformScreen =" << platformScreen;
#endif
if (m_screen == platformScreen)
return;
m_screen = platformScreen;
// Move window to proper screen/display
errno = 0;
screen_display_t display = platformScreen->nativeDisplay();
int result = screen_set_window_property_pv(m_window, SCREEN_PROPERTY_DISPLAY, (void **)&display);
if (result != 0) {
qFatal("QBBWindow: failed to set window display, errno=%d", errno);
}
// Add window to display's window group
errno = 0;
result = screen_join_window_group(m_window, platformScreen->windowGroupName());
if (result != 0) {
qFatal("QBBWindow: failed to join window group, errno=%d", errno);
}
QList<QBBWindow*>::iterator it;
for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) {
// Only subwindows and tooltips need necessarily be moved to another display with the window.
if ((window()->windowType() & Qt::WindowType_Mask) == Qt::SubWindow ||
(window()->windowType() & Qt::WindowType_Mask) == Qt::ToolTip)
(*it)->setScreen(platformScreen);
}
QBBScreen::updateHierarchy();
}
void QBBWindow::removeFromParent()
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window();
#endif
// Remove from old Hierarchy position
if (m_parentWindow) {
if (m_parentWindow->m_childWindows.removeAll(this))
m_parentWindow = 0;
else
qFatal("QBBWindow: Window Hierarchy broken; window has parent, but parent hasn't got child.");
} else {
QBBScreen::removeWindow(this);
}
}
void QBBWindow::setParent(const QPlatformWindow *window)
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << this->window() << "platformWindow =" << window;
#endif
// Cast away the const, we need to modify the hierarchy.
QBBWindow *newParent = 0;
if (window)
newParent = static_cast<QBBWindow*>((QPlatformWindow *)window);
if (newParent == m_parentWindow)
return;
removeFromParent();
m_parentWindow = newParent;
// Add to new hierarchy position.
if (m_parentWindow) {
if (m_parentWindow->m_screen != m_screen)
setScreen(m_parentWindow->m_screen);
m_parentWindow->m_childWindows.push_back(this);
} else {
QBBScreen::addWindow(this);
}
QBBScreen::updateHierarchy();
}
void QBBWindow::raise()
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window();
#endif
QBBWindow *oldParent = m_parentWindow;
if (oldParent) {
removeFromParent();
oldParent->m_childWindows.push_back(this);
} else {
QBBScreen::raiseWindow(this);
}
QBBScreen::updateHierarchy();
}
void QBBWindow::lower()
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window();
#endif
QBBWindow *oldParent = m_parentWindow;
if (oldParent) {
removeFromParent();
oldParent->m_childWindows.push_front(this);
} else {
QBBScreen::lowerWindow(this);
}
QBBScreen::updateHierarchy();
}
void QBBWindow::requestActivateWindow()
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window();
#endif
// TODO: Tell screen to set keyboard focus to this window.
// Notify that we gained focus.
gainedFocus();
}
void QBBWindow::gainedFocus()
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window();
#endif
// Got focus
QWindowSystemInterface::handleWindowActivated(window());
}
void QBBWindow::setPlatformOpenGLContext(QBBGLContext *platformOpenGLContext)
{
// This function does not take ownership of the platform gl context.
// It is owned by the frontend QOpenGLContext
m_platformOpenGLContext = platformOpenGLContext;
}
void QBBWindow::updateZorder(int &topZorder)
{
errno = 0;
int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ZORDER, &topZorder);
topZorder++;
if (result != 0)
qFatal("QBBWindow: failed to set window z-order=%d, errno=%d, mWindow=%p", topZorder, errno, m_window);
QList<QBBWindow*>::const_iterator it;
for (it = m_childWindows.begin(); it != m_childWindows.end(); it++)
(*it)->updateZorder(topZorder);
}
void QBBWindow::copyBack(const QRegion &region, int dx, int dy, bool flush)
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO << "window =" << window();
#endif
int result;
// Abort if previous buffer is invalid
if (m_previousBufferIndex == -1) {
return;
}
// Abort if nothing to copy
if (region.isEmpty()) {
return;
}
QBBBuffer &currentBuffer = m_buffers[m_currentBufferIndex];
QBBBuffer &previousBuffer = m_buffers[m_previousBufferIndex];
// Break down region into non-overlapping rectangles
QVector<QRect> rects = region.rects();
for (int i = rects.size() - 1; i >= 0; i--) {
// Clip rectangle to bounds of target
QRect rect = rects[i].intersected( currentBuffer.rect() );
if (rect.isEmpty())
continue;
// Setup blit operation
int attribs[] = { SCREEN_BLIT_SOURCE_X, rect.x(),
SCREEN_BLIT_SOURCE_Y, rect.y(),
SCREEN_BLIT_SOURCE_WIDTH, rect.width(),
SCREEN_BLIT_SOURCE_HEIGHT, rect.height(),
SCREEN_BLIT_DESTINATION_X, rect.x() + dx,
SCREEN_BLIT_DESTINATION_Y, rect.y() + dy,
SCREEN_BLIT_DESTINATION_WIDTH, rect.width(),
SCREEN_BLIT_DESTINATION_HEIGHT, rect.height(),
SCREEN_BLIT_END };
// Queue blit operation
errno = 0;
result = screen_blit(m_screenContext, currentBuffer.nativeBuffer(), previousBuffer.nativeBuffer(), attribs);
if (result != 0) {
qFatal("QBBWindow: failed to blit buffers, errno=%d", errno);
}
}
// Check if flush requested
if (flush) {
// Wait for all blits to complete
errno = 0;
result = screen_flush_blits(m_screenContext, SCREEN_WAIT_IDLE);
if (result != 0) {
qFatal("QBBWindow: failed to flush blits, errno=%d", errno);
}
// Buffer was modified outside the CPU
currentBuffer.invalidateInCache();
}
}
int QBBWindow::platformWindowFormatToNativeFormat(const QSurfaceFormat &format)
{
#if defined(QBBWINDOW_DEBUG)
qDebug() << Q_FUNC_INFO;
#endif
// Extract size of colour channels from window format
int redSize = format.redBufferSize();
if (redSize == -1) {
qFatal("QBBWindow: red size not defined");
}
int greenSize = format.greenBufferSize();
if (greenSize == -1) {
qFatal("QBBWindow: green size not defined");
}
int blueSize = format.blueBufferSize();
if (blueSize == -1) {
qFatal("QBBWindow: blue size not defined");
}
// select matching native format
if (redSize == 5 && greenSize == 6 && blueSize == 5) {
return SCREEN_FORMAT_RGB565;
} else if (redSize == 8 && greenSize == 8 && blueSize == 8) {
return SCREEN_FORMAT_RGBA8888;
} else {
qFatal("QBBWindow: unsupported pixel format");
return 0;
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,133 @@
/***************************************************************************
**
** Copyright (C) 2011 - 2012 Research In Motion
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QBBWINDOW_H
#define QBBWINDOW_H
#include <QtGui/QPlatformWindow>
#include "qbbbuffer.h"
#include <QtGui/QImage>
#include <EGL/egl.h>
#include <screen/screen.h>
QT_BEGIN_NAMESPACE
// all surfaces double buffered
#define MAX_BUFFER_COUNT 2
class QBBGLContext;
class QBBScreen;
class QPlatformGLContext;
class QSurfaceFormat;
class QBBWindow : public QPlatformWindow
{
friend class QBBScreen;
public:
QBBWindow(QWindow *window, screen_context_t context);
virtual ~QBBWindow();
virtual void setGeometry(const QRect &rect);
virtual void setVisible(bool visible);
virtual void setOpacity(qreal level);
virtual WId winId() const { return (WId)m_window; }
screen_window_t nativeHandle() const { return m_window; }
void setBufferSize(const QSize &size);
QSize bufferSize() const { return m_bufferSize; }
bool hasBuffers() const { return !m_bufferSize.isEmpty(); }
QBBBuffer &renderBuffer();
void scroll(const QRegion &region, int dx, int dy, bool flush=false);
void post(const QRegion &dirty);
void setScreen(QBBScreen *platformScreen);
virtual void setParent(const QPlatformWindow *window);
virtual void raise();
virtual void lower();
virtual void requestActivateWindow();
void gainedFocus();
QBBScreen *screen() const { return m_screen; }
const QList<QBBWindow*>& children() const { return m_childWindows; }
void setPlatformOpenGLContext(QBBGLContext *platformOpenGLContext);
QBBGLContext *platformOpenGLContext() const { return m_platformOpenGLContext; }
private:
void removeFromParent();
void offset(const QPoint &offset);
void updateVisibility(bool parentVisible);
void updateZorder(int &topZorder);
void fetchBuffers();
void copyBack(const QRegion &region, int dx, int dy, bool flush=false);
static int platformWindowFormatToNativeFormat(const QSurfaceFormat &format);
screen_context_t m_screenContext;
screen_window_t m_window;
QSize m_bufferSize;
QBBBuffer m_buffers[MAX_BUFFER_COUNT];
int m_currentBufferIndex;
int m_previousBufferIndex;
QRegion m_previousDirty;
QRegion m_scrolled;
QBBGLContext *m_platformOpenGLContext;
QBBScreen *m_screen;
QList<QBBWindow*> m_childWindows;
QBBWindow *m_parentWindow;
bool m_visible;
};
QT_END_NAMESPACE
#endif // QBBWINDOW_H

View File

@ -11,3 +11,7 @@ mac {
}
win32: SUBDIRS += windows
blackberry-armv7le-qcc {
SUBDIRS += blackberry
}